Mon, Jul 08, 2019 at 06:06:09PM CEST, pablo@xxxxxxxxxxxxx wrote: >This patch adds tcf_block_setup() which uses the flow block API. > >This infrastructure takes the flow block callbacks coming from the >driver and register/unregister to/from the cls_api core. > >Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> [...] >+static int tcf_block_bind(struct tcf_block *block, >+ struct flow_block_offload *bo) >+{ >+ struct flow_block_cb *block_cb, *next; >+ int err, i = 0; >+ >+ list_for_each_entry(block_cb, &bo->cb_list, driver_list) { >+ err = tcf_block_playback_offloads(block, block_cb->cb, >+ block_cb->cb_priv, true, >+ tcf_block_offload_in_use(block), >+ bo->extack); >+ if (err) >+ goto err_unroll; >+ >+ list_add(&block_cb->list, &block->cb_list); >+ i++; >+ } >+ list_splice(&bo->cb_list, bo->driver_block_list); This cl/driver_block list magic is really very hard to follow. Could you please make it more clear? >+ >+ return 0; >+ >+err_unroll: >+ list_for_each_entry_safe(block_cb, next, &bo->cb_list, driver_list) { >+ if (i-- > 0) { >+ list_del(&block_cb->list); >+ tcf_block_playback_offloads(block, block_cb->cb, >+ block_cb->cb_priv, false, >+ tcf_block_offload_in_use(block), >+ NULL); >+ } >+ flow_block_cb_free(block_cb); >+ } >+ >+ return err; >+} >+ >+static void tcf_block_unbind(struct tcf_block *block, >+ struct flow_block_offload *bo) >+{ >+ struct flow_block_cb *block_cb, *next; >+ >+ list_for_each_entry_safe(block_cb, next, &bo->cb_list, driver_list) { >+ list_del(&block_cb->driver_list); >+ tcf_block_playback_offloads(block, block_cb->cb, >+ block_cb->cb_priv, false, >+ tcf_block_offload_in_use(block), >+ NULL); >+ list_del(&block_cb->list); >+ flow_block_cb_free(block_cb); >+ } >+} [...]