diff options
author | Qu Wenruo <quwenruo@cn.fujitsu.com> | 2014-02-27 21:46:04 -0500 |
---|---|---|
committer | Josef Bacik <jbacik@fb.com> | 2014-03-10 15:17:03 -0400 |
commit | 1ca08976ae94f3594dd7303584581cf8099ce47e (patch) | |
tree | 36266c4bd75ea9807f8936c40d1e13803b3fd83a /fs/btrfs | |
parent | 08a9ff3264181986d1d692a4e6fce3669700c9f8 (diff) |
btrfs: Add high priority workqueue support for btrfs_workqueue_struct
Add high priority function to btrfs_workqueue.
This is implemented by embedding a btrfs_workqueue into a
btrfs_workqueue and use some helper functions to differ the normal
priority wq and high priority wq.
So the high priority wq is completely independent from the normal
workqueue.
Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
Tested-by: David Sterba <dsterba@suse.cz>
Signed-off-by: Josef Bacik <jbacik@fb.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/async-thread.c | 91 | ||||
-rw-r--r-- | fs/btrfs/async-thread.h | 5 |
2 files changed, 83 insertions, 13 deletions
diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 905de02e4386..193c84964db9 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c | |||
@@ -730,7 +730,7 @@ void btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work) | |||
730 | spin_unlock_irqrestore(&worker->lock, flags); | 730 | spin_unlock_irqrestore(&worker->lock, flags); |
731 | } | 731 | } |
732 | 732 | ||
733 | struct btrfs_workqueue_struct { | 733 | struct __btrfs_workqueue_struct { |
734 | struct workqueue_struct *normal_wq; | 734 | struct workqueue_struct *normal_wq; |
735 | /* List head pointing to ordered work list */ | 735 | /* List head pointing to ordered work list */ |
736 | struct list_head ordered_list; | 736 | struct list_head ordered_list; |
@@ -739,6 +739,38 @@ struct btrfs_workqueue_struct { | |||
739 | spinlock_t list_lock; | 739 | spinlock_t list_lock; |
740 | }; | 740 | }; |
741 | 741 | ||
742 | struct btrfs_workqueue_struct { | ||
743 | struct __btrfs_workqueue_struct *normal; | ||
744 | struct __btrfs_workqueue_struct *high; | ||
745 | }; | ||
746 | |||
747 | static inline struct __btrfs_workqueue_struct | ||
748 | *__btrfs_alloc_workqueue(char *name, int flags, int max_active) | ||
749 | { | ||
750 | struct __btrfs_workqueue_struct *ret = kzalloc(sizeof(*ret), GFP_NOFS); | ||
751 | |||
752 | if (unlikely(!ret)) | ||
753 | return NULL; | ||
754 | |||
755 | if (flags & WQ_HIGHPRI) | ||
756 | ret->normal_wq = alloc_workqueue("%s-%s-high", flags, | ||
757 | max_active, "btrfs", name); | ||
758 | else | ||
759 | ret->normal_wq = alloc_workqueue("%s-%s", flags, | ||
760 | max_active, "btrfs", name); | ||
761 | if (unlikely(!ret->normal_wq)) { | ||
762 | kfree(ret); | ||
763 | return NULL; | ||
764 | } | ||
765 | |||
766 | INIT_LIST_HEAD(&ret->ordered_list); | ||
767 | spin_lock_init(&ret->list_lock); | ||
768 | return ret; | ||
769 | } | ||
770 | |||
771 | static inline void | ||
772 | __btrfs_destroy_workqueue(struct __btrfs_workqueue_struct *wq); | ||
773 | |||
742 | struct btrfs_workqueue_struct *btrfs_alloc_workqueue(char *name, | 774 | struct btrfs_workqueue_struct *btrfs_alloc_workqueue(char *name, |
743 | int flags, | 775 | int flags, |
744 | int max_active) | 776 | int max_active) |
@@ -748,19 +780,25 @@ struct btrfs_workqueue_struct *btrfs_alloc_workqueue(char *name, | |||
748 | if (unlikely(!ret)) | 780 | if (unlikely(!ret)) |
749 | return NULL; | 781 | return NULL; |
750 | 782 | ||
751 | ret->normal_wq = alloc_workqueue("%s-%s", flags, max_active, | 783 | ret->normal = __btrfs_alloc_workqueue(name, flags & ~WQ_HIGHPRI, |
752 | "btrfs", name); | 784 | max_active); |
753 | if (unlikely(!ret->normal_wq)) { | 785 | if (unlikely(!ret->normal)) { |
754 | kfree(ret); | 786 | kfree(ret); |
755 | return NULL; | 787 | return NULL; |
756 | } | 788 | } |
757 | 789 | ||
758 | INIT_LIST_HEAD(&ret->ordered_list); | 790 | if (flags & WQ_HIGHPRI) { |
759 | spin_lock_init(&ret->list_lock); | 791 | ret->high = __btrfs_alloc_workqueue(name, flags, max_active); |
792 | if (unlikely(!ret->high)) { | ||
793 | __btrfs_destroy_workqueue(ret->normal); | ||
794 | kfree(ret); | ||
795 | return NULL; | ||
796 | } | ||
797 | } | ||
760 | return ret; | 798 | return ret; |
761 | } | 799 | } |
762 | 800 | ||
763 | static void run_ordered_work(struct btrfs_workqueue_struct *wq) | 801 | static void run_ordered_work(struct __btrfs_workqueue_struct *wq) |
764 | { | 802 | { |
765 | struct list_head *list = &wq->ordered_list; | 803 | struct list_head *list = &wq->ordered_list; |
766 | struct btrfs_work_struct *work; | 804 | struct btrfs_work_struct *work; |
@@ -804,7 +842,7 @@ static void run_ordered_work(struct btrfs_workqueue_struct *wq) | |||
804 | static void normal_work_helper(struct work_struct *arg) | 842 | static void normal_work_helper(struct work_struct *arg) |
805 | { | 843 | { |
806 | struct btrfs_work_struct *work; | 844 | struct btrfs_work_struct *work; |
807 | struct btrfs_workqueue_struct *wq; | 845 | struct __btrfs_workqueue_struct *wq; |
808 | int need_order = 0; | 846 | int need_order = 0; |
809 | 847 | ||
810 | work = container_of(arg, struct btrfs_work_struct, normal_work); | 848 | work = container_of(arg, struct btrfs_work_struct, normal_work); |
@@ -840,8 +878,8 @@ void btrfs_init_work(struct btrfs_work_struct *work, | |||
840 | work->flags = 0; | 878 | work->flags = 0; |
841 | } | 879 | } |
842 | 880 | ||
843 | void btrfs_queue_work(struct btrfs_workqueue_struct *wq, | 881 | static inline void __btrfs_queue_work(struct __btrfs_workqueue_struct *wq, |
844 | struct btrfs_work_struct *work) | 882 | struct btrfs_work_struct *work) |
845 | { | 883 | { |
846 | unsigned long flags; | 884 | unsigned long flags; |
847 | 885 | ||
@@ -854,13 +892,42 @@ void btrfs_queue_work(struct btrfs_workqueue_struct *wq, | |||
854 | queue_work(wq->normal_wq, &work->normal_work); | 892 | queue_work(wq->normal_wq, &work->normal_work); |
855 | } | 893 | } |
856 | 894 | ||
857 | void btrfs_destroy_workqueue(struct btrfs_workqueue_struct *wq) | 895 | void btrfs_queue_work(struct btrfs_workqueue_struct *wq, |
896 | struct btrfs_work_struct *work) | ||
897 | { | ||
898 | struct __btrfs_workqueue_struct *dest_wq; | ||
899 | |||
900 | if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags) && wq->high) | ||
901 | dest_wq = wq->high; | ||
902 | else | ||
903 | dest_wq = wq->normal; | ||
904 | __btrfs_queue_work(dest_wq, work); | ||
905 | } | ||
906 | |||
907 | static inline void | ||
908 | __btrfs_destroy_workqueue(struct __btrfs_workqueue_struct *wq) | ||
858 | { | 909 | { |
859 | destroy_workqueue(wq->normal_wq); | 910 | destroy_workqueue(wq->normal_wq); |
860 | kfree(wq); | 911 | kfree(wq); |
861 | } | 912 | } |
862 | 913 | ||
914 | void btrfs_destroy_workqueue(struct btrfs_workqueue_struct *wq) | ||
915 | { | ||
916 | if (!wq) | ||
917 | return; | ||
918 | if (wq->high) | ||
919 | __btrfs_destroy_workqueue(wq->high); | ||
920 | __btrfs_destroy_workqueue(wq->normal); | ||
921 | } | ||
922 | |||
863 | void btrfs_workqueue_set_max(struct btrfs_workqueue_struct *wq, int max) | 923 | void btrfs_workqueue_set_max(struct btrfs_workqueue_struct *wq, int max) |
864 | { | 924 | { |
865 | workqueue_set_max_active(wq->normal_wq, max); | 925 | workqueue_set_max_active(wq->normal->normal_wq, max); |
926 | if (wq->high) | ||
927 | workqueue_set_max_active(wq->high->normal_wq, max); | ||
928 | } | ||
929 | |||
930 | void btrfs_set_work_high_priority(struct btrfs_work_struct *work) | ||
931 | { | ||
932 | set_bit(WORK_HIGH_PRIO_BIT, &work->flags); | ||
866 | } | 933 | } |
diff --git a/fs/btrfs/async-thread.h b/fs/btrfs/async-thread.h index 9d8da53f6dd9..fce623cfe3da 100644 --- a/fs/btrfs/async-thread.h +++ b/fs/btrfs/async-thread.h | |||
@@ -121,6 +121,8 @@ void btrfs_requeue_work(struct btrfs_work *work); | |||
121 | void btrfs_set_work_high_prio(struct btrfs_work *work); | 121 | void btrfs_set_work_high_prio(struct btrfs_work *work); |
122 | 122 | ||
123 | struct btrfs_workqueue_struct; | 123 | struct btrfs_workqueue_struct; |
124 | /* Internal use only */ | ||
125 | struct __btrfs_workqueue_struct; | ||
124 | 126 | ||
125 | struct btrfs_work_struct { | 127 | struct btrfs_work_struct { |
126 | void (*func)(struct btrfs_work_struct *arg); | 128 | void (*func)(struct btrfs_work_struct *arg); |
@@ -130,7 +132,7 @@ struct btrfs_work_struct { | |||
130 | /* Don't touch things below */ | 132 | /* Don't touch things below */ |
131 | struct work_struct normal_work; | 133 | struct work_struct normal_work; |
132 | struct list_head ordered_list; | 134 | struct list_head ordered_list; |
133 | struct btrfs_workqueue_struct *wq; | 135 | struct __btrfs_workqueue_struct *wq; |
134 | unsigned long flags; | 136 | unsigned long flags; |
135 | }; | 137 | }; |
136 | 138 | ||
@@ -145,4 +147,5 @@ void btrfs_queue_work(struct btrfs_workqueue_struct *wq, | |||
145 | struct btrfs_work_struct *work); | 147 | struct btrfs_work_struct *work); |
146 | void btrfs_destroy_workqueue(struct btrfs_workqueue_struct *wq); | 148 | void btrfs_destroy_workqueue(struct btrfs_workqueue_struct *wq); |
147 | void btrfs_workqueue_set_max(struct btrfs_workqueue_struct *wq, int max); | 149 | void btrfs_workqueue_set_max(struct btrfs_workqueue_struct *wq, int max); |
150 | void btrfs_set_work_high_priority(struct btrfs_work_struct *work); | ||
148 | #endif | 151 | #endif |