Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6: (38 commits) net: Expose all network devices in a namespaces in sysfs hotplug: netns aware uevent_helper kobj: Send hotplug events in the proper namespace. netlink: Implment netlink_broadcast_filtered net/sysfs: Fix the bitrot in network device kobject namespace support netns: Teach network device kobjects which namespace they are in. kobject: Send hotplug events in all network namespaces driver-core: fix Typo in drivers/base/core.c for CONFIG_MODULE pci: check caps from sysfs file open to read device dependent config space sysfs: add struct file* to bin_attr callbacks sysfs: Remove usage of S_BIAS to avoid merge conflict with the vfs tree sysfs: Don't use enums in inline function declaration. sysfs-namespaces: add a high-level Documentation file sysfs: Comment sysfs directory tagging logic driver core: Implement ns directory support for device classes. sysfs: Implement sysfs_delete_link sysfs: Add support for tagged directories with untagged members. sysfs: Implement sysfs tagged directory support. kobj: Add basic infrastructure for dealing with namespaces. sysfs: Remove double free sysfs_get_sb ...
This commit is contained in:
commit
d6fb1db02e
|
@ -0,0 +1,42 @@
|
|||
Sysfs tagging
|
||||
-------------
|
||||
|
||||
(Taken almost verbatim from Eric Biederman's netns tagging patch
|
||||
commit msg)
|
||||
|
||||
The problem. Network devices show up in sysfs and with the network
|
||||
namespace active multiple devices with the same name can show up in
|
||||
the same directory, ouch!
|
||||
|
||||
To avoid that problem and allow existing applications in network
|
||||
namespaces to see the same interface that is currently presented in
|
||||
sysfs, sysfs now has tagging directory support.
|
||||
|
||||
By using the network namespace pointers as tags to separate out the
|
||||
the sysfs directory entries we ensure that we don't have conflicts
|
||||
in the directories and applications only see a limited set of
|
||||
the network devices.
|
||||
|
||||
Each sysfs directory entry may be tagged with zero or one
|
||||
namespaces. A sysfs_dirent is augmented with a void *s_ns. If a
|
||||
directory entry is tagged, then sysfs_dirent->s_flags will have a
|
||||
flag between KOBJ_NS_TYPE_NONE and KOBJ_NS_TYPES, and s_ns will
|
||||
point to the namespace to which it belongs.
|
||||
|
||||
Each sysfs superblock's sysfs_super_info contains an array void
|
||||
*ns[KOBJ_NS_TYPES]. When a a task in a tagging namespace
|
||||
kobj_nstype first mounts sysfs, a new superblock is created. It
|
||||
will be differentiated from other sysfs mounts by having its
|
||||
s_fs_info->ns[kobj_nstype] set to the new namespace. Note that
|
||||
through bind mounting and mounts propagation, a task can easily view
|
||||
the contents of other namespaces' sysfs mounts. Therefore, when a
|
||||
namespace exits, it will call kobj_ns_exit() to invalidate any
|
||||
sysfs_dirent->s_ns pointers pointing to it.
|
||||
|
||||
Users of this interface:
|
||||
- define a type in the kobj_ns_type enumeration.
|
||||
- call kobj_ns_type_register() with its kobj_ns_type_operations which has
|
||||
- current_ns() which returns current's namespace
|
||||
- netlink_ns() which returns a socket's namespace
|
||||
- initial_ns() which returns the initial namesapce
|
||||
- call kobj_ns_exit() when an individual tag is no longer valid
|
|
@ -53,6 +53,7 @@ static int __pci_mmap_fits(struct pci_dev *pdev, int num,
|
|||
|
||||
/**
|
||||
* pci_mmap_resource - map a PCI resource into user memory space
|
||||
* @filp: open sysfs file
|
||||
* @kobj: kobject for mapping
|
||||
* @attr: struct bin_attribute for the file being mapped
|
||||
* @vma: struct vm_area_struct passed into the mmap
|
||||
|
@ -60,7 +61,8 @@ static int __pci_mmap_fits(struct pci_dev *pdev, int num,
|
|||
*
|
||||
* Use the bus mapping routines to map a PCI resource into userspace.
|
||||
*/
|
||||
static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
|
||||
static int pci_mmap_resource(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
struct vm_area_struct *vma, int sparse)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(container_of(kobj,
|
||||
|
@ -89,14 +91,14 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
|
|||
return hose_mmap_page_range(pdev->sysdata, vma, mmap_type, sparse);
|
||||
}
|
||||
|
||||
static int pci_mmap_resource_sparse(struct kobject *kobj,
|
||||
static int pci_mmap_resource_sparse(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
return pci_mmap_resource(kobj, attr, vma, 1);
|
||||
}
|
||||
|
||||
static int pci_mmap_resource_dense(struct kobject *kobj,
|
||||
static int pci_mmap_resource_dense(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
|
|
|
@ -905,7 +905,7 @@ struct txx9_sramc_sysdev {
|
|||
void __iomem *base;
|
||||
};
|
||||
|
||||
static ssize_t txx9_sram_read(struct kobject *kobj,
|
||||
static ssize_t txx9_sram_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t size)
|
||||
{
|
||||
|
@ -920,7 +920,7 @@ static ssize_t txx9_sram_read(struct kobject *kobj,
|
|||
return size;
|
||||
}
|
||||
|
||||
static ssize_t txx9_sram_write(struct kobject *kobj,
|
||||
static ssize_t txx9_sram_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t size)
|
||||
{
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#define MV64X60_VAL_LEN_MAX 11
|
||||
#define MV64X60_PCICFG_CPCI_HOTSWAP 0x68
|
||||
|
||||
static ssize_t mv64x60_hs_reg_read(struct kobject *kobj,
|
||||
static ssize_t mv64x60_hs_reg_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf,
|
||||
loff_t off, size_t count)
|
||||
{
|
||||
|
@ -45,7 +45,7 @@ static ssize_t mv64x60_hs_reg_read(struct kobject *kobj,
|
|||
return sprintf(buf, "0x%08x\n", v);
|
||||
}
|
||||
|
||||
static ssize_t mv64x60_hs_reg_write(struct kobject *kobj,
|
||||
static ssize_t mv64x60_hs_reg_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf,
|
||||
loff_t off, size_t count)
|
||||
{
|
||||
|
|
|
@ -403,8 +403,9 @@ static ssize_t sys_ipl_device_show(struct kobject *kobj,
|
|||
static struct kobj_attribute sys_ipl_device_attr =
|
||||
__ATTR(device, S_IRUGO, sys_ipl_device_show, NULL);
|
||||
|
||||
static ssize_t ipl_parameter_read(struct kobject *kobj, struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
static ssize_t ipl_parameter_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf,
|
||||
loff_t off, size_t count)
|
||||
{
|
||||
return memory_read_from_buffer(buf, count, &off, IPL_PARMBLOCK_START,
|
||||
IPL_PARMBLOCK_SIZE);
|
||||
|
@ -419,8 +420,9 @@ static struct bin_attribute ipl_parameter_attr = {
|
|||
.read = &ipl_parameter_read,
|
||||
};
|
||||
|
||||
static ssize_t ipl_scp_data_read(struct kobject *kobj, struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
static ssize_t ipl_scp_data_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf,
|
||||
loff_t off, size_t count)
|
||||
{
|
||||
unsigned int size = IPL_PARMBLOCK_START->ipl_info.fcp.scp_data_len;
|
||||
void *scp_data = &IPL_PARMBLOCK_START->ipl_info.fcp.scp_data;
|
||||
|
@ -694,7 +696,7 @@ static struct kobj_attribute sys_reipl_ccw_vmparm_attr =
|
|||
|
||||
/* FCP reipl device attributes */
|
||||
|
||||
static ssize_t reipl_fcp_scpdata_read(struct kobject *kobj,
|
||||
static ssize_t reipl_fcp_scpdata_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -704,7 +706,7 @@ static ssize_t reipl_fcp_scpdata_read(struct kobject *kobj,
|
|||
return memory_read_from_buffer(buf, count, &off, scp_data, size);
|
||||
}
|
||||
|
||||
static ssize_t reipl_fcp_scpdata_write(struct kobject *kobj,
|
||||
static ssize_t reipl_fcp_scpdata_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
|
|
@ -71,7 +71,7 @@ struct acpi_table_attr {
|
|||
struct list_head node;
|
||||
};
|
||||
|
||||
static ssize_t acpi_table_show(struct kobject *kobj,
|
||||
static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr, char *buf,
|
||||
loff_t offset, size_t count)
|
||||
{
|
||||
|
|
|
@ -18,9 +18,9 @@ config UEVENT_HELPER_PATH
|
|||
|
||||
config DEVTMPFS
|
||||
bool "Maintain a devtmpfs filesystem to mount at /dev"
|
||||
depends on HOTPLUG && SHMEM && TMPFS
|
||||
depends on HOTPLUG
|
||||
help
|
||||
This creates a tmpfs filesystem instance early at bootup.
|
||||
This creates a tmpfs/ramfs filesystem instance early at bootup.
|
||||
In this filesystem, the kernel driver core maintains device
|
||||
nodes with their default names and permissions for all
|
||||
registered devices with an assigned major/minor number.
|
||||
|
@ -33,6 +33,9 @@ config DEVTMPFS
|
|||
functional /dev without any further help. It also allows simple
|
||||
rescue systems, and reliably handles dynamic major/minor numbers.
|
||||
|
||||
Notice: if CONFIG_TMPFS isn't enabled, the simpler ramfs
|
||||
file system will be used instead.
|
||||
|
||||
config DEVTMPFS_MOUNT
|
||||
bool "Automount devtmpfs at /dev, after the kernel mounted the rootfs"
|
||||
depends on DEVTMPFS
|
||||
|
|
|
@ -63,6 +63,14 @@ static void class_release(struct kobject *kobj)
|
|||
kfree(cp);
|
||||
}
|
||||
|
||||
static const struct kobj_ns_type_operations *class_child_ns_type(struct kobject *kobj)
|
||||
{
|
||||
struct class_private *cp = to_class(kobj);
|
||||
struct class *class = cp->class;
|
||||
|
||||
return class->ns_type;
|
||||
}
|
||||
|
||||
static const struct sysfs_ops class_sysfs_ops = {
|
||||
.show = class_attr_show,
|
||||
.store = class_attr_store,
|
||||
|
@ -71,6 +79,7 @@ static const struct sysfs_ops class_sysfs_ops = {
|
|||
static struct kobj_type class_ktype = {
|
||||
.sysfs_ops = &class_sysfs_ops,
|
||||
.release = class_release,
|
||||
.child_ns_type = class_child_ns_type,
|
||||
};
|
||||
|
||||
/* Hotplug events for classes go to the class class_subsys */
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <linux/notifier.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/async.h>
|
||||
|
||||
|
@ -132,9 +131,21 @@ static void device_release(struct kobject *kobj)
|
|||
kfree(p);
|
||||
}
|
||||
|
||||
static const void *device_namespace(struct kobject *kobj)
|
||||
{
|
||||
struct device *dev = to_dev(kobj);
|
||||
const void *ns = NULL;
|
||||
|
||||
if (dev->class && dev->class->ns_type)
|
||||
ns = dev->class->namespace(dev);
|
||||
|
||||
return ns;
|
||||
}
|
||||
|
||||
static struct kobj_type device_ktype = {
|
||||
.release = device_release,
|
||||
.sysfs_ops = &dev_sysfs_ops,
|
||||
.namespace = device_namespace,
|
||||
};
|
||||
|
||||
|
||||
|
@ -559,10 +570,10 @@ void device_initialize(struct device *dev)
|
|||
dev->kobj.kset = devices_kset;
|
||||
kobject_init(&dev->kobj, &device_ktype);
|
||||
INIT_LIST_HEAD(&dev->dma_pools);
|
||||
init_MUTEX(&dev->sem);
|
||||
mutex_init(&dev->mutex);
|
||||
lockdep_set_novalidate_class(&dev->mutex);
|
||||
spin_lock_init(&dev->devres_lock);
|
||||
INIT_LIST_HEAD(&dev->devres_head);
|
||||
device_init_wakeup(dev, 0);
|
||||
device_pm_init(dev);
|
||||
set_dev_node(dev, -1);
|
||||
}
|
||||
|
@ -596,11 +607,59 @@ static struct kobject *virtual_device_parent(struct device *dev)
|
|||
return virtual_dir;
|
||||
}
|
||||
|
||||
struct class_dir {
|
||||
struct kobject kobj;
|
||||
struct class *class;
|
||||
};
|
||||
|
||||
#define to_class_dir(obj) container_of(obj, struct class_dir, kobj)
|
||||
|
||||
static void class_dir_release(struct kobject *kobj)
|
||||
{
|
||||
struct class_dir *dir = to_class_dir(kobj);
|
||||
kfree(dir);
|
||||
}
|
||||
|
||||
static const
|
||||
struct kobj_ns_type_operations *class_dir_child_ns_type(struct kobject *kobj)
|
||||
{
|
||||
struct class_dir *dir = to_class_dir(kobj);
|
||||
return dir->class->ns_type;
|
||||
}
|
||||
|
||||
static struct kobj_type class_dir_ktype = {
|
||||
.release = class_dir_release,
|
||||
.sysfs_ops = &kobj_sysfs_ops,
|
||||
.child_ns_type = class_dir_child_ns_type
|
||||
};
|
||||
|
||||
static struct kobject *
|
||||
class_dir_create_and_add(struct class *class, struct kobject *parent_kobj)
|
||||
{
|
||||
struct class_dir *dir;
|
||||
int retval;
|
||||
|
||||
dir = kzalloc(sizeof(*dir), GFP_KERNEL);
|
||||
if (!dir)
|
||||
return NULL;
|
||||
|
||||
dir->class = class;
|
||||
kobject_init(&dir->kobj, &class_dir_ktype);
|
||||
|
||||
dir->kobj.kset = &class->p->class_dirs;
|
||||
|
||||
retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name);
|
||||
if (retval < 0) {
|
||||
kobject_put(&dir->kobj);
|
||||
return NULL;
|
||||
}
|
||||
return &dir->kobj;
|
||||
}
|
||||
|
||||
|
||||
static struct kobject *get_device_parent(struct device *dev,
|
||||
struct device *parent)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (dev->class) {
|
||||
static DEFINE_MUTEX(gdp_mutex);
|
||||
struct kobject *kobj = NULL;
|
||||
|
@ -635,18 +694,7 @@ static struct kobject *get_device_parent(struct device *dev,
|
|||
}
|
||||
|
||||
/* or create a new class-directory at the parent device */
|
||||
k = kobject_create();
|
||||
if (!k) {
|
||||
mutex_unlock(&gdp_mutex);
|
||||
return NULL;
|
||||
}
|
||||
k->kset = &dev->class->p->class_dirs;
|
||||
retval = kobject_add(k, parent_kobj, "%s", dev->class->name);
|
||||
if (retval < 0) {
|
||||
mutex_unlock(&gdp_mutex);
|
||||
kobject_put(k);
|
||||
return NULL;
|
||||
}
|
||||
k = class_dir_create_and_add(dev->class, parent_kobj);
|
||||
/* do not emit an uevent for this simple "glue" directory */
|
||||
mutex_unlock(&gdp_mutex);
|
||||
return k;
|
||||
|
@ -738,7 +786,7 @@ out_device:
|
|||
out_busid:
|
||||
if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
|
||||
device_is_not_partition(dev))
|
||||
sysfs_remove_link(&dev->class->p->class_subsys.kobj,
|
||||
sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj,
|
||||
dev_name(dev));
|
||||
#else
|
||||
/* link in the class directory pointing to the device */
|
||||
|
@ -756,7 +804,7 @@ out_busid:
|
|||
return 0;
|
||||
|
||||
out_busid:
|
||||
sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev));
|
||||
sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev));
|
||||
#endif
|
||||
|
||||
out_subsys:
|
||||
|
@ -784,13 +832,13 @@ static void device_remove_class_symlinks(struct device *dev)
|
|||
|
||||
if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
|
||||
device_is_not_partition(dev))
|
||||
sysfs_remove_link(&dev->class->p->class_subsys.kobj,
|
||||
sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj,
|
||||
dev_name(dev));
|
||||
#else
|
||||
if (dev->parent && device_is_not_partition(dev))
|
||||
sysfs_remove_link(&dev->kobj, "device");
|
||||
|
||||
sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev));
|
||||
sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev));
|
||||
#endif
|
||||
|
||||
sysfs_remove_link(&dev->kobj, "subsystem");
|
||||
|
@ -1372,7 +1420,7 @@ struct device *__root_device_register(const char *name, struct module *owner)
|
|||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MODULE /* gotta find a "cleaner" way to do this */
|
||||
#ifdef CONFIG_MODULES /* gotta find a "cleaner" way to do this */
|
||||
if (owner) {
|
||||
struct module_kobject *mk = &owner->mkobj;
|
||||
|
||||
|
@ -1576,6 +1624,14 @@ int device_rename(struct device *dev, char *new_name)
|
|||
goto out;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SYSFS_DEPRECATED
|
||||
if (dev->class) {
|
||||
error = sysfs_rename_link(&dev->class->p->class_subsys.kobj,
|
||||
&dev->kobj, old_device_name, new_name);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
error = kobject_rename(&dev->kobj, new_name);
|
||||
if (error)
|
||||
goto out;
|
||||
|
@ -1590,11 +1646,6 @@ int device_rename(struct device *dev, char *new_name)
|
|||
new_class_name);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (dev->class) {
|
||||
error = sysfs_rename_link(&dev->class->p->class_subsys.kobj,
|
||||
&dev->kobj, old_device_name, new_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
out:
|
||||
|
@ -1735,10 +1786,25 @@ EXPORT_SYMBOL_GPL(device_move);
|
|||
*/
|
||||
void device_shutdown(void)
|
||||
{
|
||||
struct device *dev, *devn;
|
||||
struct device *dev;
|
||||
|
||||
spin_lock(&devices_kset->list_lock);
|
||||
/*
|
||||
* Walk the devices list backward, shutting down each in turn.
|
||||
* Beware that device unplug events may also start pulling
|
||||
* devices offline, even as the system is shutting down.
|
||||
*/
|
||||
while (!list_empty(&devices_kset->list)) {
|
||||
dev = list_entry(devices_kset->list.prev, struct device,
|
||||
kobj.entry);
|
||||
get_device(dev);
|
||||
/*
|
||||
* Make sure the device is off the kset list, in the
|
||||
* event that dev->*->shutdown() doesn't remove it.
|
||||
*/
|
||||
list_del_init(&dev->kobj.entry);
|
||||
spin_unlock(&devices_kset->list_lock);
|
||||
|
||||
list_for_each_entry_safe_reverse(dev, devn, &devices_kset->list,
|
||||
kobj.entry) {
|
||||
if (dev->bus && dev->bus->shutdown) {
|
||||
dev_dbg(dev, "shutdown\n");
|
||||
dev->bus->shutdown(dev);
|
||||
|
@ -1746,6 +1812,10 @@ void device_shutdown(void)
|
|||
dev_dbg(dev, "shutdown\n");
|
||||
dev->driver->shutdown(dev);
|
||||
}
|
||||
put_device(dev);
|
||||
|
||||
spin_lock(&devices_kset->list_lock);
|
||||
}
|
||||
spin_unlock(&devices_kset->list_lock);
|
||||
async_synchronize_full();
|
||||
}
|
||||
|
|
|
@ -186,7 +186,7 @@ static ssize_t print_cpus_offline(struct sysdev_class *class,
|
|||
/* display offline cpus < nr_cpu_ids */
|
||||
if (!alloc_cpumask_var(&offline, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
cpumask_complement(offline, cpu_online_mask);
|
||||
cpumask_andnot(offline, cpu_possible_mask, cpu_online_mask);
|
||||
n = cpulist_scnprintf(buf, len, offline);
|
||||
free_cpumask_var(offline);
|
||||
|
||||
|
|
|
@ -40,11 +40,11 @@ static void driver_bound(struct device *dev)
|
|||
pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),
|
||||
__func__, dev->driver->name);
|
||||
|
||||
klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
|
||||
|
||||
if (dev->bus)
|
||||
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
|
||||
BUS_NOTIFY_BOUND_DRIVER, dev);
|
||||
|
||||
klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
|
||||
}
|
||||
|
||||
static int driver_sysfs_add(struct device *dev)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/namei.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/shmem_fs.h>
|
||||
#include <linux/ramfs.h>
|
||||
#include <linux/cred.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/init_task.h>
|
||||
|
@ -45,7 +46,11 @@ __setup("devtmpfs.mount=", mount_param);
|
|||
static int dev_get_sb(struct file_system_type *fs_type, int flags,
|
||||
const char *dev_name, void *data, struct vfsmount *mnt)
|
||||
{
|
||||
#ifdef CONFIG_TMPFS
|
||||
return get_sb_single(fs_type, flags, data, shmem_fill_super, mnt);
|
||||
#else
|
||||
return get_sb_single(fs_type, flags, data, ramfs_fill_super, mnt);
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct file_system_type dev_fs_type = {
|
||||
|
|
|
@ -27,6 +27,52 @@ MODULE_AUTHOR("Manuel Estrada Sainz");
|
|||
MODULE_DESCRIPTION("Multi purpose firmware loading support");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* Builtin firmware support */
|
||||
|
||||
#ifdef CONFIG_FW_LOADER
|
||||
|
||||
extern struct builtin_fw __start_builtin_fw[];
|
||||
extern struct builtin_fw __end_builtin_fw[];
|
||||
|
||||
static bool fw_get_builtin_firmware(struct firmware *fw, const char *name)
|
||||
{
|
||||
struct builtin_fw *b_fw;
|
||||
|
||||
for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++) {
|
||||
if (strcmp(name, b_fw->name) == 0) {
|
||||
fw->size = b_fw->size;
|
||||
fw->data = b_fw->data;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool fw_is_builtin_firmware(const struct firmware *fw)
|
||||
{
|
||||
struct builtin_fw *b_fw;
|
||||
|
||||
for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++)
|
||||
if (fw->data == b_fw->data)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#else /* Module case - no builtin firmware support */
|
||||
|
||||
static inline bool fw_get_builtin_firmware(struct firmware *fw, const char *name)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool fw_is_builtin_firmware(const struct firmware *fw)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
enum {
|
||||
FW_STATUS_LOADING,
|
||||
FW_STATUS_DONE,
|
||||
|
@ -40,7 +86,6 @@ static int loading_timeout = 60; /* In seconds */
|
|||
static DEFINE_MUTEX(fw_lock);
|
||||
|
||||
struct firmware_priv {
|
||||
char *fw_id;
|
||||
struct completion completion;
|
||||
struct bin_attribute attr_data;
|
||||
struct firmware *fw;
|
||||
|
@ -48,18 +93,11 @@ struct firmware_priv {
|
|||
struct page **pages;
|
||||
int nr_pages;
|
||||
int page_array_size;
|
||||
const char *vdata;
|
||||
struct timer_list timeout;
|
||||
bool nowait;
|
||||
char fw_id[];
|
||||
};
|
||||
|
||||
#ifdef CONFIG_FW_LOADER
|
||||
extern struct builtin_fw __start_builtin_fw[];
|
||||
extern struct builtin_fw __end_builtin_fw[];
|
||||
#else /* Module case. Avoid ifdefs later; it'll all optimise out */
|
||||
static struct builtin_fw *__start_builtin_fw;
|
||||
static struct builtin_fw *__end_builtin_fw;
|
||||
#endif
|
||||
|
||||
static void
|
||||
fw_load_abort(struct firmware_priv *fw_priv)
|
||||
{
|
||||
|
@ -100,9 +138,25 @@ firmware_timeout_store(struct class *class,
|
|||
return count;
|
||||
}
|
||||
|
||||
static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store);
|
||||
static struct class_attribute firmware_class_attrs[] = {
|
||||
__ATTR(timeout, S_IWUSR | S_IRUGO,
|
||||
firmware_timeout_show, firmware_timeout_store),
|
||||
__ATTR_NULL
|
||||
};
|
||||
|
||||
static void fw_dev_release(struct device *dev);
|
||||
static void fw_dev_release(struct device *dev)
|
||||
{
|
||||
struct firmware_priv *fw_priv = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < fw_priv->nr_pages; i++)
|
||||
__free_page(fw_priv->pages[i]);
|
||||
kfree(fw_priv->pages);
|
||||
kfree(fw_priv);
|
||||
kfree(dev);
|
||||
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
|
@ -112,12 +166,15 @@ static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|||
return -ENOMEM;
|
||||
if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout))
|
||||
return -ENOMEM;
|
||||
if (add_uevent_var(env, "ASYNC=%d", fw_priv->nowait))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct class firmware_class = {
|
||||
.name = "firmware",
|
||||
.class_attrs = firmware_class_attrs,
|
||||
.dev_uevent = firmware_uevent,
|
||||
.dev_release = fw_dev_release,
|
||||
};
|
||||
|
@ -130,6 +187,17 @@ static ssize_t firmware_loading_show(struct device *dev,
|
|||
return sprintf(buf, "%d\n", loading);
|
||||
}
|
||||
|
||||
static void firmware_free_data(const struct firmware *fw)
|
||||
{
|
||||
int i;
|
||||
vunmap(fw->data);
|
||||
if (fw->pages) {
|
||||
for (i = 0; i < PFN_UP(fw->size); i++)
|
||||
__free_page(fw->pages[i]);
|
||||
kfree(fw->pages);
|
||||
}
|
||||
}
|
||||
|
||||
/* Some architectures don't have PAGE_KERNEL_RO */
|
||||
#ifndef PAGE_KERNEL_RO
|
||||
#define PAGE_KERNEL_RO PAGE_KERNEL
|
||||
|
@ -162,21 +230,21 @@ static ssize_t firmware_loading_store(struct device *dev,
|
|||
mutex_unlock(&fw_lock);
|
||||
break;
|
||||
}
|
||||
vfree(fw_priv->fw->data);
|
||||
fw_priv->fw->data = NULL;
|
||||
firmware_free_data(fw_priv->fw);
|
||||
memset(fw_priv->fw, 0, sizeof(struct firmware));
|
||||
/* If the pages are not owned by 'struct firmware' */
|
||||
for (i = 0; i < fw_priv->nr_pages; i++)
|
||||
__free_page(fw_priv->pages[i]);
|
||||
kfree(fw_priv->pages);
|
||||
fw_priv->pages = NULL;
|
||||
fw_priv->page_array_size = 0;
|
||||
fw_priv->nr_pages = 0;
|
||||
fw_priv->fw->size = 0;
|
||||
set_bit(FW_STATUS_LOADING, &fw_priv->status);
|
||||
mutex_unlock(&fw_lock);
|
||||
break;
|
||||
case 0:
|
||||
if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) {
|
||||
vfree(fw_priv->fw->data);
|
||||
vunmap(fw_priv->fw->data);
|
||||
fw_priv->fw->data = vmap(fw_priv->pages,
|
||||
fw_priv->nr_pages,
|
||||
0, PAGE_KERNEL_RO);
|
||||
|
@ -184,7 +252,10 @@ static ssize_t firmware_loading_store(struct device *dev,
|
|||
dev_err(dev, "%s: vmap() failed\n", __func__);
|
||||
goto err;
|
||||
}
|
||||
/* Pages will be freed by vfree() */
|
||||
/* Pages are now owned by 'struct firmware' */
|
||||
fw_priv->fw->pages = fw_priv->pages;
|
||||
fw_priv->pages = NULL;
|
||||
|
||||
fw_priv->page_array_size = 0;
|
||||
fw_priv->nr_pages = 0;
|
||||
complete(&fw_priv->completion);
|
||||
|
@ -207,8 +278,9 @@ static ssize_t firmware_loading_store(struct device *dev,
|
|||
static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);
|
||||
|
||||
static ssize_t
|
||||
firmware_data_read(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
char *buffer, loff_t offset, size_t count)
|
||||
firmware_data_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr, char *buffer, loff_t offset,
|
||||
size_t count)
|
||||
{
|
||||
struct device *dev = to_dev(kobj);
|
||||
struct firmware_priv *fw_priv = dev_get_drvdata(dev);
|
||||
|
@ -291,6 +363,7 @@ fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
|
|||
|
||||
/**
|
||||
* firmware_data_write - write method for firmware
|
||||
* @filp: open sysfs file
|
||||
* @kobj: kobject for the device
|
||||
* @bin_attr: bin_attr structure
|
||||
* @buffer: buffer being written
|
||||
|
@ -301,8 +374,9 @@ fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
|
|||
* the driver as a firmware image.
|
||||
**/
|
||||
static ssize_t
|
||||
firmware_data_write(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
char *buffer, loff_t offset, size_t count)
|
||||
firmware_data_write(struct file* filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr, char *buffer,
|
||||
loff_t offset, size_t count)
|
||||
{
|
||||
struct device *dev = to_dev(kobj);
|
||||
struct firmware_priv *fw_priv = dev_get_drvdata(dev);
|
||||
|
@ -353,21 +427,6 @@ static struct bin_attribute firmware_attr_data_tmpl = {
|
|||
.write = firmware_data_write,
|
||||
};
|
||||
|
||||
static void fw_dev_release(struct device *dev)
|
||||
{
|
||||
struct firmware_priv *fw_priv = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < fw_priv->nr_pages; i++)
|
||||
__free_page(fw_priv->pages[i]);
|
||||
kfree(fw_priv->pages);
|
||||
kfree(fw_priv->fw_id);
|
||||
kfree(fw_priv);
|
||||
kfree(dev);
|
||||
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
static void
|
||||
firmware_class_timeout(u_long data)
|
||||
{
|
||||
|
@ -379,8 +438,8 @@ static int fw_register_device(struct device **dev_p, const char *fw_name,
|
|||
struct device *device)
|
||||
{
|
||||
int retval;
|
||||
struct firmware_priv *fw_priv = kzalloc(sizeof(*fw_priv),
|
||||
GFP_KERNEL);
|
||||
struct firmware_priv *fw_priv =
|
||||
kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL);
|
||||
struct device *f_dev = kzalloc(sizeof(*f_dev), GFP_KERNEL);
|
||||
|
||||
*dev_p = NULL;
|
||||
|
@ -391,16 +450,9 @@ static int fw_register_device(struct device **dev_p, const char *fw_name,
|
|||
goto error_kfree;
|
||||
}
|
||||
|
||||
strcpy(fw_priv->fw_id, fw_name);
|
||||
init_completion(&fw_priv->completion);
|
||||
fw_priv->attr_data = firmware_attr_data_tmpl;
|
||||
fw_priv->fw_id = kstrdup(fw_name, GFP_KERNEL);
|
||||
if (!fw_priv->fw_id) {
|
||||
dev_err(device, "%s: Firmware name allocation failed\n",
|
||||
__func__);
|
||||
retval = -ENOMEM;
|
||||
goto error_kfree;
|
||||
}
|
||||
|
||||
fw_priv->timeout.function = firmware_class_timeout;
|
||||
fw_priv->timeout.data = (u_long) fw_priv;
|
||||
init_timer(&fw_priv->timeout);
|
||||
|
@ -427,7 +479,7 @@ error_kfree:
|
|||
|
||||
static int fw_setup_device(struct firmware *fw, struct device **dev_p,
|
||||
const char *fw_name, struct device *device,
|
||||
int uevent)
|
||||
int uevent, bool nowait)
|
||||
{
|
||||
struct device *f_dev;
|
||||
struct firmware_priv *fw_priv;
|
||||
|
@ -443,6 +495,8 @@ static int fw_setup_device(struct firmware *fw, struct device **dev_p,
|
|||
|
||||
fw_priv = dev_get_drvdata(f_dev);
|
||||
|
||||
fw_priv->nowait = nowait;
|
||||
|
||||
fw_priv->fw = fw;
|
||||
sysfs_bin_attr_init(&fw_priv->attr_data);
|
||||
retval = sysfs_create_bin_file(&f_dev->kobj, &fw_priv->attr_data);
|
||||
|
@ -470,12 +524,11 @@ out:
|
|||
|
||||
static int
|
||||
_request_firmware(const struct firmware **firmware_p, const char *name,
|
||||
struct device *device, int uevent)
|
||||
struct device *device, int uevent, bool nowait)
|
||||
{
|
||||
struct device *f_dev;
|
||||
struct firmware_priv *fw_priv;
|
||||
struct firmware *firmware;
|
||||
struct builtin_fw *builtin;
|
||||
int retval;
|
||||
|
||||
if (!firmware_p)
|
||||
|
@ -489,21 +542,16 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
|
|||
goto out;
|
||||
}
|
||||
|
||||
for (builtin = __start_builtin_fw; builtin != __end_builtin_fw;
|
||||
builtin++) {
|
||||
if (strcmp(name, builtin->name))
|
||||
continue;
|
||||
dev_info(device, "firmware: using built-in firmware %s\n",
|
||||
name);
|
||||
firmware->size = builtin->size;
|
||||
firmware->data = builtin->data;
|
||||
if (fw_get_builtin_firmware(firmware, name)) {
|
||||
dev_dbg(device, "firmware: using built-in firmware %s\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uevent)
|
||||
dev_info(device, "firmware: requesting %s\n", name);
|
||||
dev_dbg(device, "firmware: requesting %s\n", name);
|
||||
|
||||
retval = fw_setup_device(firmware, &f_dev, name, device, uevent);
|
||||
retval = fw_setup_device(firmware, &f_dev, name, device,
|
||||
uevent, nowait);
|
||||
if (retval)
|
||||
goto error_kfree_fw;
|
||||
|
||||
|
@ -560,26 +608,18 @@ request_firmware(const struct firmware **firmware_p, const char *name,
|
|||
struct device *device)
|
||||
{
|
||||
int uevent = 1;
|
||||
return _request_firmware(firmware_p, name, device, uevent);
|
||||
return _request_firmware(firmware_p, name, device, uevent, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* release_firmware: - release the resource associated with a firmware image
|
||||
* @fw: firmware resource to release
|
||||
**/
|
||||
void
|
||||
release_firmware(const struct firmware *fw)
|
||||
void release_firmware(const struct firmware *fw)
|
||||
{
|
||||
struct builtin_fw *builtin;
|
||||
|
||||
if (fw) {
|
||||
for (builtin = __start_builtin_fw; builtin != __end_builtin_fw;
|
||||
builtin++) {
|
||||
if (fw->data == builtin->data)
|
||||
goto free_fw;
|
||||
}
|
||||
vfree(fw->data);
|
||||
free_fw:
|
||||
if (!fw_is_builtin_firmware(fw))
|
||||
firmware_free_data(fw);
|
||||
kfree(fw);
|
||||
}
|
||||
}
|
||||
|
@ -606,7 +646,7 @@ request_firmware_work_func(void *arg)
|
|||
return 0;
|
||||
}
|
||||
ret = _request_firmware(&fw, fw_work->name, fw_work->device,
|
||||
fw_work->uevent);
|
||||
fw_work->uevent, true);
|
||||
|
||||
fw_work->cont(fw, fw_work->context);
|
||||
|
||||
|
@ -670,26 +710,12 @@ request_firmware_nowait(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __init
|
||||
firmware_class_init(void)
|
||||
static int __init firmware_class_init(void)
|
||||
{
|
||||
int error;
|
||||
error = class_register(&firmware_class);
|
||||
if (error) {
|
||||
printk(KERN_ERR "%s: class_register failed\n", __func__);
|
||||
return error;
|
||||
}
|
||||
error = class_create_file(&firmware_class, &class_attr_timeout);
|
||||
if (error) {
|
||||
printk(KERN_ERR "%s: class_create_file failed\n",
|
||||
__func__);
|
||||
class_unregister(&firmware_class);
|
||||
}
|
||||
return error;
|
||||
|
||||
return class_register(&firmware_class);
|
||||
}
|
||||
static void __exit
|
||||
firmware_class_exit(void)
|
||||
|
||||
static void __exit firmware_class_exit(void)
|
||||
{
|
||||
class_unregister(&firmware_class);
|
||||
}
|
||||
|
|
|
@ -15,12 +15,10 @@ static char *make_driver_name(struct device_driver *drv)
|
|||
{
|
||||
char *driver_name;
|
||||
|
||||
driver_name = kmalloc(strlen(drv->name) + strlen(drv->bus->name) + 2,
|
||||
GFP_KERNEL);
|
||||
driver_name = kasprintf(GFP_KERNEL, "%s:%s", drv->bus->name, drv->name);
|
||||
if (!driver_name)
|
||||
return NULL;
|
||||
|
||||
sprintf(driver_name, "%s:%s", drv->bus->name, drv->name);
|
||||
return driver_name;
|
||||
}
|
||||
|
||||
|
|
|
@ -735,7 +735,7 @@ static void platform_pm_complete(struct device *dev)
|
|||
|
||||
#ifdef CONFIG_SUSPEND
|
||||
|
||||
static int platform_pm_suspend(struct device *dev)
|
||||
int __weak platform_pm_suspend(struct device *dev)
|
||||
{
|
||||
struct device_driver *drv = dev->driver;
|
||||
int ret = 0;
|
||||
|
@ -753,7 +753,7 @@ static int platform_pm_suspend(struct device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int platform_pm_suspend_noirq(struct device *dev)
|
||||
int __weak platform_pm_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct device_driver *drv = dev->driver;
|
||||
int ret = 0;
|
||||
|
@ -769,7 +769,7 @@ static int platform_pm_suspend_noirq(struct device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int platform_pm_resume(struct device *dev)
|
||||
int __weak platform_pm_resume(struct device *dev)
|
||||
{
|
||||
struct device_driver *drv = dev->driver;
|
||||
int ret = 0;
|
||||
|
@ -787,7 +787,7 @@ static int platform_pm_resume(struct device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int platform_pm_resume_noirq(struct device *dev)
|
||||
int __weak platform_pm_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct device_driver *drv = dev->driver;
|
||||
int ret = 0;
|
||||
|
|
|
@ -835,6 +835,8 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
|
|||
|
||||
set_capacity(lo->lo_disk, size);
|
||||
bd_set_size(bdev, size << 9);
|
||||
/* let user-space know about the new size */
|
||||
kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE);
|
||||
|
||||
set_blocksize(bdev, lo_blocksize);
|
||||
|
||||
|
@ -858,6 +860,7 @@ out_clr:
|
|||
set_capacity(lo->lo_disk, 0);
|
||||
invalidate_bdev(bdev);
|
||||
bd_set_size(bdev, 0);
|
||||
kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE);
|
||||
mapping_set_gfp_mask(mapping, lo->old_gfp_mask);
|
||||
lo->lo_state = Lo_unbound;
|
||||
out_putf:
|
||||
|
@ -944,8 +947,11 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
|
|||
if (bdev)
|
||||
invalidate_bdev(bdev);
|
||||
set_capacity(lo->lo_disk, 0);
|
||||
if (bdev)
|
||||
if (bdev) {
|
||||
bd_set_size(bdev, 0);
|
||||
/* let user-space know about this change */
|
||||
kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE);
|
||||
}
|
||||
mapping_set_gfp_mask(filp->f_mapping, gfp);
|
||||
lo->lo_state = Lo_unbound;
|
||||
/* This is safe: open() is still holding a reference. */
|
||||
|
@ -1189,6 +1195,8 @@ static int loop_set_capacity(struct loop_device *lo, struct block_device *bdev)
|
|||
sz <<= 9;
|
||||
mutex_lock(&bdev->bd_mutex);
|
||||
bd_set_size(bdev, sz);
|
||||
/* let user-space know about the new size */
|
||||
kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE);
|
||||
mutex_unlock(&bdev->bd_mutex);
|
||||
|
||||
out:
|
||||
|
|
|
@ -149,7 +149,7 @@ static ssize_t smi_data_buf_size_store(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t smi_data_read(struct kobject *kobj,
|
||||
static ssize_t smi_data_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t count)
|
||||
{
|
||||
|
@ -162,7 +162,7 @@ static ssize_t smi_data_read(struct kobject *kobj,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t smi_data_write(struct kobject *kobj,
|
||||
static ssize_t smi_data_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t count)
|
||||
{
|
||||
|
|
|
@ -522,7 +522,7 @@ static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count)
|
|||
rbu_data.image_update_buffer, rbu_data.bios_image_size);
|
||||
}
|
||||
|
||||
static ssize_t read_rbu_data(struct kobject *kobj,
|
||||
static ssize_t read_rbu_data(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buffer, loff_t pos, size_t count)
|
||||
{
|
||||
|
@ -576,7 +576,7 @@ static void callbackfn_rbu(const struct firmware *fw, void *context)
|
|||
release_firmware(fw);
|
||||
}
|
||||
|
||||
static ssize_t read_rbu_image_type(struct kobject *kobj,
|
||||
static ssize_t read_rbu_image_type(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buffer, loff_t pos, size_t count)
|
||||
{
|
||||
|
@ -586,7 +586,7 @@ static ssize_t read_rbu_image_type(struct kobject *kobj,
|
|||
return size;
|
||||
}
|
||||
|
||||
static ssize_t write_rbu_image_type(struct kobject *kobj,
|
||||
static ssize_t write_rbu_image_type(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buffer, loff_t pos, size_t count)
|
||||
{
|
||||
|
@ -647,7 +647,7 @@ static ssize_t write_rbu_image_type(struct kobject *kobj,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t read_rbu_packet_size(struct kobject *kobj,
|
||||
static ssize_t read_rbu_packet_size(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buffer, loff_t pos, size_t count)
|
||||
{
|
||||
|
@ -660,7 +660,7 @@ static ssize_t read_rbu_packet_size(struct kobject *kobj,
|
|||
return size;
|
||||
}
|
||||
|
||||
static ssize_t write_rbu_packet_size(struct kobject *kobj,
|
||||
static ssize_t write_rbu_packet_size(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buffer, loff_t pos, size_t count)
|
||||
{
|
||||
|
|
|
@ -402,7 +402,7 @@ efivar_unregister(struct efivar_entry *var)
|
|||
}
|
||||
|
||||
|
||||
static ssize_t efivar_create(struct kobject *kobj,
|
||||
static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t count)
|
||||
{
|
||||
|
@ -461,7 +461,7 @@ static ssize_t efivar_create(struct kobject *kobj,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t efivar_delete(struct kobject *kobj,
|
||||
static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t count)
|
||||
{
|
||||
|
|
|
@ -399,7 +399,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
|
|||
goto free_id;
|
||||
}
|
||||
|
||||
pdesc->value_sd = sysfs_get_dirent(dev->kobj.sd, "value");
|
||||
pdesc->value_sd = sysfs_get_dirent(dev->kobj.sd, NULL, "value");
|
||||
if (!pdesc->value_sd) {
|
||||
ret = -ENODEV;
|
||||
goto free_id;
|
||||
|
|
|
@ -193,8 +193,9 @@ static ssize_t enabled_show(struct device *device,
|
|||
"disabled");
|
||||
}
|
||||
|
||||
static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
static ssize_t edid_show(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
struct device *connector_dev = container_of(kobj, struct device, kobj);
|
||||
struct drm_connector *connector = to_drm_connector(connector_dev);
|
||||
|
|
|
@ -1678,9 +1678,9 @@ int bitmap_create(mddev_t *mddev)
|
|||
|
||||
bitmap->mddev = mddev;
|
||||
|
||||
bm = sysfs_get_dirent(mddev->kobj.sd, "bitmap");
|
||||
bm = sysfs_get_dirent(mddev->kobj.sd, NULL, "bitmap");
|
||||
if (bm) {
|
||||
bitmap->sysfs_can_clear = sysfs_get_dirent(bm, "can_clear");
|
||||
bitmap->sysfs_can_clear = sysfs_get_dirent(bm, NULL, "can_clear");
|
||||
sysfs_put(bm);
|
||||
} else
|
||||
bitmap->sysfs_can_clear = NULL;
|
||||
|
|
|
@ -1766,7 +1766,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
|
|||
kobject_del(&rdev->kobj);
|
||||
goto fail;
|
||||
}
|
||||
rdev->sysfs_state = sysfs_get_dirent(rdev->kobj.sd, "state");
|
||||
rdev->sysfs_state = sysfs_get_dirent(rdev->kobj.sd, NULL, "state");
|
||||
|
||||
list_add_rcu(&rdev->same_set, &mddev->disks);
|
||||
bd_claim_by_disk(rdev->bdev, rdev->bdev->bd_holder, mddev->gendisk);
|
||||
|
@ -4189,7 +4189,7 @@ static int md_alloc(dev_t dev, char *name)
|
|||
mutex_unlock(&disks_mutex);
|
||||
if (!error) {
|
||||
kobject_uevent(&mddev->kobj, KOBJ_ADD);
|
||||
mddev->sysfs_state = sysfs_get_dirent(mddev->kobj.sd, "array_state");
|
||||
mddev->sysfs_state = sysfs_get_dirent(mddev->kobj.sd, NULL, "array_state");
|
||||
}
|
||||
mddev_put(mddev);
|
||||
return error;
|
||||
|
@ -4398,7 +4398,7 @@ static int do_md_run(mddev_t * mddev)
|
|||
printk(KERN_WARNING
|
||||
"md: cannot register extra attributes for %s\n",
|
||||
mdname(mddev));
|
||||
mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, "sync_action");
|
||||
mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, NULL, "sync_action");
|
||||
} else if (mddev->ro == 2) /* auto-readonly not meaningful */
|
||||
mddev->ro = 0;
|
||||
|
||||
|
|
|
@ -707,7 +707,7 @@ static ssize_t __c2port_read_flash_data(struct c2port_device *dev,
|
|||
return nread;
|
||||
}
|
||||
|
||||
static ssize_t c2port_read_flash_data(struct kobject *kobj,
|
||||
static ssize_t c2port_read_flash_data(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buffer, loff_t offset, size_t count)
|
||||
{
|
||||
|
@ -824,7 +824,7 @@ static ssize_t __c2port_write_flash_data(struct c2port_device *dev,
|
|||
return nwrite;
|
||||
}
|
||||
|
||||
static ssize_t c2port_write_flash_data(struct kobject *kobj,
|
||||
static ssize_t c2port_write_flash_data(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buffer, loff_t offset, size_t count)
|
||||
{
|
||||
|
|
|
@ -140,7 +140,8 @@ static const struct attribute_group ds1682_group = {
|
|||
/*
|
||||
* User data attribute
|
||||
*/
|
||||
static ssize_t ds1682_eeprom_read(struct kobject *kobj, struct bin_attribute *attr,
|
||||
static ssize_t ds1682_eeprom_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct i2c_client *client = kobj_to_i2c_client(kobj);
|
||||
|
@ -163,7 +164,8 @@ static ssize_t ds1682_eeprom_read(struct kobject *kobj, struct bin_attribute *at
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t ds1682_eeprom_write(struct kobject *kobj, struct bin_attribute *attr,
|
||||
static ssize_t ds1682_eeprom_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct i2c_client *client = kobj_to_i2c_client(kobj);
|
||||
|
|
|
@ -274,7 +274,8 @@ static ssize_t at24_read(struct at24_data *at24,
|
|||
return retval;
|
||||
}
|
||||
|
||||
static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr,
|
||||
static ssize_t at24_bin_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct at24_data *at24;
|
||||
|
@ -395,7 +396,8 @@ static ssize_t at24_write(struct at24_data *at24, const char *buf, loff_t off,
|
|||
return retval;
|
||||
}
|
||||
|
||||
static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr,
|
||||
static ssize_t at24_bin_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct at24_data *at24;
|
||||
|
|
|
@ -126,7 +126,8 @@ at25_ee_read(
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
at25_bin_read(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
at25_bin_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct device *dev;
|
||||
|
@ -253,7 +254,8 @@ at25_ee_write(struct at25_data *at25, const char *buf, loff_t off,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
at25_bin_write(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
at25_bin_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct device *dev;
|
||||
|
|
|
@ -81,7 +81,8 @@ exit:
|
|||
mutex_unlock(&data->update_lock);
|
||||
}
|
||||
|
||||
static ssize_t eeprom_read(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
|
||||
|
|
|
@ -107,7 +107,7 @@ exit_up:
|
|||
mutex_unlock(&data->update_lock);
|
||||
}
|
||||
|
||||
static ssize_t max6875_read(struct kobject *kobj,
|
||||
static ssize_t max6875_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <linux/mutex.h>
|
||||
#include <linux/radix-tree.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <linux/mlx4/device.h>
|
||||
|
|
|
@ -2560,7 +2560,8 @@ netxen_sysfs_validate_crb(struct netxen_adapter *adapter,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
netxen_sysfs_read_crb(struct kobject *kobj, struct bin_attribute *attr,
|
||||
netxen_sysfs_read_crb(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t offset, size_t size)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
|
@ -2587,7 +2588,8 @@ netxen_sysfs_read_crb(struct kobject *kobj, struct bin_attribute *attr,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
netxen_sysfs_write_crb(struct kobject *kobj, struct bin_attribute *attr,
|
||||
netxen_sysfs_write_crb(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t offset, size_t size)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
|
@ -2627,7 +2629,8 @@ netxen_sysfs_validate_mem(struct netxen_adapter *adapter,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
netxen_sysfs_read_mem(struct kobject *kobj, struct bin_attribute *attr,
|
||||
netxen_sysfs_read_mem(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t offset, size_t size)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
|
@ -2647,7 +2650,7 @@ netxen_sysfs_read_mem(struct kobject *kobj, struct bin_attribute *attr,
|
|||
return size;
|
||||
}
|
||||
|
||||
static ssize_t netxen_sysfs_write_mem(struct kobject *kobj,
|
||||
static ssize_t netxen_sysfs_write_mem(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf,
|
||||
loff_t offset, size_t size)
|
||||
{
|
||||
|
|
|
@ -2464,7 +2464,8 @@ qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
qlcnic_sysfs_read_crb(struct kobject *kobj, struct bin_attribute *attr,
|
||||
qlcnic_sysfs_read_crb(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t offset, size_t size)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
|
@ -2488,7 +2489,8 @@ qlcnic_sysfs_read_crb(struct kobject *kobj, struct bin_attribute *attr,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
qlcnic_sysfs_write_crb(struct kobject *kobj, struct bin_attribute *attr,
|
||||
qlcnic_sysfs_write_crb(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t offset, size_t size)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
|
@ -2525,7 +2527,8 @@ qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
qlcnic_sysfs_read_mem(struct kobject *kobj, struct bin_attribute *attr,
|
||||
qlcnic_sysfs_read_mem(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t offset, size_t size)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
|
@ -2546,7 +2549,8 @@ qlcnic_sysfs_read_mem(struct kobject *kobj, struct bin_attribute *attr,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
qlcnic_sysfs_write_mem(struct kobject *kobj, struct bin_attribute *attr,
|
||||
qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t offset, size_t size)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
|
|
|
@ -108,7 +108,7 @@ static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status);
|
|||
static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status);
|
||||
static void ibm_handle_events(acpi_handle handle, u32 event, void *context);
|
||||
static int ibm_get_table_from_acpi(char **bufp);
|
||||
static ssize_t ibm_read_apci_table(struct kobject *kobj,
|
||||
static ssize_t ibm_read_apci_table(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buffer, loff_t pos, size_t size);
|
||||
static acpi_status __init ibm_find_acpi_device(acpi_handle handle,
|
||||
|
@ -351,6 +351,7 @@ read_table_done:
|
|||
|
||||
/**
|
||||
* ibm_read_apci_table - callback for the sysfs apci_table file
|
||||
* @filp: the open sysfs file
|
||||
* @kobj: the kobject this binary attribute is a part of
|
||||
* @bin_attr: struct bin_attribute for this file
|
||||
* @buffer: the kernel space buffer to fill
|
||||
|
@ -364,7 +365,7 @@ read_table_done:
|
|||
* things get really tricky here...
|
||||
* our solution is to only allow reading the table in all at once.
|
||||
*/
|
||||
static ssize_t ibm_read_apci_table(struct kobject *kobj,
|
||||
static ssize_t ibm_read_apci_table(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buffer, loff_t pos, size_t size)
|
||||
{
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/stat.h>
|
||||
#include <linux/topology.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/pci-aspm.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -357,7 +358,8 @@ boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
struct device_attribute vga_attr = __ATTR_RO(boot_vga);
|
||||
|
||||
static ssize_t
|
||||
pci_read_config(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
pci_read_config(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
|
||||
|
@ -366,7 +368,7 @@ pci_read_config(struct kobject *kobj, struct bin_attribute *bin_attr,
|
|||
u8 *data = (u8*) buf;
|
||||
|
||||
/* Several chips lock up trying to read undefined config space */
|
||||
if (capable(CAP_SYS_ADMIN)) {
|
||||
if (cap_raised(filp->f_cred->cap_effective, CAP_SYS_ADMIN)) {
|
||||
size = dev->cfg_size;
|
||||
} else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
|
||||
size = 128;
|
||||
|
@ -430,7 +432,8 @@ pci_read_config(struct kobject *kobj, struct bin_attribute *bin_attr,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
pci_write_config(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
pci_write_config(struct file* filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
|
||||
|
@ -487,7 +490,8 @@ pci_write_config(struct kobject *kobj, struct bin_attribute *bin_attr,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
read_vpd_attr(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
read_vpd_attr(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct pci_dev *dev =
|
||||
|
@ -502,7 +506,8 @@ read_vpd_attr(struct kobject *kobj, struct bin_attribute *bin_attr,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
write_vpd_attr(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
write_vpd_attr(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct pci_dev *dev =
|
||||
|
@ -519,6 +524,7 @@ write_vpd_attr(struct kobject *kobj, struct bin_attribute *bin_attr,
|
|||
#ifdef HAVE_PCI_LEGACY
|
||||
/**
|
||||
* pci_read_legacy_io - read byte(s) from legacy I/O port space
|
||||
* @filp: open sysfs file
|
||||
* @kobj: kobject corresponding to file to read from
|
||||
* @bin_attr: struct bin_attribute for this file
|
||||
* @buf: buffer to store results
|
||||
|
@ -529,7 +535,8 @@ write_vpd_attr(struct kobject *kobj, struct bin_attribute *bin_attr,
|
|||
* callback routine (pci_legacy_read).
|
||||
*/
|
||||
static ssize_t
|
||||
pci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
pci_read_legacy_io(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct pci_bus *bus = to_pci_bus(container_of(kobj,
|
||||
|
@ -545,6 +552,7 @@ pci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
|
|||
|
||||
/**
|
||||
* pci_write_legacy_io - write byte(s) to legacy I/O port space
|
||||
* @filp: open sysfs file
|
||||
* @kobj: kobject corresponding to file to read from
|
||||
* @bin_attr: struct bin_attribute for this file
|
||||
* @buf: buffer containing value to be written
|
||||
|
@ -555,7 +563,8 @@ pci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
|
|||
* callback routine (pci_legacy_write).
|
||||
*/
|
||||
static ssize_t
|
||||
pci_write_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
pci_write_legacy_io(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct pci_bus *bus = to_pci_bus(container_of(kobj,
|
||||
|
@ -570,6 +579,7 @@ pci_write_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
|
|||
|
||||
/**
|
||||
* pci_mmap_legacy_mem - map legacy PCI memory into user memory space
|
||||
* @filp: open sysfs file
|
||||
* @kobj: kobject corresponding to device to be mapped
|
||||
* @attr: struct bin_attribute for this file
|
||||
* @vma: struct vm_area_struct passed to mmap
|
||||
|
@ -579,7 +589,8 @@ pci_write_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
|
|||
* memory space.
|
||||
*/
|
||||
static int
|
||||
pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr,
|
||||
pci_mmap_legacy_mem(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct pci_bus *bus = to_pci_bus(container_of(kobj,
|
||||
|
@ -591,6 +602,7 @@ pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr,
|
|||
|
||||
/**
|
||||
* pci_mmap_legacy_io - map legacy PCI IO into user memory space
|
||||
* @filp: open sysfs file
|
||||
* @kobj: kobject corresponding to device to be mapped
|
||||
* @attr: struct bin_attribute for this file
|
||||
* @vma: struct vm_area_struct passed to mmap
|
||||
|
@ -600,7 +612,8 @@ pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr,
|
|||
* memory space. Returns -ENOSYS if the operation isn't supported
|
||||
*/
|
||||
static int
|
||||
pci_mmap_legacy_io(struct kobject *kobj, struct bin_attribute *attr,
|
||||
pci_mmap_legacy_io(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct pci_bus *bus = to_pci_bus(container_of(kobj,
|
||||
|
@ -750,14 +763,16 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
|
|||
}
|
||||
|
||||
static int
|
||||
pci_mmap_resource_uc(struct kobject *kobj, struct bin_attribute *attr,
|
||||
pci_mmap_resource_uc(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
return pci_mmap_resource(kobj, attr, vma, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
pci_mmap_resource_wc(struct kobject *kobj, struct bin_attribute *attr,
|
||||
pci_mmap_resource_wc(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
return pci_mmap_resource(kobj, attr, vma, 1);
|
||||
|
@ -861,6 +876,7 @@ void __weak pci_remove_resource_files(struct pci_dev *dev) { return; }
|
|||
|
||||
/**
|
||||
* pci_write_rom - used to enable access to the PCI ROM display
|
||||
* @filp: sysfs file
|
||||
* @kobj: kernel object handle
|
||||
* @bin_attr: struct bin_attribute for this file
|
||||
* @buf: user input
|
||||
|
@ -870,7 +886,8 @@ void __weak pci_remove_resource_files(struct pci_dev *dev) { return; }
|
|||
* writing anything except 0 enables it
|
||||
*/
|
||||
static ssize_t
|
||||
pci_write_rom(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
pci_write_rom(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj));
|
||||
|
@ -885,6 +902,7 @@ pci_write_rom(struct kobject *kobj, struct bin_attribute *bin_attr,
|
|||
|
||||
/**
|
||||
* pci_read_rom - read a PCI ROM
|
||||
* @filp: sysfs file
|
||||
* @kobj: kernel object handle
|
||||
* @bin_attr: struct bin_attribute for this file
|
||||
* @buf: where to put the data we read from the ROM
|
||||
|
@ -895,7 +913,8 @@ pci_write_rom(struct kobject *kobj, struct bin_attribute *bin_attr,
|
|||
* device corresponding to @kobj.
|
||||
*/
|
||||
static ssize_t
|
||||
pci_read_rom(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
pci_read_rom(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj));
|
||||
|
|
|
@ -1531,7 +1531,7 @@ static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf,
|
|||
}
|
||||
|
||||
|
||||
static ssize_t pccard_show_cis(struct kobject *kobj,
|
||||
static ssize_t pccard_show_cis(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -1562,7 +1562,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj,
|
|||
}
|
||||
|
||||
|
||||
static ssize_t pccard_store_cis(struct kobject *kobj,
|
||||
static ssize_t pccard_store_cis(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
|
|
@ -354,7 +354,7 @@ static enum power_supply_property olpc_bat_props[] = {
|
|||
#define EEPROM_END 0x80
|
||||
#define EEPROM_SIZE (EEPROM_END - EEPROM_START)
|
||||
|
||||
static ssize_t olpc_bat_eeprom_read(struct kobject *kobj,
|
||||
static ssize_t olpc_bat_eeprom_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf, loff_t off, size_t count)
|
||||
{
|
||||
uint8_t ec_byte;
|
||||
|
|
|
@ -68,7 +68,8 @@ struct device_attribute rio_dev_attrs[] = {
|
|||
};
|
||||
|
||||
static ssize_t
|
||||
rio_read_config(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
rio_read_config(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct rio_dev *dev =
|
||||
|
@ -139,7 +140,8 @@ rio_read_config(struct kobject *kobj, struct bin_attribute *bin_attr,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
rio_write_config(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
rio_write_config(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct rio_dev *dev =
|
||||
|
|
|
@ -519,7 +519,8 @@ static const struct rtc_class_ops cmos_rtc_ops = {
|
|||
#define NVRAM_OFFSET (RTC_REG_D + 1)
|
||||
|
||||
static ssize_t
|
||||
cmos_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
|
||||
cmos_nvram_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
int retval;
|
||||
|
@ -547,7 +548,8 @@ cmos_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
cmos_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
|
||||
cmos_nvram_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct cmos_rtc *cmos;
|
||||
|
|
|
@ -542,7 +542,8 @@ static void msg_init(struct spi_message *m, struct spi_transfer *x,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
ds1305_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
|
||||
ds1305_nvram_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct spi_device *spi;
|
||||
|
@ -572,7 +573,8 @@ ds1305_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
ds1305_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
|
||||
ds1305_nvram_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct spi_device *spi;
|
||||
|
|
|
@ -556,7 +556,8 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
|
|||
#define NVRAM_SIZE 56
|
||||
|
||||
static ssize_t
|
||||
ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
|
||||
ds1307_nvram_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
|
@ -580,7 +581,8 @@ ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
|
||||
ds1307_nvram_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
|
|
|
@ -423,7 +423,8 @@ static const struct rtc_class_ops ds1511_rtc_ops = {
|
|||
};
|
||||
|
||||
static ssize_t
|
||||
ds1511_nvram_read(struct kobject *kobj, struct bin_attribute *ba,
|
||||
ds1511_nvram_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *ba,
|
||||
char *buf, loff_t pos, size_t size)
|
||||
{
|
||||
ssize_t count;
|
||||
|
@ -452,7 +453,8 @@ ds1511_nvram_read(struct kobject *kobj, struct bin_attribute *ba,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
ds1511_nvram_write(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
ds1511_nvram_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t size)
|
||||
{
|
||||
ssize_t count;
|
||||
|
|
|
@ -252,7 +252,7 @@ static const struct rtc_class_ops ds1553_rtc_ops = {
|
|||
.update_irq_enable = ds1553_rtc_update_irq_enable,
|
||||
};
|
||||
|
||||
static ssize_t ds1553_nvram_read(struct kobject *kobj,
|
||||
static ssize_t ds1553_nvram_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t size)
|
||||
{
|
||||
|
@ -267,7 +267,7 @@ static ssize_t ds1553_nvram_read(struct kobject *kobj,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t ds1553_nvram_write(struct kobject *kobj,
|
||||
static ssize_t ds1553_nvram_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t size)
|
||||
{
|
||||
|
|
|
@ -128,7 +128,7 @@ static const struct rtc_class_ops ds1742_rtc_ops = {
|
|||
.set_time = ds1742_rtc_set_time,
|
||||
};
|
||||
|
||||
static ssize_t ds1742_nvram_read(struct kobject *kobj,
|
||||
static ssize_t ds1742_nvram_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t size)
|
||||
{
|
||||
|
@ -143,7 +143,7 @@ static ssize_t ds1742_nvram_read(struct kobject *kobj,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t ds1742_nvram_write(struct kobject *kobj,
|
||||
static ssize_t ds1742_nvram_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t size)
|
||||
{
|
||||
|
|
|
@ -343,7 +343,7 @@ static const struct rtc_class_ops m48t02_rtc_ops = {
|
|||
.set_time = m48t59_rtc_set_time,
|
||||
};
|
||||
|
||||
static ssize_t m48t59_nvram_read(struct kobject *kobj,
|
||||
static ssize_t m48t59_nvram_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t size)
|
||||
{
|
||||
|
@ -363,7 +363,7 @@ static ssize_t m48t59_nvram_read(struct kobject *kobj,
|
|||
return cnt;
|
||||
}
|
||||
|
||||
static ssize_t m48t59_nvram_write(struct kobject *kobj,
|
||||
static ssize_t m48t59_nvram_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t size)
|
||||
{
|
||||
|
|
|
@ -244,7 +244,7 @@ static const struct rtc_class_ops stk17ta8_rtc_ops = {
|
|||
.alarm_irq_enable = stk17ta8_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static ssize_t stk17ta8_nvram_read(struct kobject *kobj,
|
||||
static ssize_t stk17ta8_nvram_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf,
|
||||
loff_t pos, size_t size)
|
||||
{
|
||||
|
@ -259,7 +259,7 @@ static ssize_t stk17ta8_nvram_read(struct kobject *kobj,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t stk17ta8_nvram_write(struct kobject *kobj,
|
||||
static ssize_t stk17ta8_nvram_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf,
|
||||
loff_t pos, size_t size)
|
||||
{
|
||||
|
|
|
@ -188,7 +188,7 @@ static const struct rtc_class_ops tx4939_rtc_ops = {
|
|||
.alarm_irq_enable = tx4939_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static ssize_t tx4939_rtc_nvram_read(struct kobject *kobj,
|
||||
static ssize_t tx4939_rtc_nvram_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t size)
|
||||
{
|
||||
|
@ -207,7 +207,7 @@ static ssize_t tx4939_rtc_nvram_read(struct kobject *kobj,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t tx4939_rtc_nvram_write(struct kobject *kobj,
|
||||
static ssize_t tx4939_rtc_nvram_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t size)
|
||||
{
|
||||
|
|
|
@ -135,7 +135,8 @@ static int s390_vary_chpid(struct chp_id chpid, int on)
|
|||
/*
|
||||
* Channel measurement related functions
|
||||
*/
|
||||
static ssize_t chp_measurement_chars_read(struct kobject *kobj,
|
||||
static ssize_t chp_measurement_chars_read(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -182,7 +183,7 @@ static void chp_measurement_copy_block(struct cmg_entry *buf,
|
|||
} while (reference_buf.values[0] != buf->values[0]);
|
||||
}
|
||||
|
||||
static ssize_t chp_measurement_read(struct kobject *kobj,
|
||||
static ssize_t chp_measurement_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
|
|
@ -98,7 +98,7 @@ static int twl_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_res
|
|||
/* Functions */
|
||||
|
||||
/* This function returns AENs through sysfs */
|
||||
static ssize_t twl_sysfs_aen_read(struct kobject *kobj,
|
||||
static ssize_t twl_sysfs_aen_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *outbuf, loff_t offset, size_t count)
|
||||
{
|
||||
|
@ -129,7 +129,7 @@ static struct bin_attribute twl_sysfs_aen_read_attr = {
|
|||
};
|
||||
|
||||
/* This function returns driver compatibility info through sysfs */
|
||||
static ssize_t twl_sysfs_compat_info(struct kobject *kobj,
|
||||
static ssize_t twl_sysfs_compat_info(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *outbuf, loff_t offset, size_t count)
|
||||
{
|
||||
|
|
|
@ -59,7 +59,8 @@
|
|||
|
||||
struct device_attribute *arcmsr_host_attrs[];
|
||||
|
||||
static ssize_t arcmsr_sysfs_iop_message_read(struct kobject *kobj,
|
||||
static ssize_t arcmsr_sysfs_iop_message_read(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
struct bin_attribute *bin,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
|
@ -105,7 +106,8 @@ static ssize_t arcmsr_sysfs_iop_message_read(struct kobject *kobj,
|
|||
return (allxfer_len);
|
||||
}
|
||||
|
||||
static ssize_t arcmsr_sysfs_iop_message_write(struct kobject *kobj,
|
||||
static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
struct bin_attribute *bin,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
|
@ -153,7 +155,8 @@ static ssize_t arcmsr_sysfs_iop_message_write(struct kobject *kobj,
|
|||
}
|
||||
}
|
||||
|
||||
static ssize_t arcmsr_sysfs_iop_message_clear(struct kobject *kobj,
|
||||
static ssize_t arcmsr_sysfs_iop_message_clear(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
struct bin_attribute *bin,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
|
|
|
@ -2919,6 +2919,7 @@ static DEVICE_ATTR(log_level, S_IRUGO | S_IWUSR,
|
|||
#ifdef CONFIG_SCSI_IBMVFC_TRACE
|
||||
/**
|
||||
* ibmvfc_read_trace - Dump the adapter trace
|
||||
* @filp: open sysfs file
|
||||
* @kobj: kobject struct
|
||||
* @bin_attr: bin_attribute struct
|
||||
* @buf: buffer
|
||||
|
@ -2928,7 +2929,7 @@ static DEVICE_ATTR(log_level, S_IRUGO | S_IWUSR,
|
|||
* Return value:
|
||||
* number of bytes printed to buffer
|
||||
**/
|
||||
static ssize_t ibmvfc_read_trace(struct kobject *kobj,
|
||||
static ssize_t ibmvfc_read_trace(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
|
|
@ -3120,6 +3120,7 @@ restart:
|
|||
#ifdef CONFIG_SCSI_IPR_TRACE
|
||||
/**
|
||||
* ipr_read_trace - Dump the adapter trace
|
||||
* @filp: open sysfs file
|
||||
* @kobj: kobject struct
|
||||
* @bin_attr: bin_attribute struct
|
||||
* @buf: buffer
|
||||
|
@ -3129,7 +3130,7 @@ restart:
|
|||
* Return value:
|
||||
* number of bytes printed to buffer
|
||||
**/
|
||||
static ssize_t ipr_read_trace(struct kobject *kobj,
|
||||
static ssize_t ipr_read_trace(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -3764,6 +3765,7 @@ static struct device_attribute *ipr_ioa_attrs[] = {
|
|||
#ifdef CONFIG_SCSI_IPR_DUMP
|
||||
/**
|
||||
* ipr_read_dump - Dump the adapter
|
||||
* @filp: open sysfs file
|
||||
* @kobj: kobject struct
|
||||
* @bin_attr: bin_attribute struct
|
||||
* @buf: buffer
|
||||
|
@ -3773,7 +3775,7 @@ static struct device_attribute *ipr_ioa_attrs[] = {
|
|||
* Return value:
|
||||
* number of bytes printed to buffer
|
||||
**/
|
||||
static ssize_t ipr_read_dump(struct kobject *kobj,
|
||||
static ssize_t ipr_read_dump(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -3927,6 +3929,7 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg)
|
|||
|
||||
/**
|
||||
* ipr_write_dump - Setup dump state of adapter
|
||||
* @filp: open sysfs file
|
||||
* @kobj: kobject struct
|
||||
* @bin_attr: bin_attribute struct
|
||||
* @buf: buffer
|
||||
|
@ -3936,7 +3939,7 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg)
|
|||
* Return value:
|
||||
* number of bytes printed to buffer
|
||||
**/
|
||||
static ssize_t ipr_write_dump(struct kobject *kobj,
|
||||
static ssize_t ipr_write_dump(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
|
|
@ -2643,6 +2643,7 @@ static DEVICE_ATTR(lpfc_stat_data_ctrl, S_IRUGO | S_IWUSR,
|
|||
|
||||
/**
|
||||
* sysfs_drvr_stat_data_read - Read function for lpfc_drvr_stat_data attribute
|
||||
* @filp: sysfs file
|
||||
* @kobj: Pointer to the kernel object
|
||||
* @bin_attr: Attribute object
|
||||
* @buff: Buffer pointer
|
||||
|
@ -2654,7 +2655,8 @@ static DEVICE_ATTR(lpfc_stat_data_ctrl, S_IRUGO | S_IWUSR,
|
|||
* applications.
|
||||
**/
|
||||
static ssize_t
|
||||
sysfs_drvr_stat_data_read(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
sysfs_drvr_stat_data_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device,
|
||||
|
@ -3362,6 +3364,7 @@ struct device_attribute *lpfc_vport_attrs[] = {
|
|||
|
||||
/**
|
||||
* sysfs_ctlreg_write - Write method for writing to ctlreg
|
||||
* @filp: open sysfs file
|
||||
* @kobj: kernel kobject that contains the kernel class device.
|
||||
* @bin_attr: kernel attributes passed to us.
|
||||
* @buf: contains the data to be written to the adapter IOREG space.
|
||||
|
@ -3379,7 +3382,8 @@ struct device_attribute *lpfc_vport_attrs[] = {
|
|||
* value of count, buf contents written
|
||||
**/
|
||||
static ssize_t
|
||||
sysfs_ctlreg_write(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
sysfs_ctlreg_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
size_t buf_off;
|
||||
|
@ -3415,6 +3419,7 @@ sysfs_ctlreg_write(struct kobject *kobj, struct bin_attribute *bin_attr,
|
|||
|
||||
/**
|
||||
* sysfs_ctlreg_read - Read method for reading from ctlreg
|
||||
* @filp: open sysfs file
|
||||
* @kobj: kernel kobject that contains the kernel class device.
|
||||
* @bin_attr: kernel attributes passed to us.
|
||||
* @buf: if successful contains the data from the adapter IOREG space.
|
||||
|
@ -3431,7 +3436,8 @@ sysfs_ctlreg_write(struct kobject *kobj, struct bin_attribute *bin_attr,
|
|||
* value of count, buf contents read
|
||||
**/
|
||||
static ssize_t
|
||||
sysfs_ctlreg_read(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
sysfs_ctlreg_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
size_t buf_off;
|
||||
|
@ -3496,6 +3502,7 @@ sysfs_mbox_idle(struct lpfc_hba *phba)
|
|||
|
||||
/**
|
||||
* sysfs_mbox_write - Write method for writing information via mbox
|
||||
* @filp: open sysfs file
|
||||
* @kobj: kernel kobject that contains the kernel class device.
|
||||
* @bin_attr: kernel attributes passed to us.
|
||||
* @buf: contains the data to be written to sysfs mbox.
|
||||
|
@ -3516,7 +3523,8 @@ sysfs_mbox_idle(struct lpfc_hba *phba)
|
|||
* count number of bytes transferred
|
||||
**/
|
||||
static ssize_t
|
||||
sysfs_mbox_write(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
sysfs_mbox_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
|
@ -3571,6 +3579,7 @@ sysfs_mbox_write(struct kobject *kobj, struct bin_attribute *bin_attr,
|
|||
|
||||
/**
|
||||
* sysfs_mbox_read - Read method for reading information via mbox
|
||||
* @filp: open sysfs file
|
||||
* @kobj: kernel kobject that contains the kernel class device.
|
||||
* @bin_attr: kernel attributes passed to us.
|
||||
* @buf: contains the data to be read from sysfs mbox.
|
||||
|
@ -3593,7 +3602,8 @@ sysfs_mbox_write(struct kobject *kobj, struct bin_attribute *bin_attr,
|
|||
* count number of bytes transferred
|
||||
**/
|
||||
static ssize_t
|
||||
sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
sysfs_mbox_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
|
|
|
@ -16,7 +16,7 @@ static int qla24xx_vport_disable(struct fc_vport *, bool);
|
|||
/* SYSFS attributes --------------------------------------------------------- */
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_read_fw_dump(struct kobject *kobj,
|
||||
qla2x00_sysfs_read_fw_dump(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -32,7 +32,7 @@ qla2x00_sysfs_read_fw_dump(struct kobject *kobj,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_write_fw_dump(struct kobject *kobj,
|
||||
qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -92,7 +92,7 @@ static struct bin_attribute sysfs_fw_dump_attr = {
|
|||
};
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_read_nvram(struct kobject *kobj,
|
||||
qla2x00_sysfs_read_nvram(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -111,7 +111,7 @@ qla2x00_sysfs_read_nvram(struct kobject *kobj,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_write_nvram(struct kobject *kobj,
|
||||
qla2x00_sysfs_write_nvram(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -177,7 +177,7 @@ static struct bin_attribute sysfs_nvram_attr = {
|
|||
};
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_read_optrom(struct kobject *kobj,
|
||||
qla2x00_sysfs_read_optrom(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -193,7 +193,7 @@ qla2x00_sysfs_read_optrom(struct kobject *kobj,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_write_optrom(struct kobject *kobj,
|
||||
qla2x00_sysfs_write_optrom(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -224,7 +224,7 @@ static struct bin_attribute sysfs_optrom_attr = {
|
|||
};
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,
|
||||
qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -387,7 +387,7 @@ static struct bin_attribute sysfs_optrom_ctl_attr = {
|
|||
};
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_read_vpd(struct kobject *kobj,
|
||||
qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -408,7 +408,7 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_write_vpd(struct kobject *kobj,
|
||||
qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -461,7 +461,7 @@ static struct bin_attribute sysfs_vpd_attr = {
|
|||
};
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_read_sfp(struct kobject *kobj,
|
||||
qla2x00_sysfs_read_sfp(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -522,7 +522,7 @@ static struct bin_attribute sysfs_sfp_attr = {
|
|||
};
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_write_reset(struct kobject *kobj,
|
||||
qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -592,7 +592,7 @@ static struct bin_attribute sysfs_reset_attr = {
|
|||
};
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_write_edc(struct kobject *kobj,
|
||||
qla2x00_sysfs_write_edc(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -650,7 +650,7 @@ static struct bin_attribute sysfs_edc_attr = {
|
|||
};
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_write_edc_status(struct kobject *kobj,
|
||||
qla2x00_sysfs_write_edc_status(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -700,7 +700,7 @@ qla2x00_sysfs_write_edc_status(struct kobject *kobj,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_read_edc_status(struct kobject *kobj,
|
||||
qla2x00_sysfs_read_edc_status(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -730,7 +730,7 @@ static struct bin_attribute sysfs_edc_status_attr = {
|
|||
};
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_read_xgmac_stats(struct kobject *kobj,
|
||||
qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -782,7 +782,7 @@ static struct bin_attribute sysfs_xgmac_stats_attr = {
|
|||
};
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_read_dcbx_tlv(struct kobject *kobj,
|
||||
qla2x00_sysfs_read_dcbx_tlv(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
|
|
@ -48,6 +48,7 @@ Devices: [Quatech] DAQP-208 (daqp), DAQP-308
|
|||
*/
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include <linux/semaphore.h>
|
||||
|
||||
#include <pcmcia/cs_types.h>
|
||||
#include <pcmcia/cs.h>
|
||||
|
|
|
@ -1063,7 +1063,8 @@ static ssize_t metrics_misc_show(struct device *fbdev,
|
|||
atomic_read(&dev->lost_pixels) ? "yes" : "no");
|
||||
}
|
||||
|
||||
static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *a,
|
||||
static ssize_t edid_show(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *a,
|
||||
char *buf, loff_t off, size_t count) {
|
||||
struct device *fbdev = container_of(kobj, struct device, kobj);
|
||||
struct fb_info *fb_info = dev_get_drvdata(fbdev);
|
||||
|
|
|
@ -658,7 +658,8 @@ const struct attribute_group *usb_device_groups[] = {
|
|||
/* Binary descriptors */
|
||||
|
||||
static ssize_t
|
||||
read_descriptors(struct kobject *kobj, struct bin_attribute *attr,
|
||||
read_descriptors(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
|
|
|
@ -573,7 +573,7 @@ int usb_lock_device_for_reset(struct usb_device *udev,
|
|||
iface->condition == USB_INTERFACE_UNBOUND))
|
||||
return -EINTR;
|
||||
|
||||
while (usb_trylock_device(udev) != 0) {
|
||||
while (!usb_trylock_device(udev)) {
|
||||
|
||||
/* If we can't acquire the lock after waiting one second,
|
||||
* we're probably deadlocked */
|
||||
|
|
|
@ -2099,7 +2099,7 @@ static ssize_t radeon_show_one_edid(char *buf, loff_t off, size_t count, const u
|
|||
}
|
||||
|
||||
|
||||
static ssize_t radeon_show_edid1(struct kobject *kobj,
|
||||
static ssize_t radeon_show_edid1(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -2112,7 +2112,7 @@ static ssize_t radeon_show_edid1(struct kobject *kobj,
|
|||
}
|
||||
|
||||
|
||||
static ssize_t radeon_show_edid2(struct kobject *kobj,
|
||||
static ssize_t radeon_show_edid2(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
|
|
@ -96,7 +96,7 @@ static int w1_f2d_readblock(struct w1_slave *sl, int off, int count, char *buf)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static ssize_t w1_f2d_read_bin(struct kobject *kobj,
|
||||
static ssize_t w1_f2d_read_bin(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -202,7 +202,7 @@ retry:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t w1_f2d_write_bin(struct kobject *kobj,
|
||||
static ssize_t w1_f2d_write_bin(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
|
|
@ -92,7 +92,7 @@ static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data,
|
|||
}
|
||||
#endif /* CONFIG_W1_SLAVE_DS2433_CRC */
|
||||
|
||||
static ssize_t w1_f23_read_bin(struct kobject *kobj,
|
||||
static ssize_t w1_f23_read_bin(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -206,7 +206,7 @@ static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t w1_f23_write_bin(struct kobject *kobj,
|
||||
static ssize_t w1_f23_write_bin(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
|
|
@ -97,7 +97,7 @@ int w1_ds2760_recall_eeprom(struct device *dev, int addr)
|
|||
return w1_ds2760_eeprom_cmd(dev, addr, W1_DS2760_RECALL_DATA);
|
||||
}
|
||||
|
||||
static ssize_t w1_ds2760_read_bin(struct kobject *kobj,
|
||||
static ssize_t w1_ds2760_read_bin(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
|
|
@ -120,7 +120,7 @@ static struct device_attribute w1_slave_attr_id =
|
|||
|
||||
/* Default family */
|
||||
|
||||
static ssize_t w1_default_write(struct kobject *kobj,
|
||||
static ssize_t w1_default_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
@ -139,7 +139,7 @@ out_up:
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t w1_default_read(struct kobject *kobj,
|
||||
static ssize_t w1_default_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
|
|
@ -49,7 +49,7 @@ static ssize_t zorro_show_resource(struct device *dev, struct device_attribute *
|
|||
|
||||
static DEVICE_ATTR(resource, S_IRUGO, zorro_show_resource, NULL);
|
||||
|
||||
static ssize_t zorro_read_config(struct kobject *kobj,
|
||||
static ssize_t zorro_read_config(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
|
|
@ -214,7 +214,7 @@ static int ramfs_parse_options(char *data, struct ramfs_mount_opts *opts)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ramfs_fill_super(struct super_block * sb, void * data, int silent)
|
||||
int ramfs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
{
|
||||
struct ramfs_fs_info *fsi;
|
||||
struct inode *inode = NULL;
|
||||
|
|
|
@ -46,9 +46,9 @@ struct bin_buffer {
|
|||
};
|
||||
|
||||
static int
|
||||
fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)
|
||||
fill_read(struct file *file, char *buffer, loff_t off, size_t count)
|
||||
{
|
||||
struct sysfs_dirent *attr_sd = dentry->d_fsdata;
|
||||
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
|
||||
struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
|
||||
struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
|
||||
int rc;
|
||||
|
@ -59,7 +59,7 @@ fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)
|
|||
|
||||
rc = -EIO;
|
||||
if (attr->read)
|
||||
rc = attr->read(kobj, attr, buffer, off, count);
|
||||
rc = attr->read(file, kobj, attr, buffer, off, count);
|
||||
|
||||
sysfs_put_active(attr_sd);
|
||||
|
||||
|
@ -70,8 +70,7 @@ static ssize_t
|
|||
read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off)
|
||||
{
|
||||
struct bin_buffer *bb = file->private_data;
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
int size = dentry->d_inode->i_size;
|
||||
int size = file->f_path.dentry->d_inode->i_size;
|
||||
loff_t offs = *off;
|
||||
int count = min_t(size_t, bytes, PAGE_SIZE);
|
||||
char *temp;
|
||||
|
@ -92,7 +91,7 @@ read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off)
|
|||
|
||||
mutex_lock(&bb->mutex);
|
||||
|
||||
count = fill_read(dentry, bb->buffer, offs, count);
|
||||
count = fill_read(file, bb->buffer, offs, count);
|
||||
if (count < 0) {
|
||||
mutex_unlock(&bb->mutex);
|
||||
goto out_free;
|
||||
|
@ -117,9 +116,9 @@ read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off)
|
|||
}
|
||||
|
||||
static int
|
||||
flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)
|
||||
flush_write(struct file *file, char *buffer, loff_t offset, size_t count)
|
||||
{
|
||||
struct sysfs_dirent *attr_sd = dentry->d_fsdata;
|
||||
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
|
||||
struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
|
||||
struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
|
||||
int rc;
|
||||
|
@ -130,7 +129,7 @@ flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)
|
|||
|
||||
rc = -EIO;
|
||||
if (attr->write)
|
||||
rc = attr->write(kobj, attr, buffer, offset, count);
|
||||
rc = attr->write(file, kobj, attr, buffer, offset, count);
|
||||
|
||||
sysfs_put_active(attr_sd);
|
||||
|
||||
|
@ -141,8 +140,7 @@ static ssize_t write(struct file *file, const char __user *userbuf,
|
|||
size_t bytes, loff_t *off)
|
||||
{
|
||||
struct bin_buffer *bb = file->private_data;
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
int size = dentry->d_inode->i_size;
|
||||
int size = file->f_path.dentry->d_inode->i_size;
|
||||
loff_t offs = *off;
|
||||
int count = min_t(size_t, bytes, PAGE_SIZE);
|
||||
char *temp;
|
||||
|
@ -165,7 +163,7 @@ static ssize_t write(struct file *file, const char __user *userbuf,
|
|||
|
||||
memcpy(bb->buffer, temp, count);
|
||||
|
||||
count = flush_write(dentry, bb->buffer, offs, count);
|
||||
count = flush_write(file, bb->buffer, offs, count);
|
||||
mutex_unlock(&bb->mutex);
|
||||
|
||||
if (count > 0)
|
||||
|
@ -363,7 +361,7 @@ static int mmap(struct file *file, struct vm_area_struct *vma)
|
|||
if (!attr->mmap)
|
||||
goto out_put;
|
||||
|
||||
rc = attr->mmap(kobj, attr, vma);
|
||||
rc = attr->mmap(file, kobj, attr, vma);
|
||||
if (rc)
|
||||
goto out_put;
|
||||
|
||||
|
@ -501,7 +499,7 @@ int sysfs_create_bin_file(struct kobject *kobj,
|
|||
void sysfs_remove_bin_file(struct kobject *kobj,
|
||||
const struct bin_attribute *attr)
|
||||
{
|
||||
sysfs_hash_and_remove(kobj->sd, attr->attr.name);
|
||||
sysfs_hash_and_remove(kobj->sd, NULL, attr->attr.name);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
|
||||
|
|
114
fs/sysfs/dir.c
114
fs/sysfs/dir.c
|
@ -380,7 +380,7 @@ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
|
|||
{
|
||||
struct sysfs_inode_attrs *ps_iattr;
|
||||
|
||||
if (sysfs_find_dirent(acxt->parent_sd, sd->s_name))
|
||||
if (sysfs_find_dirent(acxt->parent_sd, sd->s_ns, sd->s_name))
|
||||
return -EEXIST;
|
||||
|
||||
sd->s_parent = sysfs_get(acxt->parent_sd);
|
||||
|
@ -533,13 +533,17 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
|
|||
* Pointer to sysfs_dirent if found, NULL if not.
|
||||
*/
|
||||
struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
|
||||
const void *ns,
|
||||
const unsigned char *name)
|
||||
{
|
||||
struct sysfs_dirent *sd;
|
||||
|
||||
for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling)
|
||||
for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling) {
|
||||
if (ns && sd->s_ns && (sd->s_ns != ns))
|
||||
continue;
|
||||
if (!strcmp(sd->s_name, name))
|
||||
return sd;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -558,12 +562,13 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
|
|||
* Pointer to sysfs_dirent if found, NULL if not.
|
||||
*/
|
||||
struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
|
||||
const void *ns,
|
||||
const unsigned char *name)
|
||||
{
|
||||
struct sysfs_dirent *sd;
|
||||
|
||||
mutex_lock(&sysfs_mutex);
|
||||
sd = sysfs_find_dirent(parent_sd, name);
|
||||
sd = sysfs_find_dirent(parent_sd, ns, name);
|
||||
sysfs_get(sd);
|
||||
mutex_unlock(&sysfs_mutex);
|
||||
|
||||
|
@ -572,7 +577,8 @@ struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
|
|||
EXPORT_SYMBOL_GPL(sysfs_get_dirent);
|
||||
|
||||
static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
|
||||
const char *name, struct sysfs_dirent **p_sd)
|
||||
enum kobj_ns_type type, const void *ns, const char *name,
|
||||
struct sysfs_dirent **p_sd)
|
||||
{
|
||||
umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
|
||||
struct sysfs_addrm_cxt acxt;
|
||||
|
@ -583,6 +589,9 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
|
|||
sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
|
||||
if (!sd)
|
||||
return -ENOMEM;
|
||||
|
||||
sd->s_flags |= (type << SYSFS_NS_TYPE_SHIFT);
|
||||
sd->s_ns = ns;
|
||||
sd->s_dir.kobj = kobj;
|
||||
|
||||
/* link in */
|
||||
|
@ -601,7 +610,33 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
|
|||
int sysfs_create_subdir(struct kobject *kobj, const char *name,
|
||||
struct sysfs_dirent **p_sd)
|
||||
{
|
||||
return create_dir(kobj, kobj->sd, name, p_sd);
|
||||
return create_dir(kobj, kobj->sd,
|
||||
KOBJ_NS_TYPE_NONE, NULL, name, p_sd);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_read_ns_type: return associated ns_type
|
||||
* @kobj: the kobject being queried
|
||||
*
|
||||
* Each kobject can be tagged with exactly one namespace type
|
||||
* (i.e. network or user). Return the ns_type associated with
|
||||
* this object if any
|
||||
*/
|
||||
static enum kobj_ns_type sysfs_read_ns_type(struct kobject *kobj)
|
||||
{
|
||||
const struct kobj_ns_type_operations *ops;
|
||||
enum kobj_ns_type type;
|
||||
|
||||
ops = kobj_child_ns_ops(kobj);
|
||||
if (!ops)
|
||||
return KOBJ_NS_TYPE_NONE;
|
||||
|
||||
type = ops->type;
|
||||
BUG_ON(type <= KOBJ_NS_TYPE_NONE);
|
||||
BUG_ON(type >= KOBJ_NS_TYPES);
|
||||
BUG_ON(!kobj_ns_type_registered(type));
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -610,7 +645,9 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name,
|
|||
*/
|
||||
int sysfs_create_dir(struct kobject * kobj)
|
||||
{
|
||||
enum kobj_ns_type type;
|
||||
struct sysfs_dirent *parent_sd, *sd;
|
||||
const void *ns = NULL;
|
||||
int error = 0;
|
||||
|
||||
BUG_ON(!kobj);
|
||||
|
@ -620,7 +657,11 @@ int sysfs_create_dir(struct kobject * kobj)
|
|||
else
|
||||
parent_sd = &sysfs_root;
|
||||
|
||||
error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);
|
||||
if (sysfs_ns_type(parent_sd))
|
||||
ns = kobj->ktype->namespace(kobj);
|
||||
type = sysfs_read_ns_type(kobj);
|
||||
|
||||
error = create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd);
|
||||
if (!error)
|
||||
kobj->sd = sd;
|
||||
return error;
|
||||
|
@ -630,13 +671,19 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
|
|||
struct nameidata *nd)
|
||||
{
|
||||
struct dentry *ret = NULL;
|
||||
struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata;
|
||||
struct dentry *parent = dentry->d_parent;
|
||||
struct sysfs_dirent *parent_sd = parent->d_fsdata;
|
||||
struct sysfs_dirent *sd;
|
||||
struct inode *inode;
|
||||
enum kobj_ns_type type;
|
||||
const void *ns;
|
||||
|
||||
mutex_lock(&sysfs_mutex);
|
||||
|
||||
sd = sysfs_find_dirent(parent_sd, dentry->d_name.name);
|
||||
type = sysfs_ns_type(parent_sd);
|
||||
ns = sysfs_info(dir->i_sb)->ns[type];
|
||||
|
||||
sd = sysfs_find_dirent(parent_sd, ns, dentry->d_name.name);
|
||||
|
||||
/* no such entry */
|
||||
if (!sd) {
|
||||
|
@ -735,7 +782,8 @@ void sysfs_remove_dir(struct kobject * kobj)
|
|||
}
|
||||
|
||||
int sysfs_rename(struct sysfs_dirent *sd,
|
||||
struct sysfs_dirent *new_parent_sd, const char *new_name)
|
||||
struct sysfs_dirent *new_parent_sd, const void *new_ns,
|
||||
const char *new_name)
|
||||
{
|
||||
const char *dup_name = NULL;
|
||||
int error;
|
||||
|
@ -743,12 +791,12 @@ int sysfs_rename(struct sysfs_dirent *sd,
|
|||
mutex_lock(&sysfs_mutex);
|
||||
|
||||
error = 0;
|
||||
if ((sd->s_parent == new_parent_sd) &&
|
||||
if ((sd->s_parent == new_parent_sd) && (sd->s_ns == new_ns) &&
|
||||
(strcmp(sd->s_name, new_name) == 0))
|
||||
goto out; /* nothing to rename */
|
||||
|
||||
error = -EEXIST;
|
||||
if (sysfs_find_dirent(new_parent_sd, new_name))
|
||||
if (sysfs_find_dirent(new_parent_sd, new_ns, new_name))
|
||||
goto out;
|
||||
|
||||
/* rename sysfs_dirent */
|
||||
|
@ -770,6 +818,7 @@ int sysfs_rename(struct sysfs_dirent *sd,
|
|||
sd->s_parent = new_parent_sd;
|
||||
sysfs_link_sibling(sd);
|
||||
}
|
||||
sd->s_ns = new_ns;
|
||||
|
||||
error = 0;
|
||||
out:
|
||||
|
@ -780,19 +829,28 @@ int sysfs_rename(struct sysfs_dirent *sd,
|
|||
|
||||
int sysfs_rename_dir(struct kobject *kobj, const char *new_name)
|
||||
{
|
||||
return sysfs_rename(kobj->sd, kobj->sd->s_parent, new_name);
|
||||
struct sysfs_dirent *parent_sd = kobj->sd->s_parent;
|
||||
const void *new_ns = NULL;
|
||||
|
||||
if (sysfs_ns_type(parent_sd))
|
||||
new_ns = kobj->ktype->namespace(kobj);
|
||||
|
||||
return sysfs_rename(kobj->sd, parent_sd, new_ns, new_name);
|
||||
}
|
||||
|
||||
int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj)
|
||||
{
|
||||
struct sysfs_dirent *sd = kobj->sd;
|
||||
struct sysfs_dirent *new_parent_sd;
|
||||
const void *new_ns = NULL;
|
||||
|
||||
BUG_ON(!sd->s_parent);
|
||||
if (sysfs_ns_type(sd->s_parent))
|
||||
new_ns = kobj->ktype->namespace(kobj);
|
||||
new_parent_sd = new_parent_kobj && new_parent_kobj->sd ?
|
||||
new_parent_kobj->sd : &sysfs_root;
|
||||
|
||||
return sysfs_rename(sd, new_parent_sd, sd->s_name);
|
||||
return sysfs_rename(sd, new_parent_sd, new_ns, sd->s_name);
|
||||
}
|
||||
|
||||
/* Relationship between s_mode and the DT_xxx types */
|
||||
|
@ -807,32 +865,35 @@ static int sysfs_dir_release(struct inode *inode, struct file *filp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct sysfs_dirent *sysfs_dir_pos(struct sysfs_dirent *parent_sd,
|
||||
ino_t ino, struct sysfs_dirent *pos)
|
||||
static struct sysfs_dirent *sysfs_dir_pos(const void *ns,
|
||||
struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos)
|
||||
{
|
||||
if (pos) {
|
||||
int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) &&
|
||||
pos->s_parent == parent_sd &&
|
||||
ino == pos->s_ino;
|
||||
sysfs_put(pos);
|
||||
if (valid)
|
||||
return pos;
|
||||
}
|
||||
if (!valid)
|
||||
pos = NULL;
|
||||
if ((ino > 1) && (ino < INT_MAX)) {
|
||||
}
|
||||
if (!pos && (ino > 1) && (ino < INT_MAX)) {
|
||||
pos = parent_sd->s_dir.children;
|
||||
while (pos && (ino > pos->s_ino))
|
||||
pos = pos->s_sibling;
|
||||
}
|
||||
while (pos && pos->s_ns && pos->s_ns != ns)
|
||||
pos = pos->s_sibling;
|
||||
return pos;
|
||||
}
|
||||
|
||||
static struct sysfs_dirent *sysfs_dir_next_pos(struct sysfs_dirent *parent_sd,
|
||||
ino_t ino, struct sysfs_dirent *pos)
|
||||
static struct sysfs_dirent *sysfs_dir_next_pos(const void *ns,
|
||||
struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos)
|
||||
{
|
||||
pos = sysfs_dir_pos(parent_sd, ino, pos);
|
||||
pos = sysfs_dir_pos(ns, parent_sd, ino, pos);
|
||||
if (pos)
|
||||
pos = pos->s_sibling;
|
||||
while (pos && pos->s_ns && pos->s_ns != ns)
|
||||
pos = pos->s_sibling;
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
@ -841,8 +902,13 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
|
|||
struct dentry *dentry = filp->f_path.dentry;
|
||||
struct sysfs_dirent * parent_sd = dentry->d_fsdata;
|
||||
struct sysfs_dirent *pos = filp->private_data;
|
||||
enum kobj_ns_type type;
|
||||
const void *ns;
|
||||
ino_t ino;
|
||||
|
||||
type = sysfs_ns_type(parent_sd);
|
||||
ns = sysfs_info(dentry->d_sb)->ns[type];
|
||||
|
||||
if (filp->f_pos == 0) {
|
||||
ino = parent_sd->s_ino;
|
||||
if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0)
|
||||
|
@ -857,9 +923,9 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
|
|||
filp->f_pos++;
|
||||
}
|
||||
mutex_lock(&sysfs_mutex);
|
||||
for (pos = sysfs_dir_pos(parent_sd, filp->f_pos, pos);
|
||||
for (pos = sysfs_dir_pos(ns, parent_sd, filp->f_pos, pos);
|
||||
pos;
|
||||
pos = sysfs_dir_next_pos(parent_sd, filp->f_pos, pos)) {
|
||||
pos = sysfs_dir_next_pos(ns, parent_sd, filp->f_pos, pos)) {
|
||||
const char * name;
|
||||
unsigned int type;
|
||||
int len, ret;
|
||||
|
|
|
@ -478,9 +478,12 @@ void sysfs_notify(struct kobject *k, const char *dir, const char *attr)
|
|||
mutex_lock(&sysfs_mutex);
|
||||
|
||||
if (sd && dir)
|
||||
sd = sysfs_find_dirent(sd, dir);
|
||||
/* Only directories are tagged, so no need to pass
|
||||
* a tag explicitly.
|
||||
*/
|
||||
sd = sysfs_find_dirent(sd, NULL, dir);
|
||||
if (sd && attr)
|
||||
sd = sysfs_find_dirent(sd, attr);
|
||||
sd = sysfs_find_dirent(sd, NULL, attr);
|
||||
if (sd)
|
||||
sysfs_notify_dirent(sd);
|
||||
|
||||
|
@ -569,7 +572,7 @@ int sysfs_add_file_to_group(struct kobject *kobj,
|
|||
int error;
|
||||
|
||||
if (group)
|
||||
dir_sd = sysfs_get_dirent(kobj->sd, group);
|
||||
dir_sd = sysfs_get_dirent(kobj->sd, NULL, group);
|
||||
else
|
||||
dir_sd = sysfs_get(kobj->sd);
|
||||
|
||||
|
@ -599,7 +602,7 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
|
|||
mutex_lock(&sysfs_mutex);
|
||||
|
||||
rc = -ENOENT;
|
||||
sd = sysfs_find_dirent(kobj->sd, attr->name);
|
||||
sd = sysfs_find_dirent(kobj->sd, NULL, attr->name);
|
||||
if (!sd)
|
||||
goto out;
|
||||
|
||||
|
@ -624,7 +627,7 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file);
|
|||
|
||||
void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
|
||||
{
|
||||
sysfs_hash_and_remove(kobj->sd, attr->name);
|
||||
sysfs_hash_and_remove(kobj->sd, NULL, attr->name);
|
||||
}
|
||||
|
||||
void sysfs_remove_files(struct kobject * kobj, const struct attribute **ptr)
|
||||
|
@ -646,11 +649,11 @@ void sysfs_remove_file_from_group(struct kobject *kobj,
|
|||
struct sysfs_dirent *dir_sd;
|
||||
|
||||
if (group)
|
||||
dir_sd = sysfs_get_dirent(kobj->sd, group);
|
||||
dir_sd = sysfs_get_dirent(kobj->sd, NULL, group);
|
||||
else
|
||||
dir_sd = sysfs_get(kobj->sd);
|
||||
if (dir_sd) {
|
||||
sysfs_hash_and_remove(dir_sd, attr->name);
|
||||
sysfs_hash_and_remove(dir_sd, NULL, attr->name);
|
||||
sysfs_put(dir_sd);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
|
|||
int i;
|
||||
|
||||
for (i = 0, attr = grp->attrs; *attr; i++, attr++)
|
||||
sysfs_hash_and_remove(dir_sd, (*attr)->name);
|
||||
sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name);
|
||||
}
|
||||
|
||||
static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
|
||||
|
@ -39,7 +39,7 @@ static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
|
|||
* visibility. Do this by first removing then
|
||||
* re-adding (if required) the file */
|
||||
if (update)
|
||||
sysfs_hash_and_remove(dir_sd, (*attr)->name);
|
||||
sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name);
|
||||
if (grp->is_visible) {
|
||||
mode = grp->is_visible(kobj, *attr, i);
|
||||
if (!mode)
|
||||
|
@ -132,7 +132,7 @@ void sysfs_remove_group(struct kobject * kobj,
|
|||
struct sysfs_dirent *sd;
|
||||
|
||||
if (grp->name) {
|
||||
sd = sysfs_get_dirent(dir_sd, grp->name);
|
||||
sd = sysfs_get_dirent(dir_sd, NULL, grp->name);
|
||||
if (!sd) {
|
||||
WARN(!sd, KERN_WARNING "sysfs group %p not found for "
|
||||
"kobject '%s'\n", grp, kobject_name(kobj));
|
||||
|
|
|
@ -324,7 +324,7 @@ void sysfs_delete_inode(struct inode *inode)
|
|||
sysfs_put(sd);
|
||||
}
|
||||
|
||||
int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
|
||||
int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const char *name)
|
||||
{
|
||||
struct sysfs_addrm_cxt acxt;
|
||||
struct sysfs_dirent *sd;
|
||||
|
@ -334,7 +334,9 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
|
|||
|
||||
sysfs_addrm_start(&acxt, dir_sd);
|
||||
|
||||
sd = sysfs_find_dirent(dir_sd, name);
|
||||
sd = sysfs_find_dirent(dir_sd, ns, name);
|
||||
if (sd && (sd->s_ns != ns))
|
||||
sd = NULL;
|
||||
if (sd)
|
||||
sysfs_remove_one(&acxt, sd);
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ static const struct super_operations sysfs_ops = {
|
|||
struct sysfs_dirent sysfs_root = {
|
||||
.s_name = "",
|
||||
.s_count = ATOMIC_INIT(1),
|
||||
.s_flags = SYSFS_DIR,
|
||||
.s_flags = SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT),
|
||||
.s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
|
||||
.s_ino = 1,
|
||||
};
|
||||
|
@ -72,18 +72,107 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sysfs_test_super(struct super_block *sb, void *data)
|
||||
{
|
||||
struct sysfs_super_info *sb_info = sysfs_info(sb);
|
||||
struct sysfs_super_info *info = data;
|
||||
enum kobj_ns_type type;
|
||||
int found = 1;
|
||||
|
||||
for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) {
|
||||
if (sb_info->ns[type] != info->ns[type])
|
||||
found = 0;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
static int sysfs_set_super(struct super_block *sb, void *data)
|
||||
{
|
||||
int error;
|
||||
error = set_anon_super(sb, data);
|
||||
if (!error)
|
||||
sb->s_fs_info = data;
|
||||
return error;
|
||||
}
|
||||
|
||||
static int sysfs_get_sb(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *data, struct vfsmount *mnt)
|
||||
{
|
||||
return get_sb_single(fs_type, flags, data, sysfs_fill_super, mnt);
|
||||
struct sysfs_super_info *info;
|
||||
enum kobj_ns_type type;
|
||||
struct super_block *sb;
|
||||
int error;
|
||||
|
||||
error = -ENOMEM;
|
||||
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
goto out;
|
||||
|
||||
for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++)
|
||||
info->ns[type] = kobj_ns_current(type);
|
||||
|
||||
sb = sget(fs_type, sysfs_test_super, sysfs_set_super, info);
|
||||
if (IS_ERR(sb) || sb->s_fs_info != info)
|
||||
kfree(info);
|
||||
if (IS_ERR(sb)) {
|
||||
error = PTR_ERR(sb);
|
||||
goto out;
|
||||
}
|
||||
if (!sb->s_root) {
|
||||
sb->s_flags = flags;
|
||||
error = sysfs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
|
||||
if (error) {
|
||||
deactivate_locked_super(sb);
|
||||
goto out;
|
||||
}
|
||||
sb->s_flags |= MS_ACTIVE;
|
||||
}
|
||||
|
||||
simple_set_mnt(mnt, sb);
|
||||
error = 0;
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
static void sysfs_kill_sb(struct super_block *sb)
|
||||
{
|
||||
struct sysfs_super_info *info = sysfs_info(sb);
|
||||
|
||||
/* Remove the superblock from fs_supers/s_instances
|
||||
* so we can't find it, before freeing sysfs_super_info.
|
||||
*/
|
||||
kill_anon_super(sb);
|
||||
kfree(info);
|
||||
}
|
||||
|
||||
static struct file_system_type sysfs_fs_type = {
|
||||
.name = "sysfs",
|
||||
.get_sb = sysfs_get_sb,
|
||||
.kill_sb = kill_anon_super,
|
||||
.kill_sb = sysfs_kill_sb,
|
||||
};
|
||||
|
||||
void sysfs_exit_ns(enum kobj_ns_type type, const void *ns)
|
||||
{
|
||||
struct super_block *sb;
|
||||
|
||||
mutex_lock(&sysfs_mutex);
|
||||
spin_lock(&sb_lock);
|
||||
list_for_each_entry(sb, &sysfs_fs_type.fs_supers, s_instances) {
|
||||
struct sysfs_super_info *info = sysfs_info(sb);
|
||||
/*
|
||||
* If we see a superblock on the fs_supers/s_instances
|
||||
* list the unmount has not completed and sb->s_fs_info
|
||||
* points to a valid struct sysfs_super_info.
|
||||
*/
|
||||
/* Ignore superblocks with the wrong ns */
|
||||
if (info->ns[type] != ns)
|
||||
continue;
|
||||
info->ns[type] = NULL;
|
||||
}
|
||||
spin_unlock(&sb_lock);
|
||||
mutex_unlock(&sysfs_mutex);
|
||||
}
|
||||
|
||||
int __init sysfs_init(void)
|
||||
{
|
||||
int err = -ENOMEM;
|
||||
|
|
|
@ -58,6 +58,8 @@ static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,
|
|||
if (!sd)
|
||||
goto out_put;
|
||||
|
||||
if (sysfs_ns_type(parent_sd))
|
||||
sd->s_ns = target->ktype->namespace(target);
|
||||
sd->s_symlink.target_sd = target_sd;
|
||||
target_sd = NULL; /* reference is now owned by the symlink */
|
||||
|
||||
|
@ -106,6 +108,26 @@ int sysfs_create_link_nowarn(struct kobject *kobj, struct kobject *target,
|
|||
return sysfs_do_create_link(kobj, target, name, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_delete_link - remove symlink in object's directory.
|
||||
* @kobj: object we're acting for.
|
||||
* @targ: object we're pointing to.
|
||||
* @name: name of the symlink to remove.
|
||||
*
|
||||
* Unlike sysfs_remove_link sysfs_delete_link has enough information
|
||||
* to successfully delete symlinks in tagged directories.
|
||||
*/
|
||||
void sysfs_delete_link(struct kobject *kobj, struct kobject *targ,
|
||||
const char *name)
|
||||
{
|
||||
const void *ns = NULL;
|
||||
spin_lock(&sysfs_assoc_lock);
|
||||
if (targ->sd)
|
||||
ns = targ->sd->s_ns;
|
||||
spin_unlock(&sysfs_assoc_lock);
|
||||
sysfs_hash_and_remove(kobj->sd, ns, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_remove_link - remove symlink in object's directory.
|
||||
* @kobj: object we're acting for.
|
||||
|
@ -121,7 +143,7 @@ void sysfs_remove_link(struct kobject * kobj, const char * name)
|
|||
else
|
||||
parent_sd = kobj->sd;
|
||||
|
||||
sysfs_hash_and_remove(parent_sd, name);
|
||||
sysfs_hash_and_remove(parent_sd, NULL, name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -137,6 +159,7 @@ int sysfs_rename_link(struct kobject *kobj, struct kobject *targ,
|
|||
const char *old, const char *new)
|
||||
{
|
||||
struct sysfs_dirent *parent_sd, *sd = NULL;
|
||||
const void *old_ns = NULL, *new_ns = NULL;
|
||||
int result;
|
||||
|
||||
if (!kobj)
|
||||
|
@ -144,8 +167,11 @@ int sysfs_rename_link(struct kobject *kobj, struct kobject *targ,
|
|||
else
|
||||
parent_sd = kobj->sd;
|
||||
|
||||
if (targ->sd)
|
||||
old_ns = targ->sd->s_ns;
|
||||
|
||||
result = -ENOENT;
|
||||
sd = sysfs_get_dirent(parent_sd, old);
|
||||
sd = sysfs_get_dirent(parent_sd, old_ns, old);
|
||||
if (!sd)
|
||||
goto out;
|
||||
|
||||
|
@ -155,7 +181,10 @@ int sysfs_rename_link(struct kobject *kobj, struct kobject *targ,
|
|||
if (sd->s_symlink.target_sd->s_dir.kobj != targ)
|
||||
goto out;
|
||||
|
||||
result = sysfs_rename(sd, parent_sd, new);
|
||||
if (sysfs_ns_type(parent_sd))
|
||||
new_ns = targ->ktype->namespace(targ);
|
||||
|
||||
result = sysfs_rename(sd, parent_sd, new_ns, new);
|
||||
|
||||
out:
|
||||
sysfs_put(sd);
|
||||
|
|
|
@ -58,6 +58,7 @@ struct sysfs_dirent {
|
|||
struct sysfs_dirent *s_sibling;
|
||||
const char *s_name;
|
||||
|
||||
const void *s_ns; /* namespace tag */
|
||||
union {
|
||||
struct sysfs_elem_dir s_dir;
|
||||
struct sysfs_elem_symlink s_symlink;
|
||||
|
@ -81,14 +82,27 @@ struct sysfs_dirent {
|
|||
#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK)
|
||||
#define SYSFS_ACTIVE_REF (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR)
|
||||
|
||||
#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK
|
||||
#define SYSFS_FLAG_REMOVED 0x0200
|
||||
/* identify any namespace tag on sysfs_dirents */
|
||||
#define SYSFS_NS_TYPE_MASK 0xff00
|
||||
#define SYSFS_NS_TYPE_SHIFT 8
|
||||
|
||||
#define SYSFS_FLAG_MASK ~(SYSFS_NS_TYPE_MASK|SYSFS_TYPE_MASK)
|
||||
#define SYSFS_FLAG_REMOVED 0x020000
|
||||
|
||||
static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
|
||||
{
|
||||
return sd->s_flags & SYSFS_TYPE_MASK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return any namespace tags on this dirent.
|
||||
* enum kobj_ns_type is defined in linux/kobject.h
|
||||
*/
|
||||
static inline enum kobj_ns_type sysfs_ns_type(struct sysfs_dirent *sd)
|
||||
{
|
||||
return (sd->s_flags & SYSFS_NS_TYPE_MASK) >> SYSFS_NS_TYPE_SHIFT;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||
#define sysfs_dirent_init_lockdep(sd) \
|
||||
do { \
|
||||
|
@ -114,6 +128,16 @@ struct sysfs_addrm_cxt {
|
|||
/*
|
||||
* mount.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* Each sb is associated with a set of namespace tags (i.e.
|
||||
* the network namespace of the task which mounted this sysfs
|
||||
* instance).
|
||||
*/
|
||||
struct sysfs_super_info {
|
||||
const void *ns[KOBJ_NS_TYPES];
|
||||
};
|
||||
#define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info))
|
||||
extern struct sysfs_dirent sysfs_root;
|
||||
extern struct kmem_cache *sysfs_dir_cachep;
|
||||
|
||||
|
@ -137,8 +161,10 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd);
|
|||
void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt);
|
||||
|
||||
struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
|
||||
const void *ns,
|
||||
const unsigned char *name);
|
||||
struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
|
||||
const void *ns,
|
||||
const unsigned char *name);
|
||||
struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type);
|
||||
|
||||
|
@ -149,7 +175,7 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name,
|
|||
void sysfs_remove_subdir(struct sysfs_dirent *sd);
|
||||
|
||||
int sysfs_rename(struct sysfs_dirent *sd,
|
||||
struct sysfs_dirent *new_parent_sd, const char *new_name);
|
||||
struct sysfs_dirent *new_parent_sd, const void *ns, const char *new_name);
|
||||
|
||||
static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd)
|
||||
{
|
||||
|
@ -179,7 +205,7 @@ int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
|
|||
int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
|
||||
int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value,
|
||||
size_t size, int flags);
|
||||
int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name);
|
||||
int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const char *name);
|
||||
int sysfs_inode_init(void);
|
||||
|
||||
/*
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/device.h>
|
||||
|
||||
|
@ -203,6 +202,9 @@ struct class {
|
|||
int (*suspend)(struct device *dev, pm_message_t state);
|
||||
int (*resume)(struct device *dev);
|
||||
|
||||
const struct kobj_ns_type_operations *ns_type;
|
||||
const void *(*namespace)(struct device *dev);
|
||||
|
||||
const struct dev_pm_ops *pm;
|
||||
|
||||
struct class_private *p;
|
||||
|
@ -404,7 +406,7 @@ struct device {
|
|||
const char *init_name; /* initial name of the device */
|
||||
struct device_type *type;
|
||||
|
||||
struct semaphore sem; /* semaphore to synchronize calls to
|
||||
struct mutex mutex; /* mutex to synchronize calls to
|
||||
* its driver.
|
||||
*/
|
||||
|
||||
|
@ -514,17 +516,17 @@ static inline bool device_async_suspend_enabled(struct device *dev)
|
|||
|
||||
static inline void device_lock(struct device *dev)
|
||||
{
|
||||
down(&dev->sem);
|
||||
mutex_lock(&dev->mutex);
|
||||
}
|
||||
|
||||
static inline int device_trylock(struct device *dev)
|
||||
{
|
||||
return down_trylock(&dev->sem);
|
||||
return mutex_trylock(&dev->mutex);
|
||||
}
|
||||
|
||||
static inline void device_unlock(struct device *dev)
|
||||
{
|
||||
up(&dev->sem);
|
||||
mutex_unlock(&dev->mutex);
|
||||
}
|
||||
|
||||
void driver_init(void);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
struct firmware {
|
||||
size_t size;
|
||||
const u8 *data;
|
||||
struct page **pages;
|
||||
};
|
||||
|
||||
struct device;
|
||||
|
|
|
@ -108,6 +108,8 @@ struct kobj_type {
|
|||
void (*release)(struct kobject *kobj);
|
||||
const struct sysfs_ops *sysfs_ops;
|
||||
struct attribute **default_attrs;
|
||||
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
|
||||
const void *(*namespace)(struct kobject *kobj);
|
||||
};
|
||||
|
||||
struct kobj_uevent_env {
|
||||
|
@ -134,6 +136,42 @@ struct kobj_attribute {
|
|||
|
||||
extern const struct sysfs_ops kobj_sysfs_ops;
|
||||
|
||||
/*
|
||||
* Namespace types which are used to tag kobjects and sysfs entries.
|
||||
* Network namespace will likely be the first.
|
||||
*/
|
||||
enum kobj_ns_type {
|
||||
KOBJ_NS_TYPE_NONE = 0,
|
||||
KOBJ_NS_TYPE_NET,
|
||||
KOBJ_NS_TYPES
|
||||
};
|
||||
|
||||
struct sock;
|
||||
|
||||
/*
|
||||
* Callbacks so sysfs can determine namespaces
|
||||
* @current_ns: return calling task's namespace
|
||||
* @netlink_ns: return namespace to which a sock belongs (right?)
|
||||
* @initial_ns: return the initial namespace (i.e. init_net_ns)
|
||||
*/
|
||||
struct kobj_ns_type_operations {
|
||||
enum kobj_ns_type type;
|
||||
const void *(*current_ns)(void);
|
||||
const void *(*netlink_ns)(struct sock *sk);
|
||||
const void *(*initial_ns)(void);
|
||||
};
|
||||
|
||||
int kobj_ns_type_register(const struct kobj_ns_type_operations *ops);
|
||||
int kobj_ns_type_registered(enum kobj_ns_type type);
|
||||
const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent);
|
||||
const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj);
|
||||
|
||||
const void *kobj_ns_current(enum kobj_ns_type type);
|
||||
const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk);
|
||||
const void *kobj_ns_initial(enum kobj_ns_type type);
|
||||
void kobj_ns_exit(enum kobj_ns_type type, const void *ns);
|
||||
|
||||
|
||||
/**
|
||||
* struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
|
||||
*
|
||||
|
|
|
@ -21,7 +21,6 @@ struct kref {
|
|||
atomic_t refcount;
|
||||
};
|
||||
|
||||
void kref_set(struct kref *kref, int num);
|
||||
void kref_init(struct kref *kref);
|
||||
void kref_get(struct kref *kref);
|
||||
int kref_put(struct kref *kref, void (*release) (struct kref *kref));
|
||||
|
|
|
@ -44,6 +44,8 @@ struct lock_class_key {
|
|||
struct lockdep_subclass_key subkeys[MAX_LOCKDEP_SUBCLASSES];
|
||||
};
|
||||
|
||||
extern struct lock_class_key __lockdep_no_validate__;
|
||||
|
||||
#define LOCKSTAT_POINTS 4
|
||||
|
||||
/*
|
||||
|
@ -270,6 +272,9 @@ extern void lockdep_init_map(struct lockdep_map *lock, const char *name,
|
|||
#define lockdep_set_subclass(lock, sub) \
|
||||
lockdep_init_map(&(lock)->dep_map, #lock, \
|
||||
(lock)->dep_map.key, sub)
|
||||
|
||||
#define lockdep_set_novalidate_class(lock) \
|
||||
lockdep_set_class(lock, &__lockdep_no_validate__)
|
||||
/*
|
||||
* Compare locking classes
|
||||
*/
|
||||
|
@ -354,6 +359,9 @@ static inline void lockdep_on(void)
|
|||
#define lockdep_set_class_and_subclass(lock, key, sub) \
|
||||
do { (void)(key); } while (0)
|
||||
#define lockdep_set_subclass(lock, sub) do { } while (0)
|
||||
|
||||
#define lockdep_set_novalidate_class(lock) do { } while (0)
|
||||
|
||||
/*
|
||||
* We don't define lockdep_match_class() and lockdep_match_key() for !LOCKDEP
|
||||
* case since the result is not well defined and the caller should rather
|
||||
|
|
|
@ -188,6 +188,10 @@ extern int netlink_has_listeners(struct sock *sk, unsigned int group);
|
|||
extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock);
|
||||
extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid,
|
||||
__u32 group, gfp_t allocation);
|
||||
extern int netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb,
|
||||
__u32 pid, __u32 group, gfp_t allocation,
|
||||
int (*filter)(struct sock *dsk, struct sk_buff *skb, void *data),
|
||||
void *filter_data);
|
||||
extern int netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code);
|
||||
extern int netlink_register_notifier(struct notifier_block *nb);
|
||||
extern int netlink_unregister_notifier(struct notifier_block *nb);
|
||||
|
|
|
@ -20,4 +20,6 @@ extern const struct file_operations ramfs_file_operations;
|
|||
extern const struct vm_operations_struct generic_file_vm_ops;
|
||||
extern int __init init_rootfs(void);
|
||||
|
||||
int ramfs_fill_super(struct super_block *sb, void *data, int silent);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
struct kobject;
|
||||
struct module;
|
||||
enum kobj_ns_type;
|
||||
|
||||
/* FIXME
|
||||
* The *owner field is no longer used.
|
||||
|
@ -86,17 +87,18 @@ struct attribute_group {
|
|||
|
||||
#define attr_name(_attr) (_attr).attr.name
|
||||
|
||||
struct file;
|
||||
struct vm_area_struct;
|
||||
|
||||
struct bin_attribute {
|
||||
struct attribute attr;
|
||||
size_t size;
|
||||
void *private;
|
||||
ssize_t (*read)(struct kobject *, struct bin_attribute *,
|
||||
ssize_t (*read)(struct file *, struct kobject *, struct bin_attribute *,
|
||||
char *, loff_t, size_t);
|
||||
ssize_t (*write)(struct kobject *, struct bin_attribute *,
|
||||
ssize_t (*write)(struct file *,struct kobject *, struct bin_attribute *,
|
||||
char *, loff_t, size_t);
|
||||
int (*mmap)(struct kobject *, struct bin_attribute *attr,
|
||||
int (*mmap)(struct file *, struct kobject *, struct bin_attribute *attr,
|
||||
struct vm_area_struct *vma);
|
||||
};
|
||||
|
||||
|
@ -154,6 +156,9 @@ void sysfs_remove_link(struct kobject *kobj, const char *name);
|
|||
int sysfs_rename_link(struct kobject *kobj, struct kobject *target,
|
||||
const char *old_name, const char *new_name);
|
||||
|
||||
void sysfs_delete_link(struct kobject *dir, struct kobject *targ,
|
||||
const char *name);
|
||||
|
||||
int __must_check sysfs_create_group(struct kobject *kobj,
|
||||
const struct attribute_group *grp);
|
||||
int sysfs_update_group(struct kobject *kobj,
|
||||
|
@ -168,10 +173,15 @@ void sysfs_remove_file_from_group(struct kobject *kobj,
|
|||
void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr);
|
||||
void sysfs_notify_dirent(struct sysfs_dirent *sd);
|
||||
struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
|
||||
const void *ns,
|
||||
const unsigned char *name);
|
||||
struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd);
|
||||
void sysfs_put(struct sysfs_dirent *sd);
|
||||
void sysfs_printk_last_file(void);
|
||||
|
||||
/* Called to clear a ns tag when it is no longer valid */
|
||||
void sysfs_exit_ns(enum kobj_ns_type type, const void *tag);
|
||||
|
||||
int __must_check sysfs_init(void);
|
||||
|
||||
#else /* CONFIG_SYSFS */
|
||||
|
@ -264,6 +274,11 @@ static inline int sysfs_rename_link(struct kobject *k, struct kobject *t,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void sysfs_delete_link(struct kobject *k, struct kobject *t,
|
||||
const char *name)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int sysfs_create_group(struct kobject *kobj,
|
||||
const struct attribute_group *grp)
|
||||
{
|
||||
|
@ -301,6 +316,7 @@ static inline void sysfs_notify_dirent(struct sysfs_dirent *sd)
|
|||
}
|
||||
static inline
|
||||
struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
|
||||
const void *ns,
|
||||
const unsigned char *name)
|
||||
{
|
||||
return NULL;
|
||||
|
@ -313,6 +329,10 @@ static inline void sysfs_put(struct sysfs_dirent *sd)
|
|||
{
|
||||
}
|
||||
|
||||
static inline void sysfs_exit_ns(int type, const void *tag)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int __must_check sysfs_init(void)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
@ -138,7 +138,8 @@ extern const void __start_notes __attribute__((weak));
|
|||
extern const void __stop_notes __attribute__((weak));
|
||||
#define notes_size (&__stop_notes - &__start_notes)
|
||||
|
||||
static ssize_t notes_read(struct kobject *kobj, struct bin_attribute *bin_attr,
|
||||
static ssize_t notes_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
memcpy(buf, &__start_notes + off, count);
|
||||
|
|
|
@ -2711,6 +2711,8 @@ void lockdep_init_map(struct lockdep_map *lock, const char *name,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(lockdep_init_map);
|
||||
|
||||
struct lock_class_key __lockdep_no_validate__;
|
||||
|
||||
/*
|
||||
* This gets called for every mutex_lock*()/spin_lock*() operation.
|
||||
* We maintain the dependency maps and validate the locking attempt:
|
||||
|
@ -2745,6 +2747,9 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (lock->key == &__lockdep_no_validate__)
|
||||
check = 1;
|
||||
|
||||
if (!subclass)
|
||||
class = lock->class_cache;
|
||||
/*
|
||||
|
|
|
@ -1182,7 +1182,7 @@ struct module_notes_attrs {
|
|||
struct bin_attribute attrs[0];
|
||||
};
|
||||
|
||||
static ssize_t module_notes_read(struct kobject *kobj,
|
||||
static ssize_t module_notes_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t pos, size_t count)
|
||||
{
|
||||
|
|
|
@ -54,8 +54,8 @@ int create_user_ns(struct cred *new)
|
|||
#endif
|
||||
/* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */
|
||||
|
||||
/* alloc_uid() incremented the userns refcount. Just set it to 1 */
|
||||
kref_set(&ns->kref, 1);
|
||||
/* root_user holds a reference to ns, our reference can be dropped */
|
||||
put_user_ns(ns);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
115
lib/kobject.c
115
lib/kobject.c
|
@ -850,6 +850,121 @@ struct kset *kset_create_and_add(const char *name,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(kset_create_and_add);
|
||||
|
||||
|
||||
static DEFINE_SPINLOCK(kobj_ns_type_lock);
|
||||
static const struct kobj_ns_type_operations *kobj_ns_ops_tbl[KOBJ_NS_TYPES];
|
||||
|
||||
int kobj_ns_type_register(const struct kobj_ns_type_operations *ops)
|
||||
{
|
||||
enum kobj_ns_type type = ops->type;
|
||||
int error;
|
||||
|
||||
spin_lock(&kobj_ns_type_lock);
|
||||
|
||||
error = -EINVAL;
|
||||
if (type >= KOBJ_NS_TYPES)
|
||||
goto out;
|
||||
|
||||
error = -EINVAL;
|
||||
if (type <= KOBJ_NS_TYPE_NONE)
|
||||
goto out;
|
||||
|
||||
error = -EBUSY;
|
||||
if (kobj_ns_ops_tbl[type])
|
||||
goto out;
|
||||
|
||||
error = 0;
|
||||
kobj_ns_ops_tbl[type] = ops;
|
||||
|
||||
out:
|
||||
spin_unlock(&kobj_ns_type_lock);
|
||||
return error;
|
||||
}
|
||||
|
||||
int kobj_ns_type_registered(enum kobj_ns_type type)
|
||||
{
|
||||
int registered = 0;
|
||||
|
||||
spin_lock(&kobj_ns_type_lock);
|
||||
if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES))
|
||||
registered = kobj_ns_ops_tbl[type] != NULL;
|
||||
spin_unlock(&kobj_ns_type_lock);
|
||||
|
||||
return registered;
|
||||
}
|
||||
|
||||
const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent)
|
||||
{
|
||||
const struct kobj_ns_type_operations *ops = NULL;
|
||||
|
||||
if (parent && parent->ktype->child_ns_type)
|
||||
ops = parent->ktype->child_ns_type(parent);
|
||||
|
||||
return ops;
|
||||
}
|
||||
|
||||
const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj)
|
||||
{
|
||||
return kobj_child_ns_ops(kobj->parent);
|
||||
}
|
||||
|
||||
|
||||
const void *kobj_ns_current(enum kobj_ns_type type)
|
||||
{
|
||||
const void *ns = NULL;
|
||||
|
||||
spin_lock(&kobj_ns_type_lock);
|
||||
if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
|
||||
kobj_ns_ops_tbl[type])
|
||||
ns = kobj_ns_ops_tbl[type]->current_ns();
|
||||
spin_unlock(&kobj_ns_type_lock);
|
||||
|
||||
return ns;
|
||||
}
|
||||
|
||||
const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk)
|
||||
{
|
||||
const void *ns = NULL;
|
||||
|
||||
spin_lock(&kobj_ns_type_lock);
|
||||
if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
|
||||
kobj_ns_ops_tbl[type])
|
||||
ns = kobj_ns_ops_tbl[type]->netlink_ns(sk);
|
||||
spin_unlock(&kobj_ns_type_lock);
|
||||
|
||||
return ns;
|
||||
}
|
||||
|
||||
const void *kobj_ns_initial(enum kobj_ns_type type)
|
||||
{
|
||||
const void *ns = NULL;
|
||||
|
||||
spin_lock(&kobj_ns_type_lock);
|
||||
if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
|
||||
kobj_ns_ops_tbl[type])
|
||||
ns = kobj_ns_ops_tbl[type]->initial_ns();
|
||||
spin_unlock(&kobj_ns_type_lock);
|
||||
|
||||
return ns;
|
||||
}
|
||||
|
||||
/*
|
||||
* kobj_ns_exit - invalidate a namespace tag
|
||||
*
|
||||
* @type: the namespace type (i.e. KOBJ_NS_TYPE_NET)
|
||||
* @ns: the actual namespace being invalidated
|
||||
*
|
||||
* This is called when a tag is no longer valid. For instance,
|
||||
* when a network namespace exits, it uses this helper to
|
||||
* make sure no sb's sysfs_info points to the now-invalidated
|
||||
* netns.
|
||||
*/
|
||||
void kobj_ns_exit(enum kobj_ns_type type, const void *ns)
|
||||
{
|
||||
sysfs_exit_ns(type, ns);
|
||||
}
|
||||
|
||||
|
||||
EXPORT_SYMBOL(kobject_get);
|
||||
EXPORT_SYMBOL(kobject_put);
|
||||
EXPORT_SYMBOL(kobject_del);
|
||||
|
|
|
@ -19,18 +19,24 @@
|
|||
#include <linux/kobject.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/user_namespace.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/net_namespace.h>
|
||||
|
||||
|
||||
u64 uevent_seqnum;
|
||||
char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
|
||||
static DEFINE_SPINLOCK(sequence_lock);
|
||||
#if defined(CONFIG_NET)
|
||||
static struct sock *uevent_sock;
|
||||
#ifdef CONFIG_NET
|
||||
struct uevent_sock {
|
||||
struct list_head list;
|
||||
struct sock *sk;
|
||||
};
|
||||
static LIST_HEAD(uevent_sock_list);
|
||||
static DEFINE_MUTEX(uevent_sock_mutex);
|
||||
#endif
|
||||
|
||||
/* the strings here must match the enum in include/linux/kobject.h */
|
||||
|
@ -77,6 +83,37 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data)
|
||||
{
|
||||
struct kobject *kobj = data;
|
||||
const struct kobj_ns_type_operations *ops;
|
||||
|
||||
ops = kobj_ns_ops(kobj);
|
||||
if (ops) {
|
||||
const void *sock_ns, *ns;
|
||||
ns = kobj->ktype->namespace(kobj);
|
||||
sock_ns = ops->netlink_ns(dsk);
|
||||
return sock_ns != ns;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kobj_usermode_filter(struct kobject *kobj)
|
||||
{
|
||||
const struct kobj_ns_type_operations *ops;
|
||||
|
||||
ops = kobj_ns_ops(kobj);
|
||||
if (ops) {
|
||||
const void *init_ns, *ns;
|
||||
ns = kobj->ktype->namespace(kobj);
|
||||
init_ns = ops->initial_ns();
|
||||
return ns != init_ns;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* kobject_uevent_env - send an uevent with environmental data
|
||||
*
|
||||
|
@ -100,6 +137,9 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
|
|||
u64 seq;
|
||||
int i = 0;
|
||||
int retval = 0;
|
||||
#ifdef CONFIG_NET
|
||||
struct uevent_sock *ue_sk;
|
||||
#endif
|
||||
|
||||
pr_debug("kobject: '%s' (%p): %s\n",
|
||||
kobject_name(kobj), kobj, __func__);
|
||||
|
@ -211,7 +251,9 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
|
|||
|
||||
#if defined(CONFIG_NET)
|
||||
/* send netlink message */
|
||||
if (uevent_sock) {
|
||||
mutex_lock(&uevent_sock_mutex);
|
||||
list_for_each_entry(ue_sk, &uevent_sock_list, list) {
|
||||
struct sock *uevent_sock = ue_sk->sk;
|
||||
struct sk_buff *skb;
|
||||
size_t len;
|
||||
|
||||
|
@ -233,18 +275,21 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
|
|||
}
|
||||
|
||||
NETLINK_CB(skb).dst_group = 1;
|
||||
retval = netlink_broadcast(uevent_sock, skb, 0, 1,
|
||||
GFP_KERNEL);
|
||||
retval = netlink_broadcast_filtered(uevent_sock, skb,
|
||||
0, 1, GFP_KERNEL,
|
||||
kobj_bcast_filter,
|
||||
kobj);
|
||||
/* ENOBUFS should be handled in userspace */
|
||||
if (retval == -ENOBUFS)
|
||||
retval = 0;
|
||||
} else
|
||||
retval = -ENOMEM;
|
||||
}
|
||||
mutex_unlock(&uevent_sock_mutex);
|
||||
#endif
|
||||
|
||||
/* call uevent_helper, usually only enabled during early boot */
|
||||
if (uevent_helper[0]) {
|
||||
if (uevent_helper[0] && !kobj_usermode_filter(kobj)) {
|
||||
char *argv [3];
|
||||
|
||||
argv [0] = uevent_helper;
|
||||
|
@ -320,18 +365,58 @@ int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
|
|||
EXPORT_SYMBOL_GPL(add_uevent_var);
|
||||
|
||||
#if defined(CONFIG_NET)
|
||||
static int __init kobject_uevent_init(void)
|
||||
static int uevent_net_init(struct net *net)
|
||||
{
|
||||
uevent_sock = netlink_kernel_create(&init_net, NETLINK_KOBJECT_UEVENT,
|
||||
struct uevent_sock *ue_sk;
|
||||
|
||||
ue_sk = kzalloc(sizeof(*ue_sk), GFP_KERNEL);
|
||||
if (!ue_sk)
|
||||
return -ENOMEM;
|
||||
|
||||
ue_sk->sk = netlink_kernel_create(net, NETLINK_KOBJECT_UEVENT,
|
||||
1, NULL, NULL, THIS_MODULE);
|
||||
if (!uevent_sock) {
|
||||
if (!ue_sk->sk) {
|
||||
printk(KERN_ERR
|
||||
"kobject_uevent: unable to create netlink socket!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
netlink_set_nonroot(NETLINK_KOBJECT_UEVENT, NL_NONROOT_RECV);
|
||||
mutex_lock(&uevent_sock_mutex);
|
||||
list_add_tail(&ue_sk->list, &uevent_sock_list);
|
||||
mutex_unlock(&uevent_sock_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uevent_net_exit(struct net *net)
|
||||
{
|
||||
struct uevent_sock *ue_sk;
|
||||
|
||||
mutex_lock(&uevent_sock_mutex);
|
||||
list_for_each_entry(ue_sk, &uevent_sock_list, list) {
|
||||
if (sock_net(ue_sk->sk) == net)
|
||||
goto found;
|
||||
}
|
||||
mutex_unlock(&uevent_sock_mutex);
|
||||
return;
|
||||
|
||||
found:
|
||||
list_del(&ue_sk->list);
|
||||
mutex_unlock(&uevent_sock_mutex);
|
||||
|
||||
netlink_kernel_release(ue_sk->sk);
|
||||
kfree(ue_sk);
|
||||
}
|
||||
|
||||
static struct pernet_operations uevent_net_ops = {
|
||||
.init = uevent_net_init,
|
||||
.exit = uevent_net_exit,
|
||||
};
|
||||
|
||||
static int __init kobject_uevent_init(void)
|
||||
{
|
||||
netlink_set_nonroot(NETLINK_KOBJECT_UEVENT, NL_NONROOT_RECV);
|
||||
return register_pernet_subsys(&uevent_net_ops);
|
||||
}
|
||||
|
||||
|
||||
postcore_initcall(kobject_uevent_init);
|
||||
#endif
|
||||
|
|
15
lib/kref.c
15
lib/kref.c
|
@ -15,24 +15,14 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/**
|
||||
* kref_set - initialize object and set refcount to requested number.
|
||||
* @kref: object in question.
|
||||
* @num: initial reference counter
|
||||
*/
|
||||
void kref_set(struct kref *kref, int num)
|
||||
{
|
||||
atomic_set(&kref->refcount, num);
|
||||
smp_mb();
|
||||
}
|
||||
|
||||
/**
|
||||
* kref_init - initialize object.
|
||||
* @kref: object in question.
|
||||
*/
|
||||
void kref_init(struct kref *kref)
|
||||
{
|
||||
kref_set(kref, 1);
|
||||
atomic_set(&kref->refcount, 1);
|
||||
smp_mb();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,7 +62,6 @@ int kref_put(struct kref *kref, void (*release)(struct kref *kref))
|
|||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(kref_set);
|
||||
EXPORT_SYMBOL(kref_init);
|
||||
EXPORT_SYMBOL(kref_get);
|
||||
EXPORT_SYMBOL(kref_put);
|
||||
|
|
|
@ -659,7 +659,7 @@ static struct attribute_group bridge_group = {
|
|||
*
|
||||
* Returns the number of bytes read.
|
||||
*/
|
||||
static ssize_t brforward_read(struct kobject *kobj,
|
||||
static ssize_t brforward_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
|
|
|
@ -1002,16 +1002,11 @@ int dev_change_name(struct net_device *dev, const char *newname)
|
|||
return err;
|
||||
|
||||
rollback:
|
||||
/* For now only devices in the initial network namespace
|
||||
* are in sysfs.
|
||||
*/
|
||||
if (net_eq(net, &init_net)) {
|
||||
ret = device_rename(&dev->dev, dev->name);
|
||||
if (ret) {
|
||||
memcpy(dev->name, oldname, IFNAMSIZ);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
write_lock_bh(&dev_base_lock);
|
||||
hlist_del(&dev->name_hlist);
|
||||
|
@ -4994,8 +4989,6 @@ int register_netdevice(struct net_device *dev)
|
|||
if (dev->features & NETIF_F_SG)
|
||||
dev->features |= NETIF_F_GSO;
|
||||
|
||||
netdev_initialize_kobject(dev);
|
||||
|
||||
ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev);
|
||||
ret = notifier_to_errno(ret);
|
||||
if (ret)
|
||||
|
@ -5547,15 +5540,6 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
|
|||
if (dev->features & NETIF_F_NETNS_LOCAL)
|
||||
goto out;
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
/* Don't allow real devices to be moved when sysfs
|
||||
* is enabled.
|
||||
*/
|
||||
err = -EINVAL;
|
||||
if (dev->dev.parent)
|
||||
goto out;
|
||||
#endif
|
||||
|
||||
/* Ensure the device has been registrered */
|
||||
err = -EINVAL;
|
||||
if (dev->reg_state != NETREG_REGISTERED)
|
||||
|
@ -5606,8 +5590,6 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
|
|||
dev_uc_flush(dev);
|
||||
dev_mc_flush(dev);
|
||||
|
||||
netdev_unregister_kobject(dev);
|
||||
|
||||
/* Actually switch the network namespace */
|
||||
dev_net_set(dev, net);
|
||||
|
||||
|
@ -5620,7 +5602,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
|
|||
}
|
||||
|
||||
/* Fixup kobjects */
|
||||
err = netdev_register_kobject(dev);
|
||||
err = device_rename(&dev->dev, dev->name);
|
||||
WARN_ON(err);
|
||||
|
||||
/* Add the device back in the hashes */
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
#include <linux/netdevice.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/nsproxy.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
@ -467,6 +469,7 @@ static struct attribute_group wireless_group = {
|
|||
.attrs = wireless_attrs,
|
||||
};
|
||||
#endif
|
||||
#endif /* CONFIG_SYSFS */
|
||||
|
||||
#ifdef CONFIG_RPS
|
||||
/*
|
||||
|
@ -766,7 +769,38 @@ static void rx_queue_remove_kobjects(struct net_device *net)
|
|||
kset_unregister(net->queues_kset);
|
||||
}
|
||||
#endif /* CONFIG_RPS */
|
||||
#endif /* CONFIG_SYSFS */
|
||||
|
||||
static const void *net_current_ns(void)
|
||||
{
|
||||
return current->nsproxy->net_ns;
|
||||
}
|
||||
|
||||
static const void *net_initial_ns(void)
|
||||
{
|
||||
return &init_net;
|
||||
}
|
||||
|
||||
static const void *net_netlink_ns(struct sock *sk)
|
||||
{
|
||||
return sock_net(sk);
|
||||
}
|
||||
|
||||
static struct kobj_ns_type_operations net_ns_type_operations = {
|
||||
.type = KOBJ_NS_TYPE_NET,
|
||||
.current_ns = net_current_ns,
|
||||
.netlink_ns = net_netlink_ns,
|
||||
.initial_ns = net_initial_ns,
|
||||
};
|
||||
|
||||
static void net_kobj_ns_exit(struct net *net)
|
||||
{
|
||||
kobj_ns_exit(KOBJ_NS_TYPE_NET, net);
|
||||
}
|
||||
|
||||
static struct pernet_operations kobj_net_ops = {
|
||||
.exit = net_kobj_ns_exit,
|
||||
};
|
||||
|
||||
|
||||
#ifdef CONFIG_HOTPLUG
|
||||
static int netdev_uevent(struct device *d, struct kobj_uevent_env *env)
|
||||
|
@ -774,9 +808,6 @@ static int netdev_uevent(struct device *d, struct kobj_uevent_env *env)
|
|||
struct net_device *dev = to_net_dev(d);
|
||||
int retval;
|
||||
|
||||
if (!net_eq(dev_net(dev), &init_net))
|
||||
return 0;
|
||||
|
||||
/* pass interface to uevent. */
|
||||
retval = add_uevent_var(env, "INTERFACE=%s", dev->name);
|
||||
if (retval)
|
||||
|
@ -806,6 +837,13 @@ static void netdev_release(struct device *d)
|
|||
kfree((char *)dev - dev->padded);
|
||||
}
|
||||
|
||||
static const void *net_namespace(struct device *d)
|
||||
{
|
||||
struct net_device *dev;
|
||||
dev = container_of(d, struct net_device, dev);
|
||||
return dev_net(dev);
|
||||
}
|
||||
|
||||
static struct class net_class = {
|
||||
.name = "net",
|
||||
.dev_release = netdev_release,
|
||||
|
@ -815,6 +853,8 @@ static struct class net_class = {
|
|||
#ifdef CONFIG_HOTPLUG
|
||||
.dev_uevent = netdev_uevent,
|
||||
#endif
|
||||
.ns_type = &net_ns_type_operations,
|
||||
.namespace = net_namespace,
|
||||
};
|
||||
|
||||
/* Delete sysfs entries but hold kobject reference until after all
|
||||
|
@ -826,9 +866,6 @@ void netdev_unregister_kobject(struct net_device * net)
|
|||
|
||||
kobject_get(&dev->kobj);
|
||||
|
||||
if (!net_eq(dev_net(net), &init_net))
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_RPS
|
||||
rx_queue_remove_kobjects(net);
|
||||
#endif
|
||||
|
@ -843,6 +880,7 @@ int netdev_register_kobject(struct net_device *net)
|
|||
const struct attribute_group **groups = net->sysfs_groups;
|
||||
int error = 0;
|
||||
|
||||
device_initialize(dev);
|
||||
dev->class = &net_class;
|
||||
dev->platform_data = net;
|
||||
dev->groups = groups;
|
||||
|
@ -865,9 +903,6 @@ int netdev_register_kobject(struct net_device *net)
|
|||
#endif
|
||||
#endif /* CONFIG_SYSFS */
|
||||
|
||||
if (!net_eq(dev_net(net), &init_net))
|
||||
return 0;
|
||||
|
||||
error = device_add(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
@ -896,13 +931,9 @@ void netdev_class_remove_file(struct class_attribute *class_attr)
|
|||
EXPORT_SYMBOL(netdev_class_create_file);
|
||||
EXPORT_SYMBOL(netdev_class_remove_file);
|
||||
|
||||
void netdev_initialize_kobject(struct net_device *net)
|
||||
{
|
||||
struct device *device = &(net->dev);
|
||||
device_initialize(device);
|
||||
}
|
||||
|
||||
int netdev_kobject_init(void)
|
||||
{
|
||||
kobj_ns_type_register(&net_ns_type_operations);
|
||||
register_pernet_subsys(&kobj_net_ops);
|
||||
return class_register(&net_class);
|
||||
}
|
||||
|
|
|
@ -4,5 +4,4 @@
|
|||
int netdev_kobject_init(void);
|
||||
int netdev_register_kobject(struct net_device *);
|
||||
void netdev_unregister_kobject(struct net_device *);
|
||||
void netdev_initialize_kobject(struct net_device *);
|
||||
#endif
|
||||
|
|
|
@ -978,6 +978,8 @@ struct netlink_broadcast_data {
|
|||
int delivered;
|
||||
gfp_t allocation;
|
||||
struct sk_buff *skb, *skb2;
|
||||
int (*tx_filter)(struct sock *dsk, struct sk_buff *skb, void *data);
|
||||
void *tx_data;
|
||||
};
|
||||
|
||||
static inline int do_one_broadcast(struct sock *sk,
|
||||
|
@ -1020,6 +1022,9 @@ static inline int do_one_broadcast(struct sock *sk,
|
|||
p->failure = 1;
|
||||
if (nlk->flags & NETLINK_BROADCAST_SEND_ERROR)
|
||||
p->delivery_failure = 1;
|
||||
} else if (p->tx_filter && p->tx_filter(sk, p->skb2, p->tx_data)) {
|
||||
kfree_skb(p->skb2);
|
||||
p->skb2 = NULL;
|
||||
} else if (sk_filter(sk, p->skb2)) {
|
||||
kfree_skb(p->skb2);
|
||||
p->skb2 = NULL;
|
||||
|
@ -1038,8 +1043,10 @@ out:
|
|||
return 0;
|
||||
}
|
||||
|
||||
int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
|
||||
u32 group, gfp_t allocation)
|
||||
int netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb, u32 pid,
|
||||
u32 group, gfp_t allocation,
|
||||
int (*filter)(struct sock *dsk, struct sk_buff *skb, void *data),
|
||||
void *filter_data)
|
||||
{
|
||||
struct net *net = sock_net(ssk);
|
||||
struct netlink_broadcast_data info;
|
||||
|
@ -1059,6 +1066,8 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
|
|||
info.allocation = allocation;
|
||||
info.skb = skb;
|
||||
info.skb2 = NULL;
|
||||
info.tx_filter = filter;
|
||||
info.tx_data = filter_data;
|
||||
|
||||
/* While we sleep in clone, do not allow to change socket list */
|
||||
|
||||
|
@ -1083,6 +1092,14 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
|
|||
}
|
||||
return -ESRCH;
|
||||
}
|
||||
EXPORT_SYMBOL(netlink_broadcast_filtered);
|
||||
|
||||
int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
|
||||
u32 group, gfp_t allocation)
|
||||
{
|
||||
return netlink_broadcast_filtered(ssk, skb, pid, group, allocation,
|
||||
NULL, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(netlink_broadcast);
|
||||
|
||||
struct netlink_set_err_data {
|
||||
|
|
|
@ -2656,6 +2656,7 @@ sub process {
|
|||
# check for semaphores used as mutexes
|
||||
if ($line =~ /^.\s*init_MUTEX_LOCKED\s*\(/) {
|
||||
WARN("consider using a completion\n" . $herecurr);
|
||||
|
||||
}
|
||||
# recommend strict_strto* over simple_strto*
|
||||
if ($line =~ /\bsimple_(strto.*?)\s*\(/) {
|
||||
|
@ -2740,6 +2741,16 @@ sub process {
|
|||
WARN("use of in_atomic() is incorrect outside core kernel code\n" . $herecurr);
|
||||
}
|
||||
}
|
||||
|
||||
# check for lockdep_set_novalidate_class
|
||||
if ($line =~ /^.\s*lockdep_set_novalidate_class\s*\(/ ||
|
||||
$line =~ /__lockdep_no_validate__\s*\)/ ) {
|
||||
if ($realfile !~ m@^kernel/lockdep@ &&
|
||||
$realfile !~ m@^include/linux/lockdep@ &&
|
||||
$realfile !~ m@^drivers/base/core@) {
|
||||
ERROR("lockdep_no_validate class is reserved for device->mutex.\n" . $herecurr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# If we have no input at all, then there is nothing to report on
|
||||
|
|
|
@ -94,7 +94,7 @@ void iint_free(struct kref *kref)
|
|||
iint->opencount);
|
||||
iint->opencount = 0;
|
||||
}
|
||||
kref_set(&iint->refcount, 1);
|
||||
kref_init(&iint->refcount);
|
||||
kmem_cache_free(iint_cache, iint);
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ static void init_once(void *foo)
|
|||
iint->readcount = 0;
|
||||
iint->writecount = 0;
|
||||
iint->opencount = 0;
|
||||
kref_set(&iint->refcount, 1);
|
||||
kref_init(&iint->refcount);
|
||||
}
|
||||
|
||||
static int __init ima_iintcache_init(void)
|
||||
|
|
Loading…
Reference in New Issue