Name: Kobject Devpath Sanity Patch Author: Rusty Russell Status: Tested in userspace. Depends: Misc/kobject-style.patch.gz D: The code to set the DEVPATH environment variable measures it first, D: kmallocs that amount, copies it in, then sprintfs that into a D: fixed-length buffer. Avoid this dance, and copy it straight into D: the buffer. Also, put the env. vars on the stack: they're a little D: large on 64-bit plaforms (256 bytes), but not too bad. Result is D: that we only do one kmalloc. diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .26668-2.5.70-bk18-kobject-sanity.pre/lib/kobject.c .26668-2.5.70-bk18-kobject-sanity/lib/kobject.c --- .26668-2.5.70-bk18-kobject-sanity.pre/lib/kobject.c 2003-06-14 16:40:22.000000000 +1000 +++ .26668-2.5.70-bk18-kobject-sanity/lib/kobject.c 2003-06-14 16:40:22.000000000 +1000 @@ -66,51 +66,43 @@ static inline struct kobject * to_kobj(s #ifdef CONFIG_HOTPLUG -static int get_kobj_path_length(struct kset *kset, struct kobject *kobj) +/* Returns bytes used, including trailing NUL. Assumes length > 0. */ +static unsigned int fill_kobj_path(struct kobject *kobj, + char *path, + unsigned int length) { - int length = 1; - struct kobject * parent = kobj; - - /* walk up the ancestors until we hit the one pointing to the - * root. - * Add 1 to strlen for leading '/' of each level. - */ - do { - length += strlen(parent->name) + 1; - parent = parent->parent; - } while (parent); - return length; -} + struct kobject *i; + unsigned int used = 0; -static void fill_kobj_path(struct kset *kset, struct kobject *kobj, char *path, int length) -{ - struct kobject * parent; + /* This is tricky without recursion, since we're going backwards. */ + for (i = kobj; i; i = i->parent) { + /* Too long? Finish here. */ + if (used + 1 + strlen(i->name) + 1 > length) + break; - --length; - for (parent = kobj; parent; parent = parent->parent) { - int cur = strlen(parent->name); - /* back up enough to print this name with '/' */ - length -= cur; - strncpy(path + length, parent->name, cur); - *(path + --length) = '/'; + /* Prepend /. */ + memmove(path + strlen(i->name) + 1, path, used); + path[0] = '/'; + memcpy(path+1, i->name, strlen(i->name)); + used += 1 + strlen(i->name); } + path[used++] = '\0'; pr_debug("%s: path = '%s'\n",__FUNCTION__,path); + return used; } #define BUFFER_SIZE 1024 /* should be enough memory for the env */ #define NUM_ENVP 32 /* number of env pointers */ + static void kset_hotplug(const char *action, struct kset *kset, struct kobject *kobj) { char *argv[3]; - char **envp = NULL; + char *envp[NUM_ENVP] = { 0, }; char *buffer = NULL; - char *scratch; - int i = 0; + int i, bufused; int retval; - int kobj_path_length; - char *kobj_path = NULL; char *name = NULL; /* If the kset has a filter operation, call it. If it returns @@ -125,14 +117,10 @@ static void kset_hotplug(const char *act if (!hotplug_path[0]) return; - envp = kmalloc(NUM_ENVP * sizeof(char *), GFP_KERNEL); - if (!envp) - return; - memset(envp, 0x00, NUM_ENVP * sizeof(char *)); - buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); if (!buffer) goto exit; + bufused = 0; if (kset->hotplug_ops->name) name = kset->hotplug_ops->name(kset, kobj); @@ -144,29 +132,22 @@ static void kset_hotplug(const char *act argv[2] = 0; /* minimal command environment */ + i = 0; envp[i++] = "HOME=/"; envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; - scratch = buffer; - - envp[i++] = scratch; - scratch += sprintf(scratch, "ACTION=%s", action) + 1; - - kobj_path_length = get_kobj_path_length(kset, kobj); - kobj_path = kmalloc(kobj_path_length, GFP_KERNEL); - if (!kobj_path) - goto exit; - memset(kobj_path, 0x00, kobj_path_length); - fill_kobj_path(kset, kobj, kobj_path, kobj_path_length); + envp[i++] = buffer + bufused; + bufused += sprintf(buffer + bufused, "ACTION=%s", action) + 1; - envp[i++] = scratch; - scratch += sprintf(scratch, "DEVPATH=%s", kobj_path) + 1; + envp[i++] = buffer + bufused; + bufused += sprintf(buffer + bufused, "DEVPATH="); + bufused += fill_kobj_path(kobj, buffer + bufused, BUFFER_SIZE-bufused); if (kset->hotplug_ops->hotplug) { /* have the kset specific function add its stuff */ retval = kset->hotplug_ops->hotplug(kset, kobj, - &envp[i], NUM_ENVP - i, scratch, - BUFFER_SIZE - (scratch - buffer)); + &envp[i], NUM_ENVP - i, buffer + bufused, + BUFFER_SIZE - bufused); if (retval) { pr_debug("%s - hotplug() returned %d\n", __FUNCTION__, retval); @@ -182,9 +163,7 @@ static void kset_hotplug(const char *act __FUNCTION__, retval); exit: - kfree(kobj_path); kfree(buffer); - kfree(envp); return; } #else