diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2016-03-08 05:55:04 -0500 |
---|---|---|
committer | Christian Borntraeger <borntraeger@de.ibm.com> | 2016-06-20 03:53:59 -0400 |
commit | 6ea427bbbd4078297bb1dbd6c5cb83f3f48aac46 (patch) | |
tree | 7ed574fcca3cae5d6a50211d43c3d5ab21620d3a /arch/s390/mm | |
parent | b2d73b2a0ad1c758cb0c1acb01a911744b845942 (diff) |
s390/mm: add reference counter to gmap structure
Let's use a reference counter mechanism to control the lifetime of
gmap structures. This will be needed for further changes related to
gmap shadows.
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Diffstat (limited to 'arch/s390/mm')
-rw-r--r-- | arch/s390/mm/gmap.c | 90 |
1 files changed, 70 insertions, 20 deletions
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c index 480c076afceb..fe25f1915800 100644 --- a/arch/s390/mm/gmap.c +++ b/arch/s390/mm/gmap.c | |||
@@ -21,13 +21,13 @@ | |||
21 | #include <asm/tlb.h> | 21 | #include <asm/tlb.h> |
22 | 22 | ||
23 | /** | 23 | /** |
24 | * gmap_alloc - allocate a guest address space | 24 | * gmap_alloc - allocate and initialize a guest address space |
25 | * @mm: pointer to the parent mm_struct | 25 | * @mm: pointer to the parent mm_struct |
26 | * @limit: maximum address of the gmap address space | 26 | * @limit: maximum address of the gmap address space |
27 | * | 27 | * |
28 | * Returns a guest address space structure. | 28 | * Returns a guest address space structure. |
29 | */ | 29 | */ |
30 | struct gmap *gmap_alloc(struct mm_struct *mm, unsigned long limit) | 30 | static struct gmap *gmap_alloc(unsigned long limit) |
31 | { | 31 | { |
32 | struct gmap *gmap; | 32 | struct gmap *gmap; |
33 | struct page *page; | 33 | struct page *page; |
@@ -58,7 +58,7 @@ struct gmap *gmap_alloc(struct mm_struct *mm, unsigned long limit) | |||
58 | INIT_RADIX_TREE(&gmap->guest_to_host, GFP_KERNEL); | 58 | INIT_RADIX_TREE(&gmap->guest_to_host, GFP_KERNEL); |
59 | INIT_RADIX_TREE(&gmap->host_to_guest, GFP_ATOMIC); | 59 | INIT_RADIX_TREE(&gmap->host_to_guest, GFP_ATOMIC); |
60 | spin_lock_init(&gmap->guest_table_lock); | 60 | spin_lock_init(&gmap->guest_table_lock); |
61 | gmap->mm = mm; | 61 | atomic_set(&gmap->ref_count, 1); |
62 | page = alloc_pages(GFP_KERNEL, 2); | 62 | page = alloc_pages(GFP_KERNEL, 2); |
63 | if (!page) | 63 | if (!page) |
64 | goto out_free; | 64 | goto out_free; |
@@ -70,9 +70,6 @@ struct gmap *gmap_alloc(struct mm_struct *mm, unsigned long limit) | |||
70 | gmap->asce = atype | _ASCE_TABLE_LENGTH | | 70 | gmap->asce = atype | _ASCE_TABLE_LENGTH | |
71 | _ASCE_USER_BITS | __pa(table); | 71 | _ASCE_USER_BITS | __pa(table); |
72 | gmap->asce_end = limit; | 72 | gmap->asce_end = limit; |
73 | spin_lock(&mm->context.gmap_lock); | ||
74 | list_add_rcu(&gmap->list, &mm->context.gmap_list); | ||
75 | spin_unlock(&mm->context.gmap_lock); | ||
76 | return gmap; | 73 | return gmap; |
77 | 74 | ||
78 | out_free: | 75 | out_free: |
@@ -80,7 +77,28 @@ out_free: | |||
80 | out: | 77 | out: |
81 | return NULL; | 78 | return NULL; |
82 | } | 79 | } |
83 | EXPORT_SYMBOL_GPL(gmap_alloc); | 80 | |
81 | /** | ||
82 | * gmap_create - create a guest address space | ||
83 | * @mm: pointer to the parent mm_struct | ||
84 | * @limit: maximum size of the gmap address space | ||
85 | * | ||
86 | * Returns a guest address space structure. | ||
87 | */ | ||
88 | struct gmap *gmap_create(struct mm_struct *mm, unsigned long limit) | ||
89 | { | ||
90 | struct gmap *gmap; | ||
91 | |||
92 | gmap = gmap_alloc(limit); | ||
93 | if (!gmap) | ||
94 | return NULL; | ||
95 | gmap->mm = mm; | ||
96 | spin_lock(&mm->context.gmap_lock); | ||
97 | list_add_rcu(&gmap->list, &mm->context.gmap_list); | ||
98 | spin_unlock(&mm->context.gmap_lock); | ||
99 | return gmap; | ||
100 | } | ||
101 | EXPORT_SYMBOL_GPL(gmap_create); | ||
84 | 102 | ||
85 | static void gmap_flush_tlb(struct gmap *gmap) | 103 | static void gmap_flush_tlb(struct gmap *gmap) |
86 | { | 104 | { |
@@ -118,21 +136,10 @@ static void gmap_radix_tree_free(struct radix_tree_root *root) | |||
118 | * gmap_free - free a guest address space | 136 | * gmap_free - free a guest address space |
119 | * @gmap: pointer to the guest address space structure | 137 | * @gmap: pointer to the guest address space structure |
120 | */ | 138 | */ |
121 | void gmap_free(struct gmap *gmap) | 139 | static void gmap_free(struct gmap *gmap) |
122 | { | 140 | { |
123 | struct page *page, *next; | 141 | struct page *page, *next; |
124 | 142 | ||
125 | /* Flush tlb. */ | ||
126 | if (MACHINE_HAS_IDTE) | ||
127 | __tlb_flush_asce(gmap->mm, gmap->asce); | ||
128 | else | ||
129 | __tlb_flush_global(); | ||
130 | |||
131 | spin_lock(&gmap->mm->context.gmap_lock); | ||
132 | list_del_rcu(&gmap->list); | ||
133 | spin_unlock(&gmap->mm->context.gmap_lock); | ||
134 | synchronize_rcu(); | ||
135 | |||
136 | /* Free all segment & region tables. */ | 143 | /* Free all segment & region tables. */ |
137 | list_for_each_entry_safe(page, next, &gmap->crst_list, lru) | 144 | list_for_each_entry_safe(page, next, &gmap->crst_list, lru) |
138 | __free_pages(page, 2); | 145 | __free_pages(page, 2); |
@@ -140,7 +147,50 @@ void gmap_free(struct gmap *gmap) | |||
140 | gmap_radix_tree_free(&gmap->host_to_guest); | 147 | gmap_radix_tree_free(&gmap->host_to_guest); |
141 | kfree(gmap); | 148 | kfree(gmap); |
142 | } | 149 | } |
143 | EXPORT_SYMBOL_GPL(gmap_free); | 150 | |
151 | /** | ||
152 | * gmap_get - increase reference counter for guest address space | ||
153 | * @gmap: pointer to the guest address space structure | ||
154 | * | ||
155 | * Returns the gmap pointer | ||
156 | */ | ||
157 | struct gmap *gmap_get(struct gmap *gmap) | ||
158 | { | ||
159 | atomic_inc(&gmap->ref_count); | ||
160 | return gmap; | ||
161 | } | ||
162 | EXPORT_SYMBOL_GPL(gmap_get); | ||
163 | |||
164 | /** | ||
165 | * gmap_put - decrease reference counter for guest address space | ||
166 | * @gmap: pointer to the guest address space structure | ||
167 | * | ||
168 | * If the reference counter reaches zero the guest address space is freed. | ||
169 | */ | ||
170 | void gmap_put(struct gmap *gmap) | ||
171 | { | ||
172 | if (atomic_dec_return(&gmap->ref_count) == 0) | ||
173 | gmap_free(gmap); | ||
174 | } | ||
175 | EXPORT_SYMBOL_GPL(gmap_put); | ||
176 | |||
177 | /** | ||
178 | * gmap_remove - remove a guest address space but do not free it yet | ||
179 | * @gmap: pointer to the guest address space structure | ||
180 | */ | ||
181 | void gmap_remove(struct gmap *gmap) | ||
182 | { | ||
183 | /* Flush tlb. */ | ||
184 | gmap_flush_tlb(gmap); | ||
185 | /* Remove gmap from the pre-mm list */ | ||
186 | spin_lock(&gmap->mm->context.gmap_lock); | ||
187 | list_del_rcu(&gmap->list); | ||
188 | spin_unlock(&gmap->mm->context.gmap_lock); | ||
189 | synchronize_rcu(); | ||
190 | /* Put reference */ | ||
191 | gmap_put(gmap); | ||
192 | } | ||
193 | EXPORT_SYMBOL_GPL(gmap_remove); | ||
144 | 194 | ||
145 | /** | 195 | /** |
146 | * gmap_enable - switch primary space to the guest address space | 196 | * gmap_enable - switch primary space to the guest address space |