aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/mm
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2016-03-08 05:55:04 -0500
committerChristian Borntraeger <borntraeger@de.ibm.com>2016-06-20 03:53:59 -0400
commit6ea427bbbd4078297bb1dbd6c5cb83f3f48aac46 (patch)
tree7ed574fcca3cae5d6a50211d43c3d5ab21620d3a /arch/s390/mm
parentb2d73b2a0ad1c758cb0c1acb01a911744b845942 (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.c90
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 */
30struct gmap *gmap_alloc(struct mm_struct *mm, unsigned long limit) 30static 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
78out_free: 75out_free:
@@ -80,7 +77,28 @@ out_free:
80out: 77out:
81 return NULL; 78 return NULL;
82} 79}
83EXPORT_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 */
88struct 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}
101EXPORT_SYMBOL_GPL(gmap_create);
84 102
85static void gmap_flush_tlb(struct gmap *gmap) 103static 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 */
121void gmap_free(struct gmap *gmap) 139static 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}
143EXPORT_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 */
157struct gmap *gmap_get(struct gmap *gmap)
158{
159 atomic_inc(&gmap->ref_count);
160 return gmap;
161}
162EXPORT_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 */
170void gmap_put(struct gmap *gmap)
171{
172 if (atomic_dec_return(&gmap->ref_count) == 0)
173 gmap_free(gmap);
174}
175EXPORT_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 */
181void 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}
193EXPORT_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