aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/drivers/ubd_kern.c
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2007-02-10 04:43:53 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-11 13:51:21 -0500
commitf28169d2000177e8b72ccc6d72887be779dceca8 (patch)
tree0ef842014c67d8a136cc26c99113b69e2ede87ea /arch/um/drivers/ubd_kern.c
parentd79a580936396bbcd2f4fae2c6215f9cf81e3c0d (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.c132
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 */
289static int ubd_setup_common(char *str, int *index_out) 289static 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
385break_loop: 384break_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;
405out: 404out:
406 mutex_unlock(&ubd_lock); 405 mutex_unlock(&ubd_lock);
407 return(err); 406 return err;
408} 407}
409 408
410static int ubd_setup(char *str) 409static 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
671static int ubd_add(int n) 676static 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
704static int ubd_config(char *str) 710static 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
780static int ubd_remove(int n) 789static 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 */
819static struct mc_device ubd_mc = { 830static 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
852static int __init ubd_init(void) 863static 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