| 2376 | } |
| 2377 | |
| 2378 | static int |
| 2379 | do_set_ceiling(struct thread *td, struct umutex *m, uint32_t ceiling, |
| 2380 | uint32_t *old_ceiling) |
| 2381 | { |
| 2382 | struct umtx_q *uq; |
| 2383 | uint32_t flags, id, owner, save_ceiling; |
| 2384 | int error, rv, rv1; |
| 2385 | |
| 2386 | error = fueword32(&m->m_flags, &flags); |
| 2387 | if (error == -1) |
| 2388 | return (EFAULT); |
| 2389 | if ((flags & UMUTEX_PRIO_PROTECT) == 0) |
| 2390 | return (EINVAL); |
| 2391 | if (ceiling > RTP_PRIO_MAX) |
| 2392 | return (EINVAL); |
| 2393 | id = td->td_tid; |
| 2394 | uq = td->td_umtxq; |
| 2395 | if ((error = umtx_key_get(m, (flags & UMUTEX_ROBUST) != 0 ? |
| 2396 | TYPE_PP_ROBUST_UMUTEX : TYPE_PP_UMUTEX, GET_SHARE(flags), |
| 2397 | &uq->uq_key)) != 0) |
| 2398 | return (error); |
| 2399 | for (;;) { |
| 2400 | umtxq_lock(&uq->uq_key); |
| 2401 | umtxq_busy(&uq->uq_key); |
| 2402 | umtxq_unlock(&uq->uq_key); |
| 2403 | |
| 2404 | rv = fueword32(&m->m_ceilings[0], &save_ceiling); |
| 2405 | if (rv == -1) { |
| 2406 | error = EFAULT; |
| 2407 | break; |
| 2408 | } |
| 2409 | |
| 2410 | rv = casueword32(&m->m_owner, UMUTEX_CONTESTED, &owner, |
| 2411 | id | UMUTEX_CONTESTED); |
| 2412 | if (rv == -1) { |
| 2413 | error = EFAULT; |
| 2414 | break; |
| 2415 | } |
| 2416 | |
| 2417 | if (rv == 0) { |
| 2418 | MPASS(owner == UMUTEX_CONTESTED); |
| 2419 | rv = suword32(&m->m_ceilings[0], ceiling); |
| 2420 | rv1 = suword32(&m->m_owner, UMUTEX_CONTESTED); |
| 2421 | error = (rv == 0 && rv1 == 0) ? 0: EFAULT; |
| 2422 | break; |
| 2423 | } |
| 2424 | |
| 2425 | if ((owner & ~UMUTEX_CONTESTED) == id) { |
| 2426 | rv = suword32(&m->m_ceilings[0], ceiling); |
| 2427 | error = rv == 0 ? 0 : EFAULT; |
| 2428 | break; |
| 2429 | } |
| 2430 | |
| 2431 | if (owner == UMUTEX_RB_OWNERDEAD) { |
| 2432 | error = EOWNERDEAD; |
| 2433 | break; |
| 2434 | } else if (owner == UMUTEX_RB_NOTRECOV) { |
| 2435 | error = ENOTRECOVERABLE; |
no test coverage detected