Skip to content

Commit

Permalink
[PATCH] uml: return hotplug errors to host
Browse files Browse the repository at this point in the history
I noticed that errors happening while hotplugging devices from the host were
never returned back to the mconsole client.  In some cases, success was
returned instead of even an information-free error.

This patch cleans that up by having the low-level configuration code pass back
an error string along with an error code.  At the top level, which knows
whether it is early boot time or responding to an mconsole request, the string
is printk'd or returned to the mconsole client.

There are also whitespace and trivial code cleanups in the surrounding code.

Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Jeff Dike authored and Linus Torvalds committed Feb 11, 2007
1 parent d79a580 commit f28169d
Show file tree
Hide file tree
Showing 12 changed files with 253 additions and 238 deletions.
77 changes: 23 additions & 54 deletions arch/um/drivers/chan_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,94 +19,61 @@
#include "line.h"
#include "os.h"

/* XXX: could well be moved to somewhere else, if needed. */
static int my_printf(const char * fmt, ...)
__attribute__ ((format (printf, 1, 2)));

static int my_printf(const char * fmt, ...)
{
/* Yes, can be called on atomic context.*/
char *buf = kmalloc(4096, GFP_ATOMIC);
va_list args;
int r;

if (!buf) {
/* We print directly fmt.
* Yes, yes, yes, feel free to complain. */
r = strlen(fmt);
} else {
va_start(args, fmt);
r = vsprintf(buf, fmt, args);
va_end(args);
fmt = buf;
}

if (r)
r = os_write_file(1, fmt, r);
return r;

}

#ifdef CONFIG_NOCONFIG_CHAN
/* Despite its name, there's no added trailing newline. */
static int my_puts(const char * buf)
static void *not_configged_init(char *str, int device,
const struct chan_opts *opts)
{
return os_write_file(1, buf, strlen(buf));
}

