proc, coredump: add CoreDumping flag to /proc/pid/status
[platform/kernel/linux-exynos.git] / drivers / base / core.c
index 12ebd05..1c67bf2 100644 (file)
@@ -217,6 +217,13 @@ struct device_link *device_link_add(struct device *consumer,
                        link->rpm_active = true;
                }
                pm_runtime_new_link(consumer);
+               /*
+                * If the link is being added by the consumer driver at probe
+                * time, balance the decrementation of the supplier's runtime PM
+                * usage counter after consumer probe in driver_probe_device().
+                */
+               if (consumer->links.status == DL_DEV_PROBING)
+                       pm_runtime_get_noresume(supplier);
        }
        get_device(supplier);
        link->supplier = supplier;
@@ -235,12 +242,12 @@ struct device_link *device_link_add(struct device *consumer,
                        switch (consumer->links.status) {
                        case DL_DEV_PROBING:
                                /*
-                                * Balance the decrementation of the supplier's
-                                * runtime PM usage counter after consumer probe
-                                * in driver_probe_device().
+                                * Some callers expect the link creation during
+                                * consumer driver probe to resume the supplier
+                                * even without DL_FLAG_RPM_ACTIVE.
                                 */
                                if (flags & DL_FLAG_PM_RUNTIME)
-                                       pm_runtime_get_sync(supplier);
+                                       pm_runtime_resume(supplier);
 
                                link->status = DL_STATE_CONSUMER_PROBE;
                                break;
@@ -313,6 +320,9 @@ static void __device_link_del(struct device_link *link)
        dev_info(link->consumer, "Dropping the link to %s\n",
                 dev_name(link->supplier));
 
+       if (link->flags & DL_FLAG_PM_RUNTIME)
+               pm_runtime_drop_link(link->consumer);
+
        list_del(&link->s_node);
        list_del(&link->c_node);
        device_link_free(link);
@@ -981,8 +991,14 @@ out:
 static ssize_t uevent_store(struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       if (kobject_synth_uevent(&dev->kobj, buf, count))
+       int rc;
+
+       rc = kobject_synth_uevent(&dev->kobj, buf, count);
+
+       if (rc) {
                dev_err(dev, "uevent: failed to send synthetic uevent\n");
+               return rc;
+       }
 
        return count;
 }
@@ -1458,7 +1474,7 @@ class_dir_create_and_add(struct class *class, struct kobject *parent_kobj)
 
        dir = kzalloc(sizeof(*dir), GFP_KERNEL);
        if (!dir)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        dir->class = class;
        kobject_init(&dir->kobj, &class_dir_ktype);
@@ -1468,7 +1484,7 @@ class_dir_create_and_add(struct class *class, struct kobject *parent_kobj)
        retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name);
        if (retval < 0) {
                kobject_put(&dir->kobj);
-               return NULL;
+               return ERR_PTR(retval);
        }
        return &dir->kobj;
 }
@@ -1561,6 +1577,8 @@ static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir)
                return;
 
        mutex_lock(&gdp_mutex);
+       if (!kobject_has_children(glue_dir))
+               kobject_del(glue_dir);
        kobject_put(glue_dir);
        mutex_unlock(&gdp_mutex);
 }
@@ -1775,6 +1793,10 @@ int device_add(struct device *dev)
 
        parent = get_device(dev->parent);
        kobj = get_device_parent(dev, parent);
+       if (IS_ERR(kobj)) {
+               error = PTR_ERR(kobj);
+               goto parent_error;
+       }
        if (kobj)
                dev->kobj.parent = kobj;
 
@@ -1873,6 +1895,7 @@ done:
        kobject_del(&dev->kobj);
  Error:
        cleanup_glue_dir(dev, glue_dir);
+parent_error:
        put_device(parent);
 name_error:
        kfree(dev->p);
@@ -1958,7 +1981,6 @@ void device_del(struct device *dev)
                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                                             BUS_NOTIFY_DEL_DEVICE, dev);
 
-       device_links_purge(dev);
        dpm_sysfs_remove(dev);
        if (parent)
                klist_del(&dev->p->knode_parent);
@@ -1986,6 +2008,7 @@ void device_del(struct device *dev)
        device_pm_remove(dev);
        driver_deferred_probe_del(dev);
        device_remove_properties(dev);
+       device_links_purge(dev);
 
        /* Notify the platform of the removal, in case they
         * need to do anything...
@@ -2692,6 +2715,11 @@ int device_move(struct device *dev, struct device *new_parent,
        device_pm_lock();
        new_parent = get_device(new_parent);
        new_parent_kobj = get_device_parent(dev, new_parent);
+       if (IS_ERR(new_parent_kobj)) {
+               error = PTR_ERR(new_parent_kobj);
+               put_device(new_parent);
+               goto out;
+       }
 
        pr_debug("device: '%s': %s: moving to '%s'\n", dev_name(dev),
                 __func__, new_parent ? dev_name(new_parent) : "<NULL>");
@@ -2763,6 +2791,9 @@ void device_shutdown(void)
 {
        struct device *dev, *parent;
 
+       wait_for_device_probe();
+       device_block_probing();
+
        spin_lock(&devices_kset->list_lock);
        /*
         * Walk the devices list backward, shutting down each in turn.