// entry), but only this function is executed on every unlock event
err = dom_cnode_delete(del_st->capref);
if (err_no(err) != SYS_ERR_RETRY_THROUGH_MONITOR) {
+ // If cap is already locked, just enqueue for retry
+ if (err_no(err) == SYS_ERR_CAP_LOCKED) {
+ DEBUG_CAPOPS("%s: from cnode_delete(): cap already locked, queuing retry\n", __FUNCTION__);
+ caplock_wait(del_st->capref, &del_st->lock_qn,
+ MKCLOSURE(delete_trylock_cont, del_st));
+ return;
+ }
+ // If cap not found, it has been deleted elsewhere, return OK
if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
- err = SYS_ERR_OK;
+ DEBUG_CAPOPS("%s: from cnode_delete(): cap not found, got deleted from elsewhere\n", __FUNCTION__);
+ err = err_push(SYS_ERR_OK, err);
}
goto report_error;
}
// try a simple delete
DEBUG_CAPOPS("%s: trying simple delete\n", __FUNCTION__);
err = dom_cnode_delete(cap);
- if (err_no(err) != SYS_ERR_RETRY_THROUGH_MONITOR) {
- DEBUG_CAPOPS("%s: err != RETRY\n", __FUNCTION__);
+ // We can also continue here if we get SYS_ERR_CAP_LOCKED, as we're going
+ // to handle already locked caps correctly in delete_trylock_cont().
+ // -SG, 2017-05-02
+ if (err_no(err) != SYS_ERR_RETRY_THROUGH_MONITOR &&
+ err_no(err) != SYS_ERR_CAP_LOCKED)
+ {
+ DEBUG_CAPOPS("%s: err != RETRY && err != LOCKED\n", __FUNCTION__);
goto err_cont;
}
- // simple delete was not able to delete cap as it was last copy and:
- // - may have remote copies, need to move or revoke cap
- // - contains further slots which need to be cleared
+ // simple delete was not able to delete cap as:
+ // * it was last copy and:
+ // - may have remote copies, need to move or revoke cap
+ // - contains further slots which need to be cleared
+ // * currently locked
struct delete_st *del_st;
err = calloce(1, sizeof(*del_st), &del_st);