OSDN Git Service

kobject_uevent: Allocate environment buffer on the stack
authorSultan Alsawaf <sultan@kerneltoast.com>
Thu, 1 Aug 2019 01:27:02 +0000 (18:27 -0700)
committer0ranko0P <ranko0p@outlook.com>
Sat, 7 Dec 2019 10:22:19 +0000 (18:22 +0800)
The environment buffer isn't very big; when it's allocated on the stack,
kobject_uevent_env's stack frame size increases to just over 2 KiB,
which is safe considering that we have a 16 KiB stack.

Allocate the environment buffer on the stack instead of using the slab
allocator in order to improve performance.

Signed-off-by: Sultan Alsawaf <sultan@kerneltoast.com>
lib/kobject_uevent.c

index f6c2c1e..3e1926e 100644 (file)
@@ -164,7 +164,7 @@ static void cleanup_uevent_env(struct subprocess_info *info)
 int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
                       char *envp_ext[])
 {
-       struct kobj_uevent_env *env;
+       struct kobj_uevent_env env;
        const char *action_string = kobject_actions[action];
        const char *devpath = NULL;
        const char *subsystem;
@@ -223,11 +223,6 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
                return 0;
        }
 
-       /* environment buffer */
-       env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
-       if (!env)
-               return -ENOMEM;
-
        /* complete object path */
        devpath = kobject_get_path(kobj, GFP_KERNEL);
        if (!devpath) {
@@ -235,21 +230,23 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
                goto exit;
        }
 
+       memset(&env, 0, sizeof(env));
+
        /* default keys */
-       retval = add_uevent_var(env, "ACTION=%s", action_string);
+       retval = add_uevent_var(&env, "ACTION=%s", action_string);
        if (retval)
                goto exit;
-       retval = add_uevent_var(env, "DEVPATH=%s", devpath);
+       retval = add_uevent_var(&env, "DEVPATH=%s", devpath);
        if (retval)
                goto exit;
-       retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
+       retval = add_uevent_var(&env, "SUBSYSTEM=%s", subsystem);
        if (retval)
                goto exit;
 
        /* keys passed in from the caller */
        if (envp_ext) {
                for (i = 0; envp_ext[i]; i++) {
-                       retval = add_uevent_var(env, "%s", envp_ext[i]);
+                       retval = add_uevent_var(&env, "%s", envp_ext[i]);
                        if (retval)
                                goto exit;
                }
@@ -257,7 +254,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
 
        /* let the kset specific function add its stuff */
        if (uevent_ops && uevent_ops->uevent) {
-               retval = uevent_ops->uevent(kset, kobj, env);
+               retval = uevent_ops->uevent(kset, kobj, &env);
                if (retval) {
                        pr_debug("kobject: '%s' (%p): %s: uevent() returned "
                                 "%d\n", kobject_name(kobj), kobj,
@@ -279,7 +276,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
 
        mutex_lock(&uevent_sock_mutex);
        /* we will send an event, so request a new sequence number */
-       retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)++uevent_seqnum);
+       retval = add_uevent_var(&env, "SEQNUM=%llu", (unsigned long long)++uevent_seqnum);
        if (retval) {
                mutex_unlock(&uevent_sock_mutex);
                goto exit;
@@ -297,7 +294,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
 
                /* allocate message with the maximum possible size */
                len = strlen(action_string) + strlen(devpath) + 2;
-               skb = alloc_skb(len + env->buflen, GFP_KERNEL);
+               skb = alloc_skb(len + env.buflen, GFP_KERNEL);
                if (skb) {
                        char *scratch;
 
@@ -306,10 +303,10 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
                        sprintf(scratch, "%s@%s", action_string, devpath);
 
                        /* copy keys to our continuous event payload buffer */
-                       for (i = 0; i < env->envp_idx; i++) {
-                               len = strlen(env->envp[i]) + 1;
+                       for (i = 0; i < env.envp_idx; i++) {
+                               len = strlen(env.envp[i]) + 1;
                                scratch = skb_put(skb, len);
-                               strcpy(scratch, env->envp[i]);
+                               strcpy(scratch, env.envp[i]);
                        }
 
                        NETLINK_CB(skb).dst_group = 1;
@@ -331,31 +328,28 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
        if (uevent_helper[0] && !kobj_usermode_filter(kobj)) {
                struct subprocess_info *info;
 
-               retval = add_uevent_var(env, "HOME=/");
+               retval = add_uevent_var(&env, "HOME=/");
                if (retval)
                        goto exit;
-               retval = add_uevent_var(env,
+               retval = add_uevent_var(&env,
                                        "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
                if (retval)
                        goto exit;
-               retval = init_uevent_argv(env, subsystem);
+               retval = init_uevent_argv(&env, subsystem);
                if (retval)
                        goto exit;
 
                retval = -ENOMEM;
-               info = call_usermodehelper_setup(env->argv[0], env->argv,
-                                                env->envp, GFP_KERNEL,
-                                                NULL, cleanup_uevent_env, env);
-               if (info) {
+               info = call_usermodehelper_setup(env.argv[0], env.argv,
+                                                env.envp, GFP_KERNEL,
+                                                NULL, cleanup_uevent_env, &env);
+               if (info)
                        retval = call_usermodehelper_exec(info, UMH_NO_WAIT);
-                       env = NULL;     /* freed by cleanup_uevent_env */
-               }
        }
 #endif
 
 exit:
        kfree(devpath);
-       kfree(env);
        return retval;
 }
 EXPORT_SYMBOL_GPL(kobject_uevent_env);