diff options
author | Jeff Dike <jdike@addtoit.com> | 2007-02-10 04:43:53 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-11 13:51:21 -0500 |
commit | f28169d2000177e8b72ccc6d72887be779dceca8 (patch) | |
tree | 0ef842014c67d8a136cc26c99113b69e2ede87ea /arch/um/drivers/ubd_kern.c | |
parent | d79a580936396bbcd2f4fae2c6215f9cf81e3c0d (diff) |
[PATCH] uml: return hotplug errors to host
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>
Diffstat (limited to 'arch/um/drivers/ubd_kern.c')
-rw-r--r-- | arch/um/drivers/ubd_kern.c | 132 |
1 files changed, 74 insertions, 58 deletions
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 49c047b75cc5..f4db97efc014 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c | |||
@@ -286,7 +286,7 @@ static int parse_unit(char **ptr) | |||
286 | * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it | 286 | * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it |
287 | * should not be freed on exit. | 287 | * should not be freed on exit. |
288 | */ | 288 | */ |
289 | static int ubd_setup_common(char *str, int *index_out) | 289 | static int ubd_setup_common(char *str, int *index_out, char **error_out) |
290 | { | 290 | { |
291 | struct ubd *ubd_dev; | 291 | struct ubd *ubd_dev; |
292 | struct openflags flags = global_openflags; | 292 | struct openflags flags = global_openflags; |
@@ -302,56 +302,54 @@ static int ubd_setup_common(char *str, int *index_out) | |||
302 | str++; | 302 | str++; |
303 | if(!strcmp(str, "sync")){ | 303 | if(!strcmp(str, "sync")){ |
304 | global_openflags = of_sync(global_openflags); | 304 | global_openflags = of_sync(global_openflags); |
305 | return(0); | 305 | return 0; |
306 | } | 306 | } |
307 | major = simple_strtoul(str, &end, 0); | 307 | major = simple_strtoul(str, &end, 0); |
308 | if((*end != '\0') || (end == str)){ | 308 | if((*end != '\0') || (end == str)){ |
309 | printk(KERN_ERR | 309 | *error_out = "Didn't parse major number"; |
310 | "ubd_setup : didn't parse major number\n"); | 310 | return -EINVAL; |
311 | return(1); | ||
312 | } | 311 | } |
313 | 312 | ||
314 | err = 1; | 313 | err = -EINVAL; |
315 | mutex_lock(&ubd_lock); | 314 | mutex_lock(&ubd_lock); |
316 | if(fake_major != MAJOR_NR){ | 315 | if(fake_major != MAJOR_NR){ |
317 | printk(KERN_ERR "Can't assign a fake major twice\n"); | 316 | *error_out = "Can't assign a fake major twice"; |
318 | goto out1; | 317 | goto out1; |
319 | } | 318 | } |
320 | 319 | ||
321 | fake_major = major; | 320 | fake_major = major; |
322 | 321 | ||
323 | printk(KERN_INFO "Setting extra ubd major number to %d\n", | 322 | printk(KERN_INFO "Setting extra ubd major number to %d\n", |
324 | major); | 323 | major); |
325 | err = 0; | 324 | err = 0; |
326 | out1: | 325 | out1: |
327 | mutex_unlock(&ubd_lock); | 326 | mutex_unlock(&ubd_lock); |
328 | return(err); | 327 | return err; |
329 | } | 328 | } |
330 | 329 | ||
331 | n = parse_unit(&str); | 330 | n = parse_unit(&str); |
332 | if(n < 0){ | 331 | if(n < 0){ |
333 | printk(KERN_ERR "ubd_setup : couldn't parse unit number " | 332 | *error_out = "Couldn't parse device number"; |
334 | "'%s'\n", str); | 333 | return -EINVAL; |
335 | return(1); | ||
336 | } | 334 | } |
337 | if(n >= MAX_DEV){ | 335 | if(n >= MAX_DEV){ |
338 | printk(KERN_ERR "ubd_setup : index %d out of range " | 336 | *error_out = "Device number out of range"; |
339 | "(%d devices, from 0 to %d)\n", n, MAX_DEV, MAX_DEV - 1); | 337 | return 1; |
340 | return(1); | ||
341 | } | 338 | } |
342 | 339 | ||
343 | err = 1; | 340 | err = -EBUSY; |
344 | mutex_lock(&ubd_lock); | 341 | mutex_lock(&ubd_lock); |
345 | 342 | ||
346 | ubd_dev = &ubd_devs[n]; | 343 | ubd_dev = &ubd_devs[n]; |
347 | if(ubd_dev->file != NULL){ | 344 | if(ubd_dev->file != NULL){ |
348 | printk(KERN_ERR "ubd_setup : device already configured\n"); | 345 | *error_out = "Device is already configured"; |
349 | goto out; | 346 | goto out; |
350 | } | 347 | } |
351 | 348 | ||
352 | if (index_out) | 349 | if (index_out) |
353 | *index_out = n; | 350 | *index_out = n; |
354 | 351 | ||
352 | err = -EINVAL; | ||
355 | for (i = 0; i < sizeof("rscd="); i++) { | 353 | for (i = 0; i < sizeof("rscd="); i++) { |
356 | switch (*str) { | 354 | switch (*str) { |
357 | case 'r': | 355 | case 'r': |
@@ -370,47 +368,54 @@ static int ubd_setup_common(char *str, int *index_out) | |||
370 | str++; | 368 | str++; |
371 | goto break_loop; | 369 | goto break_loop; |
372 | default: | 370 | default: |
373 | printk(KERN_ERR "ubd_setup : Expected '=' or flag letter (r, s, c, or d)\n"); | 371 | *error_out = "Expected '=' or flag letter " |
372 | "(r, s, c, or d)"; | ||
374 | goto out; | 373 | goto out; |
375 | } | 374 | } |
376 | str++; | 375 | str++; |
377 | } | 376 | } |
378 | 377 | ||
379 | if (*str == '=') | 378 | if (*str == '=') |
380 | printk(KERN_ERR "ubd_setup : Too many flags specified\n"); | 379 | *error_out = "Too many flags specified"; |
381 | else | 380 | else |
382 | printk(KERN_ERR "ubd_setup : Expected '='\n"); | 381 | *error_out = "Missing '='"; |
383 | goto out; | 382 | goto out; |
384 | 383 | ||
385 | break_loop: | 384 | break_loop: |
386 | err = 0; | ||
387 | backing_file = strchr(str, ','); | 385 | backing_file = strchr(str, ','); |
388 | 386 | ||
389 | if (!backing_file) { | 387 | if (backing_file == NULL) |
390 | backing_file = strchr(str, ':'); | 388 | backing_file = strchr(str, ':'); |
391 | } | ||
392 | 389 | ||
393 | if(backing_file){ | 390 | if(backing_file != NULL){ |
394 | if(ubd_dev->no_cow) | 391 | if(ubd_dev->no_cow){ |
395 | printk(KERN_ERR "Can't specify both 'd' and a " | 392 | *error_out = "Can't specify both 'd' and a cow file"; |
396 | "cow file\n"); | 393 | goto out; |
394 | } | ||
397 | else { | 395 | else { |
398 | *backing_file = '\0'; | 396 | *backing_file = '\0'; |
399 | backing_file++; | 397 | backing_file++; |
400 | } | 398 | } |
401 | } | 399 | } |
400 | err = 0; | ||
402 | ubd_dev->file = str; | 401 | ubd_dev->file = str; |
403 | ubd_dev->cow.file = backing_file; | 402 | ubd_dev->cow.file = backing_file; |
404 | ubd_dev->boot_openflags = flags; | 403 | ubd_dev->boot_openflags = flags; |
405 | out: | 404 | out: |
406 | mutex_unlock(&ubd_lock); | 405 | mutex_unlock(&ubd_lock); |
407 | return(err); | 406 | return err; |
408 | } | 407 | } |
409 | 408 | ||
410 | static int ubd_setup(char *str) | 409 | static int ubd_setup(char *str) |
411 | { | 410 | { |
412 | ubd_setup_common(str, NULL); | 411 | char *error; |
413 | return(1); | 412 | int err; |
413 | |||
414 | err = ubd_setup_common(str, NULL, &error); | ||
415 | if(err) | ||
416 | printk(KERN_ERR "Failed to initialize device with \"%s\" : " | ||
417 | "%s\n", str, error); | ||
418 | return 1; | ||
414 | } | 419 | } |
415 | 420 | ||
416 | __setup("ubd", ubd_setup); | 421 | __setup("ubd", ubd_setup); |
@@ -422,7 +427,7 @@ __uml_help(ubd_setup, | |||
422 | " use either a ':' or a ',': the first one allows writing things like;\n" | 427 | " use either a ':' or a ',': the first one allows writing things like;\n" |
423 | " ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n" | 428 | " ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n" |
424 | " while with a ',' the shell would not expand the 2nd '~'.\n" | 429 | " while with a ',' the shell would not expand the 2nd '~'.\n" |
425 | " When using only one filename, UML will detect whether to thread it like\n" | 430 | " When using only one filename, UML will detect whether to treat it like\n" |
426 | " a COW file or a backing file. To override this detection, add the 'd'\n" | 431 | " a COW file or a backing file. To override this detection, add the 'd'\n" |
427 | " flag:\n" | 432 | " flag:\n" |
428 | " ubd0d=BackingFile\n" | 433 | " ubd0d=BackingFile\n" |
@@ -668,18 +673,19 @@ static int ubd_disk_register(int major, u64 size, int unit, | |||
668 | 673 | ||
669 | #define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9)) | 674 | #define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9)) |
670 | 675 | ||
671 | static int ubd_add(int n) | 676 | static int ubd_add(int n, char **error_out) |
672 | { | 677 | { |
673 | struct ubd *ubd_dev = &ubd_devs[n]; | 678 | struct ubd *ubd_dev = &ubd_devs[n]; |
674 | int err; | 679 | int err = 0; |
675 | 680 | ||
676 | err = -ENODEV; | ||
677 | if(ubd_dev->file == NULL) | 681 | if(ubd_dev->file == NULL) |
678 | goto out; | 682 | goto out; |
679 | 683 | ||
680 | err = ubd_file_size(ubd_dev, &ubd_dev->size); | 684 | err = ubd_file_size(ubd_dev, &ubd_dev->size); |
681 | if(err < 0) | 685 | if(err < 0){ |
686 | *error_out = "Couldn't determine size of device's file"; | ||
682 | goto out; | 687 | goto out; |
688 | } | ||
683 | 689 | ||
684 | ubd_dev->size = ROUND_BLOCK(ubd_dev->size); | 690 | ubd_dev->size = ROUND_BLOCK(ubd_dev->size); |
685 | 691 | ||
@@ -701,28 +707,31 @@ out: | |||
701 | return err; | 707 | return err; |
702 | } | 708 | } |
703 | 709 | ||
704 | static int ubd_config(char *str) | 710 | static int ubd_config(char *str, char **error_out) |
705 | { | 711 | { |
706 | int n, ret; | 712 | int n, ret; |
707 | 713 | ||
714 | /* This string is possibly broken up and stored, so it's only | ||
715 | * freed if ubd_setup_common fails, or if only general options | ||
716 | * were set. | ||
717 | */ | ||
708 | str = kstrdup(str, GFP_KERNEL); | 718 | str = kstrdup(str, GFP_KERNEL); |
709 | if (str == NULL) { | 719 | if (str == NULL) { |
710 | printk(KERN_ERR "ubd_config failed to strdup string\n"); | 720 | *error_out = "Failed to allocate memory"; |
711 | ret = 1; | 721 | return -ENOMEM; |
712 | goto out; | ||
713 | } | 722 | } |
714 | ret = ubd_setup_common(str, &n); | 723 | |
715 | if (ret) { | 724 | ret = ubd_setup_common(str, &n, error_out); |
716 | ret = -1; | 725 | if (ret) |
717 | goto err_free; | 726 | goto err_free; |
718 | } | 727 | |
719 | if (n == -1) { | 728 | if (n == -1) { |
720 | ret = 0; | 729 | ret = 0; |
721 | goto err_free; | 730 | goto err_free; |
722 | } | 731 | } |
723 | 732 | ||
724 | mutex_lock(&ubd_lock); | 733 | mutex_lock(&ubd_lock); |
725 | ret = ubd_add(n); | 734 | ret = ubd_add(n, error_out); |
726 | if (ret) | 735 | if (ret) |
727 | ubd_devs[n].file = NULL; | 736 | ubd_devs[n].file = NULL; |
728 | mutex_unlock(&ubd_lock); | 737 | mutex_unlock(&ubd_lock); |
@@ -777,7 +786,7 @@ static int ubd_id(char **str, int *start_out, int *end_out) | |||
777 | return n; | 786 | return n; |
778 | } | 787 | } |
779 | 788 | ||
780 | static int ubd_remove(int n) | 789 | static int ubd_remove(int n, char **error_out) |
781 | { | 790 | { |
782 | struct ubd *ubd_dev; | 791 | struct ubd *ubd_dev; |
783 | int err = -ENODEV; | 792 | int err = -ENODEV; |
@@ -815,7 +824,9 @@ out: | |||
815 | return err; | 824 | return err; |
816 | } | 825 | } |
817 | 826 | ||
818 | /* All these are called by mconsole in process context and without ubd-specific locks. */ | 827 | /* All these are called by mconsole in process context and without |
828 | * ubd-specific locks. | ||
829 | */ | ||
819 | static struct mc_device ubd_mc = { | 830 | static struct mc_device ubd_mc = { |
820 | .name = "ubd", | 831 | .name = "ubd", |
821 | .config = ubd_config, | 832 | .config = ubd_config, |
@@ -851,7 +862,8 @@ static struct platform_driver ubd_driver = { | |||
851 | 862 | ||
852 | static int __init ubd_init(void) | 863 | static int __init ubd_init(void) |
853 | { | 864 | { |
854 | int i; | 865 | char *error; |
866 | int i, err; | ||
855 | 867 | ||
856 | if (register_blkdev(MAJOR_NR, "ubd")) | 868 | if (register_blkdev(MAJOR_NR, "ubd")) |
857 | return -1; | 869 | return -1; |
@@ -870,8 +882,12 @@ static int __init ubd_init(void) | |||
870 | return -1; | 882 | return -1; |
871 | } | 883 | } |
872 | platform_driver_register(&ubd_driver); | 884 | platform_driver_register(&ubd_driver); |
873 | for (i = 0; i < MAX_DEV; i++) | 885 | for (i = 0; i < MAX_DEV; i++){ |
874 | ubd_add(i); | 886 | err = ubd_add(i, &error); |
887 | if(err) | ||
888 | printk(KERN_ERR "Failed to initialize ubd device %d :" | ||
889 | "%s\n", i, error); | ||
890 | } | ||
875 | return 0; | 891 | return 0; |
876 | } | 892 | } |
877 | 893 | ||