diff options
author | Serge E. Hallyn <serue@us.ibm.com> | 2006-09-29 04:59:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-29 12:18:06 -0400 |
commit | 6c9979185c7ef4feeb7f8d29be032b8f032a1838 (patch) | |
tree | dd6d45dc21adf280164ba840ae0c954dd0c94233 /drivers | |
parent | 5b217fa75c3aea381f1f5fa7ff09e7b4019ea374 (diff) |
[PATCH] kthread: convert loop.c to kthread
Convert loop.c from the deprecated kernel_thread to kthread. This patch
simplifies the code quite a bit and passes similar testing to the previous
submission on both emulated x86 and s390.
Changes since last submission:
switched to using a rather simple loop based on
wait_event_interruptible.
Signed-off-by: Serge E. Hallyn <serue@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/loop.c | 69 |
1 files changed, 24 insertions, 45 deletions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index c774121684d7..e87b88731adc 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c | |||
@@ -72,6 +72,7 @@ | |||
72 | #include <linux/completion.h> | 72 | #include <linux/completion.h> |
73 | #include <linux/highmem.h> | 73 | #include <linux/highmem.h> |
74 | #include <linux/gfp.h> | 74 | #include <linux/gfp.h> |
75 | #include <linux/kthread.h> | ||
75 | 76 | ||
76 | #include <asm/uaccess.h> | 77 | #include <asm/uaccess.h> |
77 | 78 | ||
@@ -522,15 +523,12 @@ static int loop_make_request(request_queue_t *q, struct bio *old_bio) | |||
522 | goto out; | 523 | goto out; |
523 | if (unlikely(rw == WRITE && (lo->lo_flags & LO_FLAGS_READ_ONLY))) | 524 | if (unlikely(rw == WRITE && (lo->lo_flags & LO_FLAGS_READ_ONLY))) |
524 | goto out; | 525 | goto out; |
525 | lo->lo_pending++; | ||
526 | loop_add_bio(lo, old_bio); | 526 | loop_add_bio(lo, old_bio); |
527 | wake_up(&lo->lo_event); | ||
527 | spin_unlock_irq(&lo->lo_lock); | 528 | spin_unlock_irq(&lo->lo_lock); |
528 | complete(&lo->lo_bh_done); | ||
529 | return 0; | 529 | return 0; |
530 | 530 | ||
531 | out: | 531 | out: |
532 | if (lo->lo_pending == 0) | ||
533 | complete(&lo->lo_bh_done); | ||
534 | spin_unlock_irq(&lo->lo_lock); | 532 | spin_unlock_irq(&lo->lo_lock); |
535 | bio_io_error(old_bio, old_bio->bi_size); | 533 | bio_io_error(old_bio, old_bio->bi_size); |
536 | return 0; | 534 | return 0; |
@@ -570,14 +568,18 @@ static inline void loop_handle_bio(struct loop_device *lo, struct bio *bio) | |||
570 | * to avoid blocking in our make_request_fn. it also does loop decrypting | 568 | * to avoid blocking in our make_request_fn. it also does loop decrypting |
571 | * on reads for block backed loop, as that is too heavy to do from | 569 | * on reads for block backed loop, as that is too heavy to do from |
572 | * b_end_io context where irqs may be disabled. | 570 | * b_end_io context where irqs may be disabled. |
571 | * | ||
572 | * Loop explanation: loop_clr_fd() sets lo_state to Lo_rundown before | ||
573 | * calling kthread_stop(). Therefore once kthread_should_stop() is | ||
574 | * true, make_request will not place any more requests. Therefore | ||
575 | * once kthread_should_stop() is true and lo_bio is NULL, we are | ||
576 | * done with the loop. | ||
573 | */ | 577 | */ |
574 | static int loop_thread(void *data) | 578 | static int loop_thread(void *data) |
575 | { | 579 | { |
576 | struct loop_device *lo = data; | 580 | struct loop_device *lo = data; |
577 | struct bio *bio; | 581 | struct bio *bio; |
578 | 582 | ||
579 | daemonize("loop%d", lo->lo_number); | ||
580 | |||
581 | /* | 583 | /* |
582 | * loop can be used in an encrypted device, | 584 | * loop can be used in an encrypted device, |
583 | * hence, it mustn't be stopped at all | 585 | * hence, it mustn't be stopped at all |
@@ -587,47 +589,21 @@ static int loop_thread(void *data) | |||
587 | 589 | ||
588 | set_user_nice(current, -20); | 590 | set_user_nice(current, -20); |
589 | 591 | ||
590 | lo->lo_state = Lo_bound; | 592 | while (!kthread_should_stop() || lo->lo_bio) { |
591 | lo->lo_pending = 1; | ||
592 | |||
593 | /* | ||
594 | * complete it, we are running | ||
595 | */ | ||
596 | complete(&lo->lo_done); | ||
597 | 593 | ||
598 | for (;;) { | 594 | wait_event_interruptible(lo->lo_event, |
599 | int pending; | 595 | lo->lo_bio || kthread_should_stop()); |
600 | 596 | ||
601 | if (wait_for_completion_interruptible(&lo->lo_bh_done)) | 597 | if (!lo->lo_bio) |
602 | continue; | 598 | continue; |
603 | |||
604 | spin_lock_irq(&lo->lo_lock); | 599 | spin_lock_irq(&lo->lo_lock); |
605 | |||
606 | /* | ||
607 | * could be completed because of tear-down, not pending work | ||
608 | */ | ||
609 | if (unlikely(!lo->lo_pending)) { | ||
610 | spin_unlock_irq(&lo->lo_lock); | ||
611 | break; | ||
612 | } | ||
613 | |||
614 | bio = loop_get_bio(lo); | 600 | bio = loop_get_bio(lo); |
615 | lo->lo_pending--; | ||
616 | pending = lo->lo_pending; | ||
617 | spin_unlock_irq(&lo->lo_lock); | 601 | spin_unlock_irq(&lo->lo_lock); |
618 | 602 | ||
619 | BUG_ON(!bio); | 603 | BUG_ON(!bio); |
620 | loop_handle_bio(lo, bio); | 604 | loop_handle_bio(lo, bio); |
621 | |||
622 | /* | ||
623 | * upped both for pending work and tear-down, lo_pending | ||
624 | * will hit zero then | ||
625 | */ | ||
626 | if (unlikely(!pending)) | ||
627 | break; | ||
628 | } | 605 | } |
629 | 606 | ||
630 | complete(&lo->lo_done); | ||
631 | return 0; | 607 | return 0; |
632 | } | 608 | } |
633 | 609 | ||
@@ -840,10 +816,15 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file, | |||
840 | 816 | ||
841 | set_blocksize(bdev, lo_blocksize); | 817 | set_blocksize(bdev, lo_blocksize); |
842 | 818 | ||
843 | error = kernel_thread(loop_thread, lo, CLONE_KERNEL); | 819 | lo->lo_thread = kthread_create(loop_thread, lo, "loop%d", |
844 | if (error < 0) | 820 | lo->lo_number); |
821 | if (IS_ERR(lo->lo_thread)) { | ||
822 | error = PTR_ERR(lo->lo_thread); | ||
823 | lo->lo_thread = NULL; | ||
845 | goto out_putf; | 824 | goto out_putf; |
846 | wait_for_completion(&lo->lo_done); | 825 | } |
826 | lo->lo_state = Lo_bound; | ||
827 | wake_up_process(lo->lo_thread); | ||
847 | return 0; | 828 | return 0; |
848 | 829 | ||
849 | out_putf: | 830 | out_putf: |
@@ -907,12 +888,9 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) | |||
907 | 888 | ||
908 | spin_lock_irq(&lo->lo_lock); | 889 | spin_lock_irq(&lo->lo_lock); |
909 | lo->lo_state = Lo_rundown; | 890 | lo->lo_state = Lo_rundown; |
910 | lo->lo_pending--; | ||
911 | if (!lo->lo_pending) | ||
912 | complete(&lo->lo_bh_done); | ||
913 | spin_unlock_irq(&lo->lo_lock); | 891 | spin_unlock_irq(&lo->lo_lock); |
914 | 892 | ||
915 | wait_for_completion(&lo->lo_done); | 893 | kthread_stop(lo->lo_thread); |
916 | 894 | ||
917 | lo->lo_backing_file = NULL; | 895 | lo->lo_backing_file = NULL; |
918 | 896 | ||
@@ -925,6 +903,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) | |||
925 | lo->lo_sizelimit = 0; | 903 | lo->lo_sizelimit = 0; |
926 | lo->lo_encrypt_key_size = 0; | 904 | lo->lo_encrypt_key_size = 0; |
927 | lo->lo_flags = 0; | 905 | lo->lo_flags = 0; |
906 | lo->lo_thread = NULL; | ||
928 | memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE); | 907 | memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE); |
929 | memset(lo->lo_crypt_name, 0, LO_NAME_SIZE); | 908 | memset(lo->lo_crypt_name, 0, LO_NAME_SIZE); |
930 | memset(lo->lo_file_name, 0, LO_NAME_SIZE); | 909 | memset(lo->lo_file_name, 0, LO_NAME_SIZE); |
@@ -1287,9 +1266,9 @@ static int __init loop_init(void) | |||
1287 | if (!lo->lo_queue) | 1266 | if (!lo->lo_queue) |
1288 | goto out_mem4; | 1267 | goto out_mem4; |
1289 | mutex_init(&lo->lo_ctl_mutex); | 1268 | mutex_init(&lo->lo_ctl_mutex); |
1290 | init_completion(&lo->lo_done); | ||
1291 | init_completion(&lo->lo_bh_done); | ||
1292 | lo->lo_number = i; | 1269 | lo->lo_number = i; |
1270 | lo->lo_thread = NULL; | ||
1271 | init_waitqueue_head(&lo->lo_event); | ||
1293 | spin_lock_init(&lo->lo_lock); | 1272 | spin_lock_init(&lo->lo_lock); |
1294 | disk->major = LOOP_MAJOR; | 1273 | disk->major = LOOP_MAJOR; |
1295 | disk->first_minor = i; | 1274 | disk->first_minor = i; |