if (!atomic_inc_unless_negative(&sd->s_active))
return NULL;
- if (likely(!sysfs_ignore_lockdep(sd)))
+ if (sd->s_flags & SYSFS_FLAG_LOCKDEP)
rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_);
return sd;
}
if (unlikely(!sd))
return;
- if (likely(!sysfs_ignore_lockdep(sd)))
+ if (sd->s_flags & SYSFS_FLAG_LOCKDEP)
rwsem_release(&sd->dep_map, 1, _RET_IP_);
v = atomic_dec_return(&sd->s_active);
if (likely(v != SD_DEACTIVATED_BIAS))
*/
static const struct kernfs_ops *kernfs_ops(struct sysfs_dirent *sd)
{
- if (!sysfs_ignore_lockdep(sd))
+ if (sd->s_flags & SYSFS_FLAG_LOCKDEP)
lockdep_assert_held(sd);
return sd->s_attr.ops;
}
{
struct kobject *kobj = sd->s_parent->priv;
- if (!sysfs_ignore_lockdep(sd))
+ if (sd->s_flags & SYSFS_FLAG_LOCKDEP)
lockdep_assert_held(sd);
return kobj->ktype ? kobj->ktype->sysfs_ops : NULL;
}
const struct attribute *attr, bool is_bin,
umode_t mode, const void *ns)
{
+ struct lock_class_key *key = NULL;
const struct kernfs_ops *ops;
struct sysfs_dirent *sd;
loff_t size;
size = battr->size;
}
- sd = kernfs_create_file_ns(dir_sd, attr->name, mode, size,
- ops, (void *)attr, ns);
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+ if (!attr->ignore_lockdep)
+ key = attr->key ?: (struct lock_class_key *)&attr->skey;
+#endif
+ sd = kernfs_create_file_ns_key(dir_sd, attr->name, mode, size,
+ ops, (void *)attr, ns, key);
if (IS_ERR(sd)) {
if (PTR_ERR(sd) == -EEXIST)
sysfs_warn_dup(dir_sd, attr->name);
}
/**
- * kernfs_create_file_ns - create a file
+ * kernfs_create_file_ns_key - create a file
* @parent: directory to create the file in
* @name: name of the file
* @mode: mode of the file
* @ops: kernfs operations for the file
* @priv: private data for the file
* @ns: optional namespace tag of the file
+ * @key: lockdep key for the file's active_ref, %NULL to disable lockdep
*
* Returns the created node on success, ERR_PTR() value on error.
*/
-struct sysfs_dirent *kernfs_create_file_ns(struct sysfs_dirent *parent,
- const char *name,
- umode_t mode, loff_t size,
- const struct kernfs_ops *ops,
- void *priv, const void *ns)
+struct sysfs_dirent *kernfs_create_file_ns_key(struct sysfs_dirent *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)
{
struct sysfs_addrm_cxt acxt;
struct sysfs_dirent *sd;
sd->s_attr.size = size;
sd->s_ns = ns;
sd->priv = priv;
- sysfs_dirent_init_lockdep(sd);
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+ if (key) {
+ lockdep_init_map(&sd->dep_map, "s_active", key, 0);
+ sd->s_flags |= SYSFS_FLAG_LOCKDEP;
+ }
+#endif
/*
* sd->s_attr.ops is accesible only while holding active ref. We
#define SYSFS_FLAG_NS 0x0020
#define SYSFS_FLAG_HAS_SEQ_SHOW 0x0040
#define SYSFS_FLAG_HAS_MMAP 0x0080
+#define SYSFS_FLAG_LOCKDEP 0x0100
static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
{
return sd->s_flags & SYSFS_TYPE_MASK;
}
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-
-#define sysfs_dirent_init_lockdep(sd) \
-do { \
- struct attribute *attr = sd->priv; \
- struct lock_class_key *key = attr->key; \
- if (!key) \
- key = &attr->skey; \
- \
- lockdep_init_map(&sd->dep_map, "s_active", key, 0); \
-} while (0)
-
-/* Test for attributes that want to ignore lockdep for read-locking */
-static inline bool sysfs_ignore_lockdep(struct sysfs_dirent *sd)
-{
- struct attribute *attr = sd->priv;
-
- return sysfs_type(sd) == SYSFS_KOBJ_ATTR && attr->ignore_lockdep;
-}
-
-#else
-
-#define sysfs_dirent_init_lockdep(sd) do {} while (0)
-
-static inline bool sysfs_ignore_lockdep(struct sysfs_dirent *sd)
-{
- return true;
-}
-
-#endif
-
/*
* Context structure to be used while adding/removing nodes.
*/
#include <linux/err.h>
#include <linux/list.h>
#include <linux/mutex.h>
+#include <linux/lockdep.h>
struct file;
struct iattr;
loff_t off);
int (*mmap)(struct sysfs_open_file *of, struct vm_area_struct *vma);
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+ struct lock_class_key lockdep_key;
+#endif
};
#ifdef CONFIG_SYSFS
struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent,
const char *name, void *priv,
const void *ns);
-struct sysfs_dirent *kernfs_create_file_ns(struct sysfs_dirent *parent,
- const char *name,
- umode_t mode, loff_t size,
- const struct kernfs_ops *ops,
- void *priv, const void *ns);
+struct sysfs_dirent *kernfs_create_file_ns_key(struct sysfs_dirent *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);
struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent,
const char *name,
struct sysfs_dirent *target);
{ return ERR_PTR(-ENOSYS); }
static inline struct sysfs_dirent *
-kernfs_create_file_ns(struct sysfs_dirent *parent, const char *name,
- umode_t mode, loff_t size, const struct kernfs_ops *ops,
- void *priv, const void *ns)
+kernfs_create_file_ns_key(struct sysfs_dirent *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)
{ return ERR_PTR(-ENOSYS); }
static inline struct sysfs_dirent *
return kernfs_create_dir_ns(parent, name, priv, NULL);
}
+static inline struct sysfs_dirent *
+kernfs_create_file_ns(struct sysfs_dirent *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_ns_key(parent, name, mode, size, ops, priv,
+ ns, key);
+}
+
static inline struct sysfs_dirent *
kernfs_create_file(struct sysfs_dirent *parent, const char *name, umode_t mode,
loff_t size, const struct kernfs_ops *ops, void *priv)