diff options
author | Tejun Heo <tj@kernel.org> | 2013-11-28 14:54:29 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-11-29 20:48:15 -0500 |
commit | 517e64f57883bd63c5a4ab8b3d0d3ed68c55d0cf (patch) | |
tree | 573f1e42c269ab32985511788a612ed3d7a99347 /fs/sysfs | |
parent | 2b25a62901a1af654c2604f19592b13742ad1601 (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>
Diffstat (limited to 'fs/sysfs')
-rw-r--r-- | fs/sysfs/dir.c | 4 | ||||
-rw-r--r-- | fs/sysfs/file.c | 35 | ||||
-rw-r--r-- | fs/sysfs/sysfs.h | 32 |
3 files changed, 27 insertions, 44 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 | */ |
59 | static const struct kernfs_ops *kernfs_ops(struct sysfs_dirent *sd) | 59 | static 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 | */ |
1006 | struct sysfs_dirent *kernfs_create_file_ns(struct sysfs_dirent *parent, | 1012 | struct 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 | ||
96 | static inline unsigned int sysfs_type(struct sysfs_dirent *sd) | 97 | static 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) \ | ||
104 | do { \ | ||
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 */ | ||
114 | static 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 | |||
125 | static 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 | */ |