aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/drivers/ubd_kern.c
diff options
context:
space:
mode:
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