summaryrefslogtreecommitdiffstats
path: root/include/linux/kernfs.h
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-11-29 17:18:32 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-11-29 21:21:01 -0500
commitcf9e5a73aaff0204801dd19cb4bd91d32f32026a (patch)
tree4a63d030a4c2ee08c06b97d348bcf42bdf7a3cd4 /include/linux/kernfs.h
parentfa736a951e456b996a76826ba78ff974414c3b55 (diff)
sysfs, kernfs: make sysfs_dirent definition public
sysfs_dirent includes some information which should be available to kernfs users - the type, flags, name and parent pointer. This patch moves sysfs_dirent definition from kernfs/kernfs-internal.h to include/linux/kernfs.h so that kernfs users can access them. The type part of flags is exported as enum kernfs_node_type, the flags kernfs_node_flag, sysfs_type() and kernfs_enable_ns() are moved to include/linux/kernfs.h and the former is updated to return the enum type. sysfs_dirent->s_parent and ->s_name are marked explicitly as public. This patch doesn't introduce any functional changes. v2: Flags exported too and kernfs_enable_ns() definition moved. v3: While moving kernfs_enable_ns() to include/linux/kernfs.h, v1 and v2 put the definition outside CONFIG_SYSFS replacing the dummy implementation with the actual implementation too. Unfortunately, this can lead to oops when !CONFIG_SYSFS because kernfs_enable_ns() may be called on a NULL @sd and now tries to dereference @sd instead of not doing anything. This issue was reported by Yuanhan Liu. Signed-off-by: Tejun Heo <tj@kernel.org> Reported-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'include/linux/kernfs.h')
-rw-r--r--include/linux/kernfs.h118
1 files changed, 114 insertions, 4 deletions
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index 75fcbe5c9d65..faaf4f29e33d 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -13,6 +13,9 @@
13#include <linux/mutex.h> 13#include <linux/mutex.h>
14#include <linux/idr.h> 14#include <linux/idr.h>
15#include <linux/lockdep.h> 15#include <linux/lockdep.h>
16#include <linux/rbtree.h>
17#include <linux/atomic.h>
18#include <linux/completion.h>
16 19
17struct file; 20struct file;
18struct iattr; 21struct iattr;
@@ -21,7 +24,92 @@ struct vm_area_struct;
21struct super_block; 24struct super_block;
22struct file_system_type; 25struct file_system_type;
23 26
24struct sysfs_dirent; 27struct sysfs_open_dirent;
28struct sysfs_inode_attrs;
29
30enum kernfs_node_type {
31 SYSFS_DIR = 0x0001,
32 SYSFS_KOBJ_ATTR = 0x0002,
33 SYSFS_KOBJ_LINK = 0x0004,
34};
35
36#define SYSFS_TYPE_MASK 0x000f
37#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK)
38#define SYSFS_ACTIVE_REF SYSFS_KOBJ_ATTR
39#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK
40
41enum kernfs_node_flag {
42 SYSFS_FLAG_REMOVED = 0x0010,
43 SYSFS_FLAG_NS = 0x0020,
44 SYSFS_FLAG_HAS_SEQ_SHOW = 0x0040,
45 SYSFS_FLAG_HAS_MMAP = 0x0080,
46 SYSFS_FLAG_LOCKDEP = 0x0100,
47};
48
49/* type-specific structures for sysfs_dirent->s_* union members */
50struct sysfs_elem_dir {
51 unsigned long subdirs;
52 /* children rbtree starts here and goes through sd->s_rb */
53 struct rb_root children;
54
55 /*
56 * The kernfs hierarchy this directory belongs to. This fits
57 * better directly in sysfs_dirent but is here to save space.
58 */
59 struct kernfs_root *root;
60};
61
62struct sysfs_elem_symlink {
63 struct sysfs_dirent *target_sd;
64};
65
66struct sysfs_elem_attr {
67 const struct kernfs_ops *ops;
68 struct sysfs_open_dirent *open;
69 loff_t size;
70};
71
72/*
73 * sysfs_dirent - the building block of sysfs hierarchy. Each and every
74 * sysfs node is represented by single sysfs_dirent. Most fields are
75 * private to kernfs and shouldn't be accessed directly by kernfs users.
76 *
77 * As long as s_count reference is held, the sysfs_dirent itself is
78 * accessible. Dereferencing s_elem or any other outer entity
79 * requires s_active reference.
80 */
81struct sysfs_dirent {
82 atomic_t s_count;
83 atomic_t s_active;
84#ifdef CONFIG_DEBUG_LOCK_ALLOC
85 struct lockdep_map dep_map;
86#endif
87 /* the following two fields are published */
88 struct sysfs_dirent *s_parent;
89 const char *s_name;
90
91 struct rb_node s_rb;
92
93 union {
94 struct completion *completion;
95 struct sysfs_dirent *removed_list;
96 } u;
97
98 const void *s_ns; /* namespace tag */
99 unsigned int s_hash; /* ns + name hash */
100 union {
101 struct sysfs_elem_dir s_dir;
102 struct sysfs_elem_symlink s_symlink;
103 struct sysfs_elem_attr s_attr;
104 };
105
106 void *priv;
107
108 unsigned short s_flags;
109 umode_t s_mode;
110 unsigned int s_ino;
111 struct sysfs_inode_attrs *s_iattr;
112};
25 113
26struct kernfs_root { 114struct kernfs_root {
27 /* published fields */ 115 /* published fields */
@@ -82,6 +170,26 @@ struct kernfs_ops {
82 170
83#ifdef CONFIG_SYSFS 171#ifdef CONFIG_SYSFS
84 172
173static inline enum kernfs_node_type sysfs_type(struct sysfs_dirent *sd)
174{
175 return sd->s_flags & SYSFS_TYPE_MASK;
176}
177
178/**
179 * kernfs_enable_ns - enable namespace under a directory
180 * @sd: directory of interest, should be empty
181 *
182 * This is to be called right after @sd is created to enable namespace
183 * under it. All children of @sd must have non-NULL namespace tags and
184 * only the ones which match the super_block's tag will be visible.
185 */
186static inline void kernfs_enable_ns(struct sysfs_dirent *sd)
187{
188 WARN_ON_ONCE(sysfs_type(sd) != SYSFS_DIR);
189 WARN_ON_ONCE(!RB_EMPTY_ROOT(&sd->s_dir.children));
190 sd->s_flags |= SYSFS_FLAG_NS;
191}
192
85struct sysfs_dirent *kernfs_find_and_get_ns(struct sysfs_dirent *parent, 193struct sysfs_dirent *kernfs_find_and_get_ns(struct sysfs_dirent *parent,
86 const char *name, const void *ns); 194 const char *name, const void *ns);
87void kernfs_get(struct sysfs_dirent *sd); 195void kernfs_get(struct sysfs_dirent *sd);
@@ -107,7 +215,6 @@ int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name,
107 const void *ns); 215 const void *ns);
108int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, 216int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent,
109 const char *new_name, const void *new_ns); 217 const char *new_name, const void *new_ns);
110void kernfs_enable_ns(struct sysfs_dirent *sd);
111int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr); 218int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr);
112void kernfs_notify(struct sysfs_dirent *sd); 219void kernfs_notify(struct sysfs_dirent *sd);
113 220
@@ -120,6 +227,11 @@ void kernfs_init(void);
120 227
121#else /* CONFIG_SYSFS */ 228#else /* CONFIG_SYSFS */
122 229
230static inline enum kernfs_node_type sysfs_type(struct sysfs_dirent *sd)
231{ return 0; } /* whatever */
232
233static inline void kernfs_enable_ns(struct sysfs_dirent *sd) { }
234
123static inline struct sysfs_dirent * 235static inline struct sysfs_dirent *
124kernfs_find_and_get_ns(struct sysfs_dirent *parent, const char *name, 236kernfs_find_and_get_ns(struct sysfs_dirent *parent, const char *name,
125 const void *ns) 237 const void *ns)
@@ -161,8 +273,6 @@ static inline int kernfs_rename_ns(struct sysfs_dirent *sd,
161 const char *new_name, const void *new_ns) 273 const char *new_name, const void *new_ns)
162{ return -ENOSYS; } 274{ return -ENOSYS; }
163 275
164static inline void kernfs_enable_ns(struct sysfs_dirent *sd) { }
165
166static inline int kernfs_setattr(struct sysfs_dirent *sd, 276static inline int kernfs_setattr(struct sysfs_dirent *sd,
167 const struct iattr *iattr) 277 const struct iattr *iattr)
168{ return -ENOSYS; } 278{ return -ENOSYS; }