T245: capops: fix distributed delete
Fix distributed delete for the case where the cap to delete is already locked
when we enter capops_delete().  In that case we need to actually continue the
delete and queue it for retrying rather than returning the error to the
caller.
Closes T245.
@@ -410,8 +410,17 @@ delete_trylock_cont(void *st)
// 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;
}
@@ -487,14 +496,21 @@ capops_delete(struct domcapref cap,
// 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:
+ // 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);
