static ssize_t store_mem_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct memory_block *mem = to_memory_block(dev); int ret, online_type; ret = lock_device_hotplug_sysfs(); if (ret) return ret; if (sysfs_streq(buf, "online_kernel")) online_type = MMOP_ONLINE_KERNEL; else if (sysfs_streq(buf, "online_movable")) online_type = MMOP_ONLINE_MOVABLE; else if (sysfs_streq(buf, "online")) online_type = MMOP_ONLINE_KEEP; else if (sysfs_streq(buf, "offline")) online_type = MMOP_OFFLINE; else { ret = -EINVAL; goto err; } /* * Memory hotplug needs to hold mem_hotplug_begin() for probe to find * the correct memory block to online before doing device_online(dev), * which will take dev->mutex. Take the lock early to prevent an * inversion, memory_subsys_online() callbacks will be implemented by * assuming it's already protected. */ mem_hotplug_begin(); switch (online_type) { case MMOP_ONLINE_KERNEL: case MMOP_ONLINE_MOVABLE: case MMOP_ONLINE_KEEP: mem->online_type = online_type; ret = device_online(&mem->dev); break; case MMOP_OFFLINE: ret = device_offline(&mem->dev); break; default: ret = -EINVAL; /* should never happen */ } mem_hotplug_done(); err: unlock_device_hotplug(); if (ret) return ret; return count; }
static ssize_t store_mem_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct memory_block *mem = to_memory_block(dev); int ret, online_type; ret = lock_device_hotplug_sysfs(); if (ret) return ret; if (sysfs_streq(buf, "online_kernel")) online_type = MMOP_ONLINE_KERNEL; else if (sysfs_streq(buf, "online_movable")) online_type = MMOP_ONLINE_MOVABLE; else if (sysfs_streq(buf, "online")) online_type = MMOP_ONLINE_KEEP; else if (sysfs_streq(buf, "offline")) online_type = MMOP_OFFLINE; else { ret = -EINVAL; goto err; } switch (online_type) { case MMOP_ONLINE_KERNEL: case MMOP_ONLINE_MOVABLE: case MMOP_ONLINE_KEEP: /* * mem->online_type is not protected so there can be a * race here. However, when racing online, the first * will succeed and the second will just return as the * block will already be online. The online type * could be either one, but that is expected. */ mem->online_type = online_type; ret = device_online(&mem->dev); break; case MMOP_OFFLINE: ret = device_offline(&mem->dev); break; default: ret = -EINVAL; /* should never happen */ } err: unlock_device_hotplug(); if (ret) return ret; return count; }
static ssize_t cpu_probe_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { ssize_t cnt; int ret; ret = lock_device_hotplug_sysfs(); if (ret) return ret; cnt = arch_cpu_probe(buf, count); unlock_device_hotplug(); return cnt; }
static ssize_t write_cpuhp_target(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id); struct cpuhp_step *sp; int target, ret; ret = kstrtoint(buf, 10, &target); if (ret) return ret; #ifdef CONFIG_CPU_HOTPLUG_STATE_CONTROL if (target < CPUHP_OFFLINE || target > CPUHP_ONLINE) return -EINVAL; #else if (target != CPUHP_OFFLINE && target != CPUHP_ONLINE) return -EINVAL; #endif ret = lock_device_hotplug_sysfs(); if (ret) return ret; mutex_lock(&cpuhp_state_mutex); sp = cpuhp_get_step(target); ret = !sp->name || sp->cant_stop ? -EINVAL : 0; mutex_unlock(&cpuhp_state_mutex); if (ret) return ret; if (st->state < target) ret = do_cpu_up(dev->id, target); else ret = do_cpu_down(dev->id, target); unlock_device_hotplug(); return ret ? ret : count; }