diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2014-01-10 14:18:27 +1100 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2014-01-10 14:18:27 +1100 |
commit | 0f02a9cdf56291900082b836bb25efb1ab5b4a5e (patch) | |
tree | 144429dfc73c3209e0bdb4423e929a4e9d11cbcb /include | |
parent | 19eee7a401b4a2316f1ebcdc7e66b44d6d7ea963 (diff) | |
parent | 08da2012e0bb0f3f1422cce3f76c36a90da366b5 (diff) |
Merge remote-tracking branch 'driver-core/driver-core-next'
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/firmware.h | 7 | ||||
-rw-r--r-- | include/linux/kernfs.h | 375 | ||||
-rw-r--r-- | include/linux/kobj_completion.h | 18 | ||||
-rw-r--r-- | include/linux/kobject.h | 2 | ||||
-rw-r--r-- | include/linux/memory.h | 1 | ||||
-rw-r--r-- | include/linux/sysfs.h | 47 |
6 files changed, 404 insertions, 46 deletions
diff --git a/include/linux/firmware.h b/include/linux/firmware.h index e154c1005cd1..59529330efd6 100644 --- a/include/linux/firmware.h +++ b/include/linux/firmware.h @@ -68,4 +68,11 @@ static inline void release_firmware(const struct firmware *fw) #endif +#ifdef CONFIG_FW_LOADER_USER_HELPER +int request_firmware_direct(const struct firmware **fw, const char *name, + struct device *device); +#else +#define request_firmware_direct request_firmware +#endif + #endif diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h new file mode 100644 index 000000000000..d2c439db4efa --- /dev/null +++ b/include/linux/kernfs.h @@ -0,0 +1,375 @@ +/* + * kernfs.h - pseudo filesystem decoupled from vfs locking + * + * This file is released under the GPLv2. + */ + +#ifndef __LINUX_KERNFS_H +#define __LINUX_KERNFS_H + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/idr.h> +#include <linux/lockdep.h> +#include <linux/rbtree.h> +#include <linux/atomic.h> +#include <linux/completion.h> + +struct file; +struct iattr; +struct seq_file; +struct vm_area_struct; +struct super_block; +struct file_system_type; + +struct kernfs_open_node; +struct kernfs_iattrs; + +enum kernfs_node_type { + KERNFS_DIR = 0x0001, + KERNFS_FILE = 0x0002, + KERNFS_LINK = 0x0004, +}; + +#define KERNFS_TYPE_MASK 0x000f +#define KERNFS_ACTIVE_REF KERNFS_FILE +#define KERNFS_FLAG_MASK ~KERNFS_TYPE_MASK + +enum kernfs_node_flag { + KERNFS_REMOVED = 0x0010, + KERNFS_NS = 0x0020, + KERNFS_HAS_SEQ_SHOW = 0x0040, + KERNFS_HAS_MMAP = 0x0080, + KERNFS_LOCKDEP = 0x0100, + KERNFS_STATIC_NAME = 0x0200, +}; + +/* type-specific structures for kernfs_node union members */ +struct kernfs_elem_dir { + unsigned long subdirs; + /* children rbtree starts here and goes through kn->rb */ + struct rb_root children; + + /* + * The kernfs hierarchy this directory belongs to. This fits + * better directly in kernfs_node but is here to save space. + */ + struct kernfs_root *root; +}; + +struct kernfs_elem_symlink { + struct kernfs_node *target_kn; +}; + +struct kernfs_elem_attr { + const struct kernfs_ops *ops; + struct kernfs_open_node *open; + loff_t size; +}; + +/* + * kernfs_node - the building block of kernfs hierarchy. Each and every + * kernfs node is represented by single kernfs_node. Most fields are + * private to kernfs and shouldn't be accessed directly by kernfs users. + * + * As long as s_count reference is held, the kernfs_node itself is + * accessible. Dereferencing elem or any other outer entity requires + * active reference. + */ +struct kernfs_node { + atomic_t count; + atomic_t active; +#ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; +#endif + /* the following two fields are published */ + struct kernfs_node *parent; + const char *name; + + struct rb_node rb; + + union { + struct completion *completion; + struct kernfs_node *removed_list; + } u; + + const void *ns; /* namespace tag */ + unsigned int hash; /* ns + name hash */ + union { + struct kernfs_elem_dir dir; + struct kernfs_elem_symlink symlink; + struct kernfs_elem_attr attr; + }; + + void *priv; + + unsigned short flags; + umode_t mode; + unsigned int ino; + struct kernfs_iattrs *iattr; +}; + +/* + * kernfs_dir_ops may be specified on kernfs_create_root() to support + * directory manipulation syscalls. These optional callbacks are invoked + * on the matching syscalls and can perform any kernfs operations which + * don't necessarily have to be the exact operation requested. + */ +struct kernfs_dir_ops { + int (*mkdir)(struct kernfs_node *parent, const char *name, + umode_t mode); + int (*rmdir)(struct kernfs_node *kn); + int (*rename)(struct kernfs_node *kn, struct kernfs_node *new_parent, + const char *new_name); +}; + +struct kernfs_root { + /* published fields */ + struct kernfs_node *kn; + + /* private fields, do not use outside kernfs proper */ + struct ida ino_ida; + struct kernfs_dir_ops *dir_ops; +}; + +struct kernfs_open_file { + /* published fields */ + struct kernfs_node *kn; + struct file *file; + + /* private fields, do not use outside kernfs proper */ + struct mutex mutex; + int event; + struct list_head list; + + bool mmapped; + const struct vm_operations_struct *vm_ops; +}; + +struct kernfs_ops { + /* + * Read is handled by either seq_file or raw_read(). + * + * If seq_show() is present, seq_file path is active. Other seq + * operations are optional and if not implemented, the behavior is + * equivalent to single_open(). @sf->private points to the + * associated kernfs_open_file. + * + * read() is bounced through kernel buffer and a read larger than + * PAGE_SIZE results in partial operation of PAGE_SIZE. + */ + int (*seq_show)(struct seq_file *sf, void *v); + + void *(*seq_start)(struct seq_file *sf, loff_t *ppos); + void *(*seq_next)(struct seq_file *sf, void *v, loff_t *ppos); + void (*seq_stop)(struct seq_file *sf, void *v); + + ssize_t (*read)(struct kernfs_open_file *of, char *buf, size_t bytes, + loff_t off); + + /* + * write() is bounced through kernel buffer and a write larger than + * PAGE_SIZE results in partial operation of PAGE_SIZE. + */ + ssize_t (*write)(struct kernfs_open_file *of, char *buf, size_t bytes, + loff_t off); + + int (*mmap)(struct kernfs_open_file *of, struct vm_area_struct *vma); + +#ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lock_class_key lockdep_key; +#endif +}; + +#ifdef CONFIG_SYSFS + +static inline enum kernfs_node_type kernfs_type(struct kernfs_node *kn) +{ + return kn->flags & KERNFS_TYPE_MASK; +} + +/** + * kernfs_enable_ns - enable namespace under a directory + * @kn: directory of interest, should be empty + * + * This is to be called right after @kn is created to enable namespace + * under it. All children of @kn must have non-NULL namespace tags and + * only the ones which match the super_block's tag will be visible. + */ +static inline void kernfs_enable_ns(struct kernfs_node *kn) +{ + WARN_ON_ONCE(kernfs_type(kn) != KERNFS_DIR); + WARN_ON_ONCE(!RB_EMPTY_ROOT(&kn->dir.children)); + kn->flags |= KERNFS_NS; +} + +/** + * kernfs_ns_enabled - test whether namespace is enabled + * @kn: the node to test + * + * Test whether namespace filtering is enabled for the children of @ns. + */ +static inline bool kernfs_ns_enabled(struct kernfs_node *kn) +{ + return kn->flags & KERNFS_NS; +} + +struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, + const char *name, const void *ns); +void kernfs_get(struct kernfs_node *kn); +void kernfs_put(struct kernfs_node *kn); + +struct kernfs_root *kernfs_create_root(struct kernfs_dir_ops *kdops, + void *priv); +void kernfs_destroy_root(struct kernfs_root *root); + +struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, + const char *name, umode_t mode, + void *priv, const void *ns); +struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, + const char *name, + umode_t mode, loff_t size, + const struct kernfs_ops *ops, + void *priv, const void *ns, + bool name_is_static, + struct lock_class_key *key); +struct kernfs_node *kernfs_create_link(struct kernfs_node *parent, + const char *name, + struct kernfs_node *target); +void kernfs_remove(struct kernfs_node *kn); +int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, + const void *ns); +int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, + const char *new_name, const void *new_ns); +int kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr); +void kernfs_notify(struct kernfs_node *kn); + +const void *kernfs_super_ns(struct super_block *sb); +struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, + struct kernfs_root *root, const void *ns); +void kernfs_kill_sb(struct super_block *sb); + +void kernfs_init(void); + +#else /* CONFIG_SYSFS */ + +static inline enum kernfs_node_type kernfs_type(struct kernfs_node *kn) +{ return 0; } /* whatever */ + +static inline void kernfs_enable_ns(struct kernfs_node *kn) { } + +static inline bool kernfs_ns_enabled(struct kernfs_node *kn) +{ return false; } + +static inline struct kernfs_node * +kernfs_find_and_get_ns(struct kernfs_node *parent, const char *name, + const void *ns) +{ return NULL; } + +static inline void kernfs_get(struct kernfs_node *kn) { } +static inline void kernfs_put(struct kernfs_node *kn) { } + +static inline struct kernfs_root * +kernfs_create_root(struct kernfs_dir_ops *kdops, void *priv) +{ return ERR_PTR(-ENOSYS); } + +static inline void kernfs_destroy_root(struct kernfs_root *root) { } + +static inline struct kernfs_node * +kernfs_create_dir_ns(struct kernfs_node *parent, const char *name, + umode_t mode, void *priv, const void *ns) +{ return ERR_PTR(-ENOSYS); } + +static inline struct kernfs_node * +__kernfs_create_file(struct kernfs_node *parent, const char *name, + umode_t mode, loff_t size, const struct kernfs_ops *ops, + void *priv, const void *ns, bool name_is_static, + struct lock_class_key *key) +{ return ERR_PTR(-ENOSYS); } + +static inline struct kernfs_node * +kernfs_create_link(struct kernfs_node *parent, const char *name, + struct kernfs_node *target) +{ return ERR_PTR(-ENOSYS); } + +static inline void kernfs_remove(struct kernfs_node *kn) { } + +static inline int kernfs_remove_by_name_ns(struct kernfs_node *kn, + const char *name, const void *ns) +{ return -ENOSYS; } + +static inline int kernfs_rename_ns(struct kernfs_node *kn, + struct kernfs_node *new_parent, + const char *new_name, const void *new_ns) +{ return -ENOSYS; } + +static inline int kernfs_setattr(struct kernfs_node *kn, + const struct iattr *iattr) +{ return -ENOSYS; } + +static inline void kernfs_notify(struct kernfs_node *kn) { } + +static inline const void *kernfs_super_ns(struct super_block *sb) +{ return NULL; } + +static inline struct dentry * +kernfs_mount_ns(struct file_system_type *fs_type, int flags, + struct kernfs_root *root, const void *ns) +{ return ERR_PTR(-ENOSYS); } + +static inline void kernfs_kill_sb(struct super_block *sb) { } + +static inline void kernfs_init(void) { } + +#endif /* CONFIG_SYSFS */ + +static inline struct kernfs_node * +kernfs_find_and_get(struct kernfs_node *kn, const char *name) +{ + return kernfs_find_and_get_ns(kn, name, NULL); +} + +static inline struct kernfs_node * +kernfs_create_dir(struct kernfs_node *parent, const char *name, umode_t mode, + void *priv) +{ + return kernfs_create_dir_ns(parent, name, mode, priv, NULL); +} + +static inline struct kernfs_node * +kernfs_create_file_ns(struct kernfs_node *parent, const char *name, + umode_t mode, loff_t size, const struct kernfs_ops *ops, + void *priv, const void *ns) +{ + struct lock_class_key *key = NULL; + +#ifdef CONFIG_DEBUG_LOCK_ALLOC + key = (struct lock_class_key *)&ops->lockdep_key; +#endif + return __kernfs_create_file(parent, name, mode, size, ops, priv, ns, + false, key); +} + +static inline struct kernfs_node * +kernfs_create_file(struct kernfs_node *parent, const char *name, umode_t mode, + loff_t size, const struct kernfs_ops *ops, void *priv) +{ + return kernfs_create_file_ns(parent, name, mode, size, ops, priv, NULL); +} + +static inline int kernfs_remove_by_name(struct kernfs_node *parent, + const char *name) +{ + return kernfs_remove_by_name_ns(parent, name, NULL); +} + +static inline struct dentry * +kernfs_mount(struct file_system_type *fs_type, int flags, + struct kernfs_root *root) +{ + return kernfs_mount_ns(fs_type, flags, root, NULL); +} + +#endif /* __LINUX_KERNFS_H */ diff --git a/include/linux/kobj_completion.h b/include/linux/kobj_completion.h deleted file mode 100644 index a428f6436063..000000000000 --- a/include/linux/kobj_completion.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _KOBJ_COMPLETION_H_ -#define _KOBJ_COMPLETION_H_ - -#include <linux/kobject.h> -#include <linux/completion.h> - -struct kobj_completion { - struct kobject kc_kobj; - struct completion kc_unregister; -}; - -#define kobj_to_kobj_completion(kobj) \ - container_of(kobj, struct kobj_completion, kc_kobj) - -void kobj_completion_init(struct kobj_completion *kc, struct kobj_type *ktype); -void kobj_completion_release(struct kobject *kobj); -void kobj_completion_del_and_wait(struct kobj_completion *kc); -#endif /* _KOBJ_COMPLETION_H_ */ diff --git a/include/linux/kobject.h b/include/linux/kobject.h index e7ba650086ce..926afb6f6b5f 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -64,7 +64,7 @@ struct kobject { struct kobject *parent; struct kset *kset; struct kobj_type *ktype; - struct sysfs_dirent *sd; + struct kernfs_node *sd; struct kref kref; #ifdef CONFIG_DEBUG_KOBJECT_RELEASE struct delayed_work release; diff --git a/include/linux/memory.h b/include/linux/memory.h index 9a6bbf76452d..bb7384e3c3d8 100644 --- a/include/linux/memory.h +++ b/include/linux/memory.h @@ -35,6 +35,7 @@ struct memory_block { }; int arch_get_memory_phys_device(unsigned long start_pfn); +unsigned long __weak memory_block_size_bytes(void); /* These states are exposed to userspace as text strings in sysfs */ #define MEM_ONLINE (1<<0) /* exposed to userspace */ diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 6695040a0317..30b2ebee6439 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -12,6 +12,7 @@ #ifndef _SYSFS_H_ #define _SYSFS_H_ +#include <linux/kernfs.h> #include <linux/compiler.h> #include <linux/errno.h> #include <linux/list.h> @@ -175,8 +176,6 @@ struct sysfs_ops { ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t); }; -struct sysfs_dirent; - #ifdef CONFIG_SYSFS int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), @@ -244,12 +243,6 @@ void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name, const char *link_name); 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_ns(struct sysfs_dirent *parent_sd, - const unsigned char *name, - const void *ns); -struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd); -void sysfs_put(struct sysfs_dirent *sd); int __must_check sysfs_init(void); @@ -419,22 +412,6 @@ static inline void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr) { } -static inline void sysfs_notify_dirent(struct sysfs_dirent *sd) -{ -} -static inline struct sysfs_dirent * -sysfs_get_dirent_ns(struct sysfs_dirent *parent_sd, const unsigned char *name, - const void *ns) -{ - return NULL; -} -static inline struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd) -{ - return NULL; -} -static inline void sysfs_put(struct sysfs_dirent *sd) -{ -} static inline int __must_check sysfs_init(void) { @@ -461,10 +438,26 @@ static inline int sysfs_rename_link(struct kobject *kobj, struct kobject *target return sysfs_rename_link_ns(kobj, target, old_name, new_name, NULL); } -static inline struct sysfs_dirent * -sysfs_get_dirent(struct sysfs_dirent *parent_sd, const unsigned char *name) +static inline void sysfs_notify_dirent(struct kernfs_node *kn) +{ + kernfs_notify(kn); +} + +static inline struct kernfs_node *sysfs_get_dirent(struct kernfs_node *parent, + const unsigned char *name) +{ + return kernfs_find_and_get(parent, name); +} + +static inline struct kernfs_node *sysfs_get(struct kernfs_node *kn) +{ + kernfs_get(kn); + return kn; +} + +static inline void sysfs_put(struct kernfs_node *kn) { - return sysfs_get_dirent_ns(parent_sd, name, NULL); + kernfs_put(kn); } #endif /* _SYSFS_H_ */ |