static ssize_t ccwgroup_ungroup_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct ccwgroup_device *gdev; int rc; gdev = to_ccwgroupdev(dev); /* Prevent concurrent online/offline processing and ungrouping. */ if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) return -EAGAIN; if (gdev->state != CCWGROUP_OFFLINE) { rc = -EINVAL; goto out; } /* Note that we cannot unregister the device from one of its * attribute methods, so we have to use this roundabout approach. */ rc = device_schedule_callback(dev, ccwgroup_ungroup_callback); out: if (rc) { if (rc != -EAGAIN) /* Release onoff "lock" when ungrouping failed. */ atomic_set(&gdev->onoff, 0); return rc; } return count; }
static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, void *data) { struct device *dev = data; if (action == BUS_NOTIFY_UNBIND_DRIVER) device_schedule_callback(dev, ccwgroup_ungroup_callback); return NOTIFY_OK; }
static ssize_t ccwgroup_ungroup_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct ccwgroup_device *gdev; int rc; gdev = to_ccwgroupdev(dev); if (gdev->state != CCWGROUP_OFFLINE) return -EINVAL; /* Note that we cannot unregister the device from one of its * attribute methods, so we have to use this roundabout approach. */ rc = device_schedule_callback(dev, ccwgroup_ungroup_callback); if (rc) count = rc; return count; }