diff options
Diffstat (limited to 'arch/x86/kernel/ds.c')
-rw-r--r-- | arch/x86/kernel/ds.c | 88 |
1 files changed, 48 insertions, 40 deletions
diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c index d1a121443bde..a2d1176c38ee 100644 --- a/arch/x86/kernel/ds.c +++ b/arch/x86/kernel/ds.c | |||
@@ -21,8 +21,6 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | 23 | ||
24 | #ifdef CONFIG_X86_DS | ||
25 | |||
26 | #include <asm/ds.h> | 24 | #include <asm/ds.h> |
27 | 25 | ||
28 | #include <linux/errno.h> | 26 | #include <linux/errno.h> |
@@ -211,14 +209,15 @@ static DEFINE_PER_CPU(struct ds_context *, system_context); | |||
211 | static inline struct ds_context *ds_get_context(struct task_struct *task) | 209 | static inline struct ds_context *ds_get_context(struct task_struct *task) |
212 | { | 210 | { |
213 | struct ds_context *context; | 211 | struct ds_context *context; |
212 | unsigned long irq; | ||
214 | 213 | ||
215 | spin_lock(&ds_lock); | 214 | spin_lock_irqsave(&ds_lock, irq); |
216 | 215 | ||
217 | context = (task ? task->thread.ds_ctx : this_system_context); | 216 | context = (task ? task->thread.ds_ctx : this_system_context); |
218 | if (context) | 217 | if (context) |
219 | context->count++; | 218 | context->count++; |
220 | 219 | ||
221 | spin_unlock(&ds_lock); | 220 | spin_unlock_irqrestore(&ds_lock, irq); |
222 | 221 | ||
223 | return context; | 222 | return context; |
224 | } | 223 | } |
@@ -226,55 +225,46 @@ static inline struct ds_context *ds_get_context(struct task_struct *task) | |||
226 | /* | 225 | /* |
227 | * Same as ds_get_context, but allocates the context and it's DS | 226 | * Same as ds_get_context, but allocates the context and it's DS |
228 | * structure, if necessary; returns NULL; if out of memory. | 227 | * structure, if necessary; returns NULL; if out of memory. |
229 | * | ||
230 | * pre: requires ds_lock to be held | ||
231 | */ | 228 | */ |
232 | static inline struct ds_context *ds_alloc_context(struct task_struct *task) | 229 | static inline struct ds_context *ds_alloc_context(struct task_struct *task) |
233 | { | 230 | { |
234 | struct ds_context **p_context = | 231 | struct ds_context **p_context = |
235 | (task ? &task->thread.ds_ctx : &this_system_context); | 232 | (task ? &task->thread.ds_ctx : &this_system_context); |
236 | struct ds_context *context = *p_context; | 233 | struct ds_context *context = *p_context; |
234 | unsigned long irq; | ||
237 | 235 | ||
238 | if (!context) { | 236 | if (!context) { |
239 | spin_unlock(&ds_lock); | ||
240 | |||
241 | context = kzalloc(sizeof(*context), GFP_KERNEL); | 237 | context = kzalloc(sizeof(*context), GFP_KERNEL); |
242 | 238 | if (!context) | |
243 | if (!context) { | ||
244 | spin_lock(&ds_lock); | ||
245 | return NULL; | 239 | return NULL; |
246 | } | ||
247 | 240 | ||
248 | context->ds = kzalloc(ds_cfg.sizeof_ds, GFP_KERNEL); | 241 | context->ds = kzalloc(ds_cfg.sizeof_ds, GFP_KERNEL); |
249 | if (!context->ds) { | 242 | if (!context->ds) { |
250 | kfree(context); | 243 | kfree(context); |
251 | spin_lock(&ds_lock); | ||
252 | return NULL; | 244 | return NULL; |
253 | } | 245 | } |
254 | 246 | ||
255 | spin_lock(&ds_lock); | 247 | spin_lock_irqsave(&ds_lock, irq); |
256 | /* | 248 | |
257 | * Check for race - another CPU could have allocated | ||
258 | * it meanwhile: | ||
259 | */ | ||
260 | if (*p_context) { | 249 | if (*p_context) { |
261 | kfree(context->ds); | 250 | kfree(context->ds); |
262 | kfree(context); | 251 | kfree(context); |
263 | return *p_context; | ||
264 | } | ||
265 | 252 | ||
266 | *p_context = context; | 253 | context = *p_context; |
254 | } else { | ||
255 | *p_context = context; | ||
267 | 256 | ||
268 | context->this = p_context; | 257 | context->this = p_context; |
269 | context->task = task; | 258 | context->task = task; |
270 | 259 | ||
271 | if (task) | 260 | if (task) |
272 | set_tsk_thread_flag(task, TIF_DS_AREA_MSR); | 261 | set_tsk_thread_flag(task, TIF_DS_AREA_MSR); |
273 | 262 | ||
274 | if (!task || (task == current)) | 263 | if (!task || (task == current)) |
275 | wrmsr(MSR_IA32_DS_AREA, (unsigned long)context->ds, 0); | 264 | wrmsrl(MSR_IA32_DS_AREA, |
276 | 265 | (unsigned long)context->ds); | |
277 | get_tracer(task); | 266 | } |
267 | spin_unlock_irqrestore(&ds_lock, irq); | ||
278 | } | 268 | } |
279 | 269 | ||
280 | context->count++; | 270 | context->count++; |
@@ -288,10 +278,12 @@ static inline struct ds_context *ds_alloc_context(struct task_struct *task) | |||
288 | */ | 278 | */ |
289 | static inline void ds_put_context(struct ds_context *context) | 279 | static inline void ds_put_context(struct ds_context *context) |
290 | { | 280 | { |
281 | unsigned long irq; | ||
282 | |||
291 | if (!context) | 283 | if (!context) |
292 | return; | 284 | return; |
293 | 285 | ||
294 | spin_lock(&ds_lock); | 286 | spin_lock_irqsave(&ds_lock, irq); |
295 | 287 | ||
296 | if (--context->count) | 288 | if (--context->count) |
297 | goto out; | 289 | goto out; |
@@ -313,7 +305,7 @@ static inline void ds_put_context(struct ds_context *context) | |||
313 | kfree(context->ds); | 305 | kfree(context->ds); |
314 | kfree(context); | 306 | kfree(context); |
315 | out: | 307 | out: |
316 | spin_unlock(&ds_lock); | 308 | spin_unlock_irqrestore(&ds_lock, irq); |
317 | } | 309 | } |
318 | 310 | ||
319 | 311 | ||
@@ -384,6 +376,7 @@ static int ds_request(struct task_struct *task, void *base, size_t size, | |||
384 | struct ds_context *context; | 376 | struct ds_context *context; |
385 | unsigned long buffer, adj; | 377 | unsigned long buffer, adj; |
386 | const unsigned long alignment = (1 << 3); | 378 | const unsigned long alignment = (1 << 3); |
379 | unsigned long irq; | ||
387 | int error = 0; | 380 | int error = 0; |
388 | 381 | ||
389 | if (!ds_cfg.sizeof_ds) | 382 | if (!ds_cfg.sizeof_ds) |
@@ -398,26 +391,27 @@ static int ds_request(struct task_struct *task, void *base, size_t size, | |||
398 | return -EOPNOTSUPP; | 391 | return -EOPNOTSUPP; |
399 | 392 | ||
400 | 393 | ||
401 | spin_lock(&ds_lock); | ||
402 | |||
403 | error = -ENOMEM; | ||
404 | context = ds_alloc_context(task); | 394 | context = ds_alloc_context(task); |
405 | if (!context) | 395 | if (!context) |
406 | goto out_unlock; | 396 | return -ENOMEM; |
397 | |||
398 | spin_lock_irqsave(&ds_lock, irq); | ||
407 | 399 | ||
408 | error = -EPERM; | 400 | error = -EPERM; |
409 | if (!check_tracer(task)) | 401 | if (!check_tracer(task)) |
410 | goto out_unlock; | 402 | goto out_unlock; |
411 | 403 | ||
404 | get_tracer(task); | ||
405 | |||
412 | error = -EALREADY; | 406 | error = -EALREADY; |
413 | if (context->owner[qual] == current) | 407 | if (context->owner[qual] == current) |
414 | goto out_unlock; | 408 | goto out_put_tracer; |
415 | error = -EPERM; | 409 | error = -EPERM; |
416 | if (context->owner[qual] != NULL) | 410 | if (context->owner[qual] != NULL) |
417 | goto out_unlock; | 411 | goto out_put_tracer; |
418 | context->owner[qual] = current; | 412 | context->owner[qual] = current; |
419 | 413 | ||
420 | spin_unlock(&ds_lock); | 414 | spin_unlock_irqrestore(&ds_lock, irq); |
421 | 415 | ||
422 | 416 | ||
423 | error = -ENOMEM; | 417 | error = -ENOMEM; |
@@ -465,10 +459,17 @@ static int ds_request(struct task_struct *task, void *base, size_t size, | |||
465 | out_release: | 459 | out_release: |
466 | context->owner[qual] = NULL; | 460 | context->owner[qual] = NULL; |
467 | ds_put_context(context); | 461 | ds_put_context(context); |
462 | put_tracer(task); | ||
463 | return error; | ||
464 | |||
465 | out_put_tracer: | ||
466 | spin_unlock_irqrestore(&ds_lock, irq); | ||
467 | ds_put_context(context); | ||
468 | put_tracer(task); | ||
468 | return error; | 469 | return error; |
469 | 470 | ||
470 | out_unlock: | 471 | out_unlock: |
471 | spin_unlock(&ds_lock); | 472 | spin_unlock_irqrestore(&ds_lock, irq); |
472 | ds_put_context(context); | 473 | ds_put_context(context); |
473 | return error; | 474 | return error; |
474 | } | 475 | } |
@@ -818,13 +819,21 @@ static const struct ds_configuration ds_cfg_var = { | |||
818 | .sizeof_ds = sizeof(long) * 12, | 819 | .sizeof_ds = sizeof(long) * 12, |
819 | .sizeof_field = sizeof(long), | 820 | .sizeof_field = sizeof(long), |
820 | .sizeof_rec[ds_bts] = sizeof(long) * 3, | 821 | .sizeof_rec[ds_bts] = sizeof(long) * 3, |
822 | #ifdef __i386__ | ||
821 | .sizeof_rec[ds_pebs] = sizeof(long) * 10 | 823 | .sizeof_rec[ds_pebs] = sizeof(long) * 10 |
824 | #else | ||
825 | .sizeof_rec[ds_pebs] = sizeof(long) * 18 | ||
826 | #endif | ||
822 | }; | 827 | }; |
823 | static const struct ds_configuration ds_cfg_64 = { | 828 | static const struct ds_configuration ds_cfg_64 = { |
824 | .sizeof_ds = 8 * 12, | 829 | .sizeof_ds = 8 * 12, |
825 | .sizeof_field = 8, | 830 | .sizeof_field = 8, |
826 | .sizeof_rec[ds_bts] = 8 * 3, | 831 | .sizeof_rec[ds_bts] = 8 * 3, |
832 | #ifdef __i386__ | ||
827 | .sizeof_rec[ds_pebs] = 8 * 10 | 833 | .sizeof_rec[ds_pebs] = 8 * 10 |
834 | #else | ||
835 | .sizeof_rec[ds_pebs] = 8 * 18 | ||
836 | #endif | ||
828 | }; | 837 | }; |
829 | 838 | ||
830 | static inline void | 839 | static inline void |
@@ -878,4 +887,3 @@ void ds_free(struct ds_context *context) | |||
878 | while (leftovers--) | 887 | while (leftovers--) |
879 | ds_put_context(context); | 888 | ds_put_context(context); |
880 | } | 889 | } |
881 | #endif /* CONFIG_X86_DS */ | ||