static void
__vr_htable_oentry_invalidate(struct vr_htable *table, vr_hentry_t *ent)
{
    vr_hentry_t *prev, *head_ent;

    if (!table || !ent)
        return;

    if (ent->hentry_flags & VR_HENTRY_FLAG_IN_FREE_LIST)
        return;

    if (ent->hentry_index >= table->ht_hentries) {
        head_ent = __vr_htable_get_hentry_by_index((vr_htable_t)table,
                                            ent->hentry_bucket_index);
        for (prev = head_ent; prev; prev = prev->hentry_next) {
            if (prev->hentry_next == ent) {

                prev->hentry_next = ent->hentry_next;

                if (prev->hentry_next) {
                    prev->hentry_next_index =
                        ent->hentry_next->hentry_index;
                } else {
                    prev->hentry_next_index = VR_INVALID_HENTRY_INDEX;
                }

                break;
            }
        }

        vr_htable_oentry_invalidate(table, ent);
    }

    return;
}
Example #2
0
static void
vr_htable_hentry_defer_delete(struct vrouter *router, void *arg)
{
    vr_hentry_t *ent;
    struct vr_hentry_delete_data *defer_data;
    struct vr_htable *table;

    defer_data = (struct vr_hentry_delete_data *)arg;
    table = (struct vr_htable *)(defer_data->hd_table);

    ent = __vr_htable_get_hentry_by_index((vr_htable_t)table,
                                        defer_data->hd_index);
    vr_htable_oentry_invalidate(table, ent);

    return;
}
Example #3
0
void
vr_htable_reset(vr_htable_t htable, htable_trav_cb cb, void *data)
{
    unsigned int i;
    vr_hentry_t *ent, *next;
    struct vr_htable *table = (struct vr_htable *)htable;

    if (!table || !cb)
        return;

    for (i = 0; i < table->ht_hentries + table->ht_oentries; i++) {
        ent = __vr_htable_get_hentry_by_index(htable, i);

        cb(htable, ent, i, data);

        if (ent->hentry_flags & VR_HENTRY_FLAG_VALID) {
            ent->hentry_flags &= ~VR_HENTRY_FLAG_VALID;
            (void)__sync_sub_and_fetch(&table->ht_used_entries, 1);
        }


        if ((i < table->ht_hentries) && ent->hentry_next) {
            next = ent->hentry_next;
            ent->hentry_next = NULL;
            ent->hentry_next_index = VR_INVALID_HENTRY_INDEX;
            ent = next;

            while (ent) {
                next = ent->hentry_next;

                if (ent->hentry_flags & VR_HENTRY_FLAG_VALID) {
                    ent->hentry_flags &= ~VR_HENTRY_FLAG_VALID;
                    (void)__sync_sub_and_fetch(&table->ht_used_entries, 1);
                }

                vr_htable_oentry_invalidate(table, ent);

                ent = next;
            }
        }
    }

    return;
}
Example #4
0
static void
vr_htable_hentry_scheduled_delete(void *arg)
{
    unsigned int count;
    struct vr_hentry_delete_data *delete_data, *defer_data;
    vr_hentry_t *head_ent, *ent, *prev, *next;
    struct vr_htable *table;


    delete_data = (struct vr_hentry_delete_data *)arg;
    table = delete_data->hd_table;

    head_ent = __vr_htable_get_hentry_by_index((vr_htable_t)(table),
                                                delete_data->hd_index);

    if (!head_ent)
        return;

    (void)__sync_bool_compare_and_swap(&delete_data->hd_scheduled, 1, 0);

    /*
     * We attempt to delete only those many entries that have been
     * delete marked. If some new entries are delete marked while
     * processing these, they will get scheduled in new work item
     */
    count = delete_data->hd_count;
    (void)__sync_sub_and_fetch(&delete_data->hd_count, count);

    prev = head_ent;
    ent = head_ent->hentry_next;

    while (count && ent) {

        /*
         * Process only if delete marked. If already processed,
         * delete marking is changed to delete processed
         */
        if (ent->hentry_flags & VR_HENTRY_FLAG_DELETE_MARKED) {

            /*
             * As the insertion happens only at head entry, it has
             * to be verified if something is inserted while delete
             * attemped. If inserted, traversal needs to restart, to
             * get hold of the new previous
             */
            if (prev == head_ent) {
                if (!__sync_bool_compare_and_swap(&prev->hentry_next,
                                                      ent, ent->hentry_next)) {
                    prev = head_ent;
                    ent = head_ent->hentry_next;
                    continue;
                }
            } else {
                prev->hentry_next = ent->hentry_next;
            }

            count--;

            /* update next index for the previous */
            if (ent->hentry_next)
                prev->hentry_next_index = ent->hentry_next->hentry_index;
            else
                prev->hentry_next_index = VR_INVALID_HENTRY_INDEX;

            ent->hentry_flags &= ~VR_HENTRY_FLAG_DELETE_MARKED;
            ent->hentry_flags |= VR_HENTRY_FLAG_DELETE_PROCESSED;
        }

        next = ent->hentry_next;

        /*
         * A separate check for VR_HENTRY_FLAG_DELETE_PROCESSED flag to
         * defer the entry if we ever failed to allocate memeory while
         * deferring it
         */
        if (ent->hentry_flags & VR_HENTRY_FLAG_DELETE_PROCESSED) {

            /*
             * Defer the entry to reset the values. If alloc of
             * defer data fails, this entry will be in delete state
             * for ever
             */
            if (!vr_not_ready) {
                defer_data = vr_get_defer_data(sizeof(*defer_data));
                if (defer_data) {
                    defer_data->hd_table = delete_data->hd_table;
                    defer_data->hd_index = ent->hentry_index;
                    vr_defer(delete_data->hd_table->ht_router,
                         vr_htable_hentry_defer_delete, (void *)defer_data);
                }
            } else {
                vr_htable_oentry_invalidate(table, ent);
                ent = next;
                continue;
            }
        }

        /* Previous should not be under deletion */
        if (!(ent->hentry_flags & VR_HENTRY_FLAG_UNDER_DELETION))
            prev = ent;

        ent = next;
    }

    return;
}