Skip to content

Commit 356c05d

Browse files
AlanSterngregkh
authored andcommitted
sysfs: get rid of some lockdep false positives
This patch (as1554) fixes a lockdep false-positive report. The problem arises because lockdep is unable to deal with the tree-structured locks created by the device core and sysfs. This particular problem involves a sysfs attribute method that unregisters itself, not from the device it was called for, but from a descendant device. Lockdep doesn't understand the distinction and reports a possible deadlock, even though the operation is safe. This is the sort of thing that would normally be handled by using a nested lock annotation; unfortunately it's not feasible to do that here. There's no sensible way to tell sysfs when attribute removal occurs in the context of a parent attribute method. As a workaround, the patch adds a new flag to struct attribute telling sysfs not to inform lockdep when it acquires a readlock on a sysfs_dirent instance for the attribute. The readlock is still acquired, but lockdep doesn't know about it and hence does not complain about impossible deadlock scenarios. Also added are macros for static initialization of attribute structures with the ignore_lockdep flag set. The three offending attributes in the USB subsystem are converted to use the new macros. Signed-off-by: Alan Stern <[email protected]> Acked-by: Tejun Heo <[email protected]> CC: Eric W. Biederman <[email protected]> CC: Peter Zijlstra <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent c836d0a commit 356c05d

File tree

4 files changed

+44
-8
lines changed

4 files changed

+44
-8
lines changed

drivers/usb/core/sysfs.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
7373
return (value < 0) ? value : count;
7474
}
7575

76-
static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR,
76+
static DEVICE_ATTR_IGNORE_LOCKDEP(bConfigurationValue, S_IRUGO | S_IWUSR,
7777
show_bConfigurationValue, set_bConfigurationValue);
7878

7979
/* String fields */
@@ -595,7 +595,7 @@ static ssize_t usb_dev_authorized_store(struct device *dev,
595595
return result < 0? result : size;
596596
}
597597

598-
static DEVICE_ATTR(authorized, 0644,
598+
static DEVICE_ATTR_IGNORE_LOCKDEP(authorized, 0644,
599599
usb_dev_authorized_show, usb_dev_authorized_store);
600600

601601
/* "Safely remove a device" */
@@ -618,7 +618,7 @@ static ssize_t usb_remove_store(struct device *dev,
618618
usb_unlock_device(udev);
619619
return rc;
620620
}
621-
static DEVICE_ATTR(remove, 0200, NULL, usb_remove_store);
621+
static DEVICE_ATTR_IGNORE_LOCKDEP(remove, 0200, NULL, usb_remove_store);
622622

623623

624624
static struct attribute *dev_attrs[] = {

fs/sysfs/dir.c

+26-5
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,24 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
132132
rb_erase(&sd->s_rb, &sd->s_parent->s_dir.children);
133133
}
134134

135+
#ifdef CONFIG_DEBUG_LOCK_ALLOC
136+
137+
/* Test for attributes that want to ignore lockdep for read-locking */
138+
static bool ignore_lockdep(struct sysfs_dirent *sd)
139+
{
140+
return sysfs_type(sd) == SYSFS_KOBJ_ATTR &&
141+
sd->s_attr.attr->ignore_lockdep;
142+
}
143+
144+
#else
145+
146+
static inline bool ignore_lockdep(struct sysfs_dirent *sd)
147+
{
148+
return true;
149+
}
150+
151+
#endif
152+
135153
/**
136154
* sysfs_get_active - get an active reference to sysfs_dirent
137155
* @sd: sysfs_dirent to get an active reference to
@@ -155,15 +173,17 @@ struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd)
155173
return NULL;
156174

157175
t = atomic_cmpxchg(&sd->s_active, v, v + 1);
158-
if (likely(t == v)) {
159-
rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_);
160-
return sd;
161-
}
176+
if (likely(t == v))
177+
break;
162178
if (t < 0)
163179
return NULL;
164180

165181
cpu_relax();
166182
}
183+
184+
if (likely(!ignore_lockdep(sd)))
185+
rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_);
186+
return sd;
167187
}
168188

169189
/**
@@ -180,7 +200,8 @@ void sysfs_put_active(struct sysfs_dirent *sd)
180200
if (unlikely(!sd))
181201
return;
182202

183-
rwsem_release(&sd->dep_map, 1, _RET_IP_);
203+
if (likely(!ignore_lockdep(sd)))
204+
rwsem_release(&sd->dep_map, 1, _RET_IP_);
184205
v = atomic_dec_return(&sd->s_active);
185206
if (likely(v != SD_DEACTIVATED_BIAS))
186207
return;

include/linux/device.h

+3
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,9 @@ ssize_t device_store_int(struct device *dev, struct device_attribute *attr,
504504
#define DEVICE_INT_ATTR(_name, _mode, _var) \
505505
struct dev_ext_attribute dev_attr_##_name = \
506506
{ __ATTR(_name, _mode, device_show_int, device_store_int), &(_var) }
507+
#define DEVICE_ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) \
508+
struct device_attribute dev_attr_##_name = \
509+
__ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store)
507510

508511
extern int device_create_file(struct device *device,
509512
const struct device_attribute *entry);

include/linux/sysfs.h

+12
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ struct attribute {
2727
const char *name;
2828
umode_t mode;
2929
#ifdef CONFIG_DEBUG_LOCK_ALLOC
30+
bool ignore_lockdep:1;
3031
struct lock_class_key *key;
3132
struct lock_class_key skey;
3233
#endif
@@ -80,6 +81,17 @@ struct attribute_group {
8081

8182
#define __ATTR_NULL { .attr = { .name = NULL } }
8283

84+
#ifdef CONFIG_DEBUG_LOCK_ALLOC
85+
#define __ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) { \
86+
.attr = {.name = __stringify(_name), .mode = _mode, \
87+
.ignore_lockdep = true }, \
88+
.show = _show, \
89+
.store = _store, \
90+
}
91+
#else
92+
#define __ATTR_IGNORE_LOCKDEP __ATTR
93+
#endif
94+
8395
#define attr_name(_attr) (_attr).attr.name
8496

8597
struct file;

0 commit comments

Comments
 (0)