static void *not_configged_init(char *str, int device, struct chan_opts *opts)
{
my_puts("Using a channel type which is configured out of "
printk("Using a channel type which is configured out of "
"UML\n");
return NULL;
}

static int not_configged_open(int input, int output, int primary, void *data,
char **dev_out)
{
my_puts("Using a channel type which is configured out of "
printk("Using a channel type which is configured out of "
"UML\n");
return -ENODEV;
}

static void not_configged_close(int fd, void *data)
{
my_puts("Using a channel type which is configured out of "
printk("Using a channel type which is configured out of "
"UML\n");
}

static int not_configged_read(int fd, char *c_out, void *data)
{
my_puts("Using a channel type which is configured out of "
printk("Using a channel type which is configured out of "
"UML\n");
return -EIO;
}

static int not_configged_write(int fd, const char *buf, int len, void *data)
{
my_puts("Using a channel type which is configured out of "
printk("Using a channel type which is configured out of "
"UML\n");
return -EIO;
}

static int not_configged_console_write(int fd, const char *buf, int len)
{
my_puts("Using a channel type which is configured out of "
printk("Using a channel type which is configured out of "
"UML\n");
return -EIO;
}

static int not_configged_window_size(int fd, void *data, unsigned short *rows,
unsigned short *cols)
{
my_puts("Using a channel type which is configured out of "
printk("Using a channel type which is configured out of "
"UML\n");
return -ENODEV;
}

static void not_configged_free(void *data)
{
my_puts("Using a channel type which is configured out of "
printk("Using a channel type which is configured out of "
"UML\n");
}

Expand Down Expand Up @@ -534,7 +501,7 @@ static const struct chan_type chan_table[] = {
};

static struct chan *parse_chan(struct line *line, char *str, int device,
const struct chan_opts *opts)
const struct chan_opts *opts, char **error_out)
{
const struct chan_type *entry;
const struct chan_ops *ops;
Expand All @@ -553,19 +520,21 @@ static struct chan *parse_chan(struct line *line, char *str, int device,
}
}
if(ops == NULL){
my_printf("parse_chan couldn't parse \"%s\"\n",
str);
*error_out = "No match for configured backends";
return NULL;
}
if(ops->init == NULL)
return NULL;

data = (*ops->init)(str, device, opts);
if(data == NULL)
if(data == NULL){
*error_out = "Configuration failed";
return NULL;
}

chan = kmalloc(sizeof(*chan), GFP_ATOMIC);
if(chan == NULL)
if(chan == NULL){
*error_out = "Memory allocation failed";
return NULL;
}
*chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list),
.free_list =
LIST_HEAD_INIT(chan->free_list),
Expand All @@ -582,7 +551,7 @@ static struct chan *parse_chan(struct line *line, char *str, int device,
}

int parse_chan_pair(char *str, struct line *line, int device,
const struct chan_opts *opts)
const struct chan_opts *opts, char **error_out)
{
struct list_head *chans = &line->chan_list;
struct chan *new, *chan;
Expand All @@ -599,22 +568,22 @@ int parse_chan_pair(char *str, struct line *line, int device,
in = str;
*out = '\0';
out++;
new = parse_chan(line, in, device, opts);
new = parse_chan(line, in, device, opts, error_out);
if(new == NULL)
return -1;

new->input = 1;
list_add(&new->list, chans);

new = parse_chan(line, out, device, opts);
new = parse_chan(line, out, device, opts, error_out);
if(new == NULL)
return -1;

list_add(&new->list, chans);
new->output = 1;
}
else {
new = parse_chan(line, str, device, opts);
new = parse_chan(line, str, device, opts, error_out);
if(new == NULL)
return -1;

Expand Down
66 changes: 39 additions & 27 deletions arch/um/drivers/line.c
Original file line number Diff line number Diff line change
Expand Up @@ -549,14 +549,16 @@ void close_lines(struct line *lines, int nlines)
close_chan(&lines[i].chan_list, 0);
}

static void setup_one_line(struct line *lines, int n, char *init, int init_prio)
static int setup_one_line(struct line *lines, int n, char *init, int init_prio,
char **error_out)
{
struct line *line = &lines[n];
int err = -EINVAL;

spin_lock(&line->count_lock);

if(line->tty != NULL){
printk("line_setup - device %d is open\n", n);
*error_out = "Device is already open";
goto out;
}

Expand All @@ -569,18 +571,22 @@ static void setup_one_line(struct line *lines, int n, char *init, int init_prio)
line->valid = 1;
}
}
err = 0;
out:
spin_unlock(&line->count_lock);
return err;
}

/* Common setup code for both startup command line and mconsole initialization.
* @lines contains the array (of size @num) to modify;
* @init is the setup string;
* @error_out is an error string in the case of failure;
*/

int line_setup(struct line *lines, unsigned int num, char *init)
int line_setup(struct line *lines, unsigned int num, char *init,
char **error_out)
{
int i, n;
int i, n, err;
char *end;

if(*init == '=') {
Expand All @@ -591,52 +597,56 @@ int line_setup(struct line *lines, unsigned int num, char *init)
else {
n = simple_strtoul(init, &end, 0);
if(*end != '='){
printk(KERN_ERR "line_setup failed to parse \"%s\"\n",
init);
return 0;
*error_out = "Couldn't parse device number";
return -EINVAL;
}
init = end;
}
init++;

if (n >= (signed int) num) {
printk("line_setup - %d out of range ((0 ... %d) allowed)\n",
n, num - 1);
return 0;
*error_out = "Device number out of range";
return -EINVAL;
}
else if (n >= 0){
err = setup_one_line(lines, n, init, INIT_ONE, error_out);
if(err)
return err;
}
else if (n >= 0)
setup_one_line(lines, n, init, INIT_ONE);
else {
for(i = 0; i < num; i++)
setup_one_line(lines, i, init, INIT_ALL);
for(i = 0; i < num; i++){
err = setup_one_line(lines, i, init, INIT_ALL,
error_out);
if(err)
return err;
}
}
return n == -1 ? num : n;
}

int line_config(struct line *lines, unsigned int num, char *str,
const struct chan_opts *opts)
const struct chan_opts *opts, char **error_out)
{
struct line *line;
char *new;
int n;

if(*str == '='){
printk("line_config - can't configure all devices from "
"mconsole\n");
return 1;
*error_out = "Can't configure all devices from mconsole";
return -EINVAL;
}

new = kstrdup(str, GFP_KERNEL);
if(new == NULL){
printk("line_config - kstrdup failed\n");
return 1;
*error_out = "Failed to allocate memory";
return -ENOMEM;
}
n = line_setup(lines, num, new);
n = line_setup(lines, num, new, error_out);
if(n < 0)
return 1;
return n;

line = &lines[n];
return parse_chan_pair(line->init_str, line, n, opts);
return parse_chan_pair(line->init_str, line, n, opts, error_out);
}

int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
Expand Down Expand Up @@ -685,13 +695,13 @@ int line_id(char **str, int *start_out, int *end_out)
return n;
}

int line_remove(struct line *lines, unsigned int num, int n)
int line_remove(struct line *lines, unsigned int num, int n, char **error_out)
{
int err;
char config[sizeof("conxxxx=none\0")];

sprintf(config, "%d=none", n);
err = line_setup(lines, num, config);
err = line_setup(lines, num, config, error_out);
if(err >= 0)
err = 0;
return err;
Expand Down Expand Up @@ -740,6 +750,7 @@ static LIST_HEAD(winch_handlers);
void lines_init(struct line *lines, int nlines, struct chan_opts *opts)
{
struct line *line;
char *error;
int i;

for(i = 0; i < nlines; i++){
Expand All @@ -754,8 +765,9 @@ void lines_init(struct line *lines, int nlines, struct chan_opts *opts)
if(line->init_str == NULL)
printk("lines_init - kstrdup returned NULL\n");

if(parse_chan_pair(line->init_str, line, i, opts)){
printk("parse_chan_pair failed for device %d\n", i);
if(parse_chan_pair(line->init_str, line, i, opts, &error)){
printk("parse_chan_pair failed for device %d : %s\n",
i, error);
line->valid = 0;
}
}
Expand Down
Loading

0 comments on commit f28169d

Please sign in to comment.