aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-11-28 14:54:29 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-11-29 20:48:15 -0500
commit517e64f57883bd63c5a4ab8b3d0d3ed68c55d0cf (patch)
tree573f1e42c269ab32985511788a612ed3d7a99347
parent2b25a62901a1af654c2604f19592b13742ad1601 (diff)
sysfs, kernfs: revamp sysfs_dirent active_ref lockdep annotation
Currently, sysfs_dirent active_ref lockdep annotation uses attribute->[s]key as the lockdep key, which forces kernfs_create_file_ns() to assume that sysfs_dirent->priv is pointing to a struct attribute which may not be true for non-sysfs users. This patch restructures the lockdep annotation such that * kernfs_ops contains lockdep_key which is used by default for files created kernfs_create_file_ns(). * kernfs_create_file_ns_key() is introduced which takes an extra @key argument. The created file will use the specified key for active_ref lockdep annotation. If NULL is specified, lockdep for the file is disabled. * sysfs_add_file_mode_ns() is updated to use kernfs_create_file_ns_key() with the appropriate key from the attribute or NULL if ignore_lockdep is set. This makes the lockdep annotation properly contained in kernfs while allowing sysfs to cleanly keep its current behavior. This patch doesn't introduce any behavior differences. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--fs/sysfs/dir.c4
-rw-r--r--fs/sysfs/file.c35
-rw-r--r--fs/sysfs/sysfs.h32
-rw-r--r--include/linux/kernfs.h37
4 files changed, 56 insertions, 52 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index e88e9a94a083..8f2d577b5f64 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -150,7 +150,7 @@ struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd)
150 if (!atomic_inc_unless_negative(&sd->s_active)) 150 if (!atomic_inc_unless_negative(&sd->s_active))
151 return NULL; 151 return NULL;
152 152
153 if (likely(!sysfs_ignore_lockdep(sd))) 153 if (sd->s_flags & SYSFS_FLAG_LOCKDEP)
154 rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_); 154 rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_);
155 return sd; 155 return sd;
156} 156}
@@ -169,7 +169,7 @@ void sysfs_put_active(struct sysfs_dirent *sd)
169 if (unlikely(!sd)) 169 if (unlikely(!sd))
170 return; 170 return;
171 171
172 if (likely(!sysfs_ignore_lockdep(sd))) 172 if (sd->s_flags & SYSFS_FLAG_LOCKDEP)
173 rwsem_release(&sd->dep_map, 1, _RET_IP_); 173 rwsem_release(&sd->dep_map, 1, _RET_IP_);
174 v = atomic_dec_return(&sd->s_active); 174 v = atomic_dec_return(&sd->s_active);
175 if (likely(v != SD_DEACTIVATED_BIAS)) 175 if (likely(v != SD_DEACTIVATED_BIAS))
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index a68cbef3a674..e4eca285b390 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -58,7 +58,7 @@ static struct sysfs_open_file *sysfs_of(struct file *file)
58 */ 58 */
59static const struct kernfs_ops *kernfs_ops(struct sysfs_dirent *sd) 59static const struct kernfs_ops *kernfs_ops(struct sysfs_dirent *sd)
60{ 60{
61 if (!sysfs_ignore_lockdep(sd)) 61 if (sd->s_flags & SYSFS_FLAG_LOCKDEP)
62 lockdep_assert_held(sd); 62 lockdep_assert_held(sd);
63 return sd->s_attr.ops; 63 return sd->s_attr.ops;
64} 64}
@@ -71,7 +71,7 @@ static const struct sysfs_ops *sysfs_file_ops(struct sysfs_dirent *sd)
71{ 71{
72 struct kobject *kobj = sd->s_parent->priv; 72 struct kobject *kobj = sd->s_parent->priv;
73 73
74 if (!sysfs_ignore_lockdep(sd)) 74 if (sd->s_flags & SYSFS_FLAG_LOCKDEP)
75 lockdep_assert_held(sd); 75 lockdep_assert_held(sd);
76 return kobj->ktype ? kobj->ktype->sysfs_ops : NULL; 76 return kobj->ktype ? kobj->ktype->sysfs_ops : NULL;
77} 77}
@@ -942,6 +942,7 @@ int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd,
942 const struct attribute *attr, bool is_bin, 942 const struct attribute *attr, bool is_bin,
943 umode_t mode, const void *ns) 943 umode_t mode, const void *ns)
944{ 944{
945 struct lock_class_key *key = NULL;
945 const struct kernfs_ops *ops; 946 const struct kernfs_ops *ops;
946 struct sysfs_dirent *sd; 947 struct sysfs_dirent *sd;
947 loff_t size; 948 loff_t size;
@@ -981,8 +982,12 @@ int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd,
981 size = battr->size; 982 size = battr->size;
982 } 983 }
983 984
984 sd = kernfs_create_file_ns(dir_sd, attr->name, mode, size, 985#ifdef CONFIG_DEBUG_LOCK_ALLOC
985 ops, (void *)attr, ns); 986 if (!attr->ignore_lockdep)
987 key = attr->key ?: (struct lock_class_key *)&attr->skey;
988#endif
989 sd = kernfs_create_file_ns_key(dir_sd, attr->name, mode, size,
990 ops, (void *)attr, ns, key);
986 if (IS_ERR(sd)) { 991 if (IS_ERR(sd)) {
987 if (PTR_ERR(sd) == -EEXIST) 992 if (PTR_ERR(sd) == -EEXIST)
988 sysfs_warn_dup(dir_sd, attr->name); 993 sysfs_warn_dup(dir_sd, attr->name);
@@ -992,7 +997,7 @@ int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd,
992} 997}
993 998
994/** 999/**
995 * kernfs_create_file_ns - create a file 1000 * kernfs_create_file_ns_key - create a file
996 * @parent: directory to create the file in 1001 * @parent: directory to create the file in
997 * @name: name of the file 1002 * @name: name of the file
998 * @mode: mode of the file 1003 * @mode: mode of the file
@@ -1000,14 +1005,16 @@ int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd,
1000 * @ops: kernfs operations for the file 1005 * @ops: kernfs operations for the file
1001 * @priv: private data for the file 1006 * @priv: private data for the file
1002 * @ns: optional namespace tag of the file 1007 * @ns: optional namespace tag of the file
1008 * @key: lockdep key for the file's active_ref, %NULL to disable lockdep
1003 * 1009 *
1004 * Returns the created node on success, ERR_PTR() value on error. 1010 * Returns the created node on success, ERR_PTR() value on error.
1005 */ 1011 */
1006struct sysfs_dirent *kernfs_create_file_ns(struct sysfs_dirent *parent, 1012struct sysfs_dirent *kernfs_create_file_ns_key(struct sysfs_dirent *parent,
1007 const char *name, 1013 const char *name,
1008 umode_t mode, loff_t size, 1014 umode_t mode, loff_t size,
1009 const struct kernfs_ops *ops, 1015 const struct kernfs_ops *ops,
1010 void *priv, const void *ns) 1016 void *priv, const void *ns,
1017 struct lock_class_key *key)
1011{ 1018{
1012 struct sysfs_addrm_cxt acxt; 1019 struct sysfs_addrm_cxt acxt;
1013 struct sysfs_dirent *sd; 1020 struct sysfs_dirent *sd;
@@ -1022,7 +1029,13 @@ struct sysfs_dirent *kernfs_create_file_ns(struct sysfs_dirent *parent,
1022 sd->s_attr.size = size; 1029 sd->s_attr.size = size;
1023 sd->s_ns = ns; 1030 sd->s_ns = ns;
1024 sd->priv = priv; 1031 sd->priv = priv;
1025 sysfs_dirent_init_lockdep(sd); 1032
1033#ifdef CONFIG_DEBUG_LOCK_ALLOC
1034 if (key) {
1035 lockdep_init_map(&sd->dep_map, "s_active", key, 0);
1036 sd->s_flags |= SYSFS_FLAG_LOCKDEP;
1037 }
1038#endif
1026 1039
1027 /* 1040 /*
1028 * sd->s_attr.ops is accesible only while holding active ref. We 1041 * sd->s_attr.ops is accesible only while holding active ref. We
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index c86456c9b19e..e93f8b845611 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -92,43 +92,13 @@ struct sysfs_dirent {
92#define SYSFS_FLAG_NS 0x0020 92#define SYSFS_FLAG_NS 0x0020
93#define SYSFS_FLAG_HAS_SEQ_SHOW 0x0040 93#define SYSFS_FLAG_HAS_SEQ_SHOW 0x0040
94#define SYSFS_FLAG_HAS_MMAP 0x0080 94#define SYSFS_FLAG_HAS_MMAP 0x0080
95#define SYSFS_FLAG_LOCKDEP 0x0100
95 96
96static inline unsigned int sysfs_type(struct sysfs_dirent *sd) 97static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
97{ 98{
98 return sd->s_flags & SYSFS_TYPE_MASK; 99 return sd->s_flags & SYSFS_TYPE_MASK;
99} 100}
100 101
101#ifdef CONFIG_DEBUG_LOCK_ALLOC
102
103#define sysfs_dirent_init_lockdep(sd) \
104do { \
105 struct attribute *attr = sd->priv; \
106 struct lock_class_key *key = attr->key; \
107 if (!key) \
108 key = &attr->skey; \
109 \
110 lockdep_init_map(&sd->dep_map, "s_active", key, 0); \
111} while (0)
112
113/* Test for attributes that want to ignore lockdep for read-locking */
114static inline bool sysfs_ignore_lockdep(struct sysfs_dirent *sd)
115{
116 struct attribute *attr = sd->priv;
117
118 return sysfs_type(sd) == SYSFS_KOBJ_ATTR && attr->ignore_lockdep;
119}
120
121#else
122
123#define sysfs_dirent_init_lockdep(sd) do {} while (0)
124
125static inline bool sysfs_ignore_lockdep(struct sysfs_dirent *sd)
126{
127 return true;
128}
129
130#endif
131
132/* 102/*
133 * Context structure to be used while adding/removing nodes. 103 * Context structure to be used while adding/removing nodes.
134 */ 104 */
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index f20796ecc76e..105d09dcb064 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -11,6 +11,7 @@
11#include <linux/err.h> 11#include <linux/err.h>
12#include <linux/list.h> 12#include <linux/list.h>
13#include <linux/mutex.h> 13#include <linux/mutex.h>
14#include <linux/lockdep.h>
14 15
15struct file; 16struct file;
16struct iattr; 17struct iattr;
@@ -62,6 +63,10 @@ struct kernfs_ops {
62 loff_t off); 63 loff_t off);
63 64
64 int (*mmap)(struct sysfs_open_file *of, struct vm_area_struct *vma); 65 int (*mmap)(struct sysfs_open_file *of, struct vm_area_struct *vma);
66
67#ifdef CONFIG_DEBUG_LOCK_ALLOC
68 struct lock_class_key lockdep_key;
69#endif
65}; 70};
66 71
67#ifdef CONFIG_SYSFS 72#ifdef CONFIG_SYSFS
@@ -69,11 +74,12 @@ struct kernfs_ops {
69struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, 74struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent,
70 const char *name, void *priv, 75 const char *name, void *priv,
71 const void *ns); 76 const void *ns);
72struct sysfs_dirent *kernfs_create_file_ns(struct sysfs_dirent *parent, 77struct sysfs_dirent *kernfs_create_file_ns_key(struct sysfs_dirent *parent,
73 const char *name, 78 const char *name,
74 umode_t mode, loff_t size, 79 umode_t mode, loff_t size,
75 const struct kernfs_ops *ops, 80 const struct kernfs_ops *ops,
76 void *priv, const void *ns); 81 void *priv, const void *ns,
82 struct lock_class_key *key);
77struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, 83struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent,
78 const char *name, 84 const char *name,
79 struct sysfs_dirent *target); 85 struct sysfs_dirent *target);
@@ -94,9 +100,10 @@ kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv,
94{ return ERR_PTR(-ENOSYS); } 100{ return ERR_PTR(-ENOSYS); }
95 101
96static inline struct sysfs_dirent * 102static inline struct sysfs_dirent *
97kernfs_create_file_ns(struct sysfs_dirent *parent, const char *name, 103kernfs_create_file_ns_key(struct sysfs_dirent *parent, const char *name,
98 umode_t mode, loff_t size, const struct kernfs_ops *ops, 104 umode_t mode, loff_t size,
99 void *priv, const void *ns) 105 const struct kernfs_ops *ops, void *priv,
106 const void *ns, struct lock_class_key *key)
100{ return ERR_PTR(-ENOSYS); } 107{ return ERR_PTR(-ENOSYS); }
101 108
102static inline struct sysfs_dirent * 109static inline struct sysfs_dirent *
@@ -132,6 +139,20 @@ kernfs_create_dir(struct sysfs_dirent *parent, const char *name, void *priv)
132} 139}
133 140
134static inline struct sysfs_dirent * 141static inline struct sysfs_dirent *
142kernfs_create_file_ns(struct sysfs_dirent *parent, const char *name,
143 umode_t mode, loff_t size, const struct kernfs_ops *ops,
144 void *priv, const void *ns)
145{
146 struct lock_class_key *key = NULL;
147
148#ifdef CONFIG_DEBUG_LOCK_ALLOC
149 key = (struct lock_class_key *)&ops->lockdep_key;
150#endif
151 return kernfs_create_file_ns_key(parent, name, mode, size, ops, priv,
152 ns, key);
153}
154
155static inline struct sysfs_dirent *
135kernfs_create_file(struct sysfs_dirent *parent, const char *name, umode_t mode, 156kernfs_create_file(struct sysfs_dirent *parent, const char *name, umode_t mode,
136 loff_t size, const struct kernfs_ops *ops, void *priv) 157 loff_t size, const struct kernfs_ops *ops, void *priv)
137{ 158{