return PTR_ERR(table);
if (table->flags & NFT_TABLE_INACTIVE)
return -ENOENT;
-
- if (!list_empty(&table->chains) || !list_empty(&table->sets))
+ if (table->use > 0)
return -EBUSY;
nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
static void nf_tables_table_destroy(struct nft_ctx *ctx)
{
+ BUG_ON(ctx->table->use > 0);
+
kfree(ctx->table);
module_put(ctx->afi->owner);
}
if (err < 0)
goto err2;
+ table->use++;
list_add_tail(&chain->list, &table->chains);
return 0;
err2:
return PTR_ERR(chain);
if (chain->flags & NFT_CHAIN_INACTIVE)
return -ENOENT;
- if (!list_empty(&chain->rules) || chain->use > 0)
+ if (chain->use > 0)
return -EBUSY;
nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
if (err < 0)
return err;
+ table->use--;
list_del(&chain->list);
return 0;
}
err = -ENOMEM;
goto err3;
}
+ chain->use++;
return 0;
err3:
if (nft_trans_rule_add(ctx, NFT_MSG_DELRULE, rule) == NULL)
return -ENOMEM;
nft_rule_disactivate_next(ctx->net, rule);
+ ctx->chain->use--;
return 0;
}
return -ENOENT;
goto err2;
list_add_tail(&set->list, &table->sets);
+ table->use++;
return 0;
err2:
return err;
list_del(&set->list);
+ ctx.table->use--;
return 0;
}
err = nft_add_set_elem(&ctx, set, attr);
if (err < 0)
break;
+
+ set->nelems++;
}
return err;
}
err = nft_del_setelem(&ctx, set, attr);
if (err < 0)
break;
+
+ set->nelems--;
}
return err;
}
case NFT_MSG_NEWCHAIN:
if (nft_trans_chain_update(trans))
nft_chain_commit_update(trans);
- else {
+ else
trans->ctx.chain->flags &= ~NFT_CHAIN_INACTIVE;
- trans->ctx.table->use++;
- }
+
nf_tables_chain_notify(&trans->ctx, NFT_MSG_NEWCHAIN);
nft_trans_destroy(trans);
break;
case NFT_MSG_DELCHAIN:
- trans->ctx.table->use--;
nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN);
if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT) &&
trans->ctx.chain->flags & NFT_BASE_CHAIN) {
break;
case NFT_MSG_NEWSET:
nft_trans_set(trans)->flags &= ~NFT_SET_INACTIVE;
+ /* This avoids hitting -EBUSY when deleting the table
+ * from the transaction.
+ */
+ if (nft_trans_set(trans)->flags & NFT_SET_ANONYMOUS &&
+ !list_empty(&nft_trans_set(trans)->bindings))
+ trans->ctx.table->use--;
+
nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
NFT_MSG_NEWSET);
nft_trans_destroy(trans);
NFT_MSG_DELSET);
break;
case NFT_MSG_NEWSETELEM:
- nft_trans_elem_set(trans)->nelems++;
nf_tables_setelem_notify(&trans->ctx,
nft_trans_elem_set(trans),
&nft_trans_elem(trans),
nft_trans_destroy(trans);
break;
case NFT_MSG_DELSETELEM:
- nft_trans_elem_set(trans)->nelems--;
nf_tables_setelem_notify(&trans->ctx,
nft_trans_elem_set(trans),
&nft_trans_elem(trans),
nft_trans_destroy(trans);
} else {
+ trans->ctx.table->use--;
list_del(&trans->ctx.chain->list);
if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT) &&
trans->ctx.chain->flags & NFT_BASE_CHAIN) {
}
break;
case NFT_MSG_DELCHAIN:
+ trans->ctx.table->use++;
list_add_tail(&trans->ctx.chain->list,
&trans->ctx.table->chains);
nft_trans_destroy(trans);
break;
case NFT_MSG_NEWRULE:
+ trans->ctx.chain->use--;
list_del_rcu(&nft_trans_rule(trans)->list);
break;
case NFT_MSG_DELRULE:
+ trans->ctx.chain->use++;
nft_rule_clear(trans->ctx.net, nft_trans_rule(trans));
nft_trans_destroy(trans);
break;
case NFT_MSG_NEWSET:
+ trans->ctx.table->use--;
list_del(&nft_trans_set(trans)->list);
break;
case NFT_MSG_DELSET:
+ trans->ctx.table->use++;
list_add_tail(&nft_trans_set(trans)->list,
&trans->ctx.table->sets);
nft_trans_destroy(trans);
break;
case NFT_MSG_NEWSETELEM:
+ nft_trans_elem_set(trans)->nelems--;
set = nft_trans_elem_set(trans);
set->ops->get(set, &nft_trans_elem(trans));
set->ops->remove(set, &nft_trans_elem(trans));
nft_trans_destroy(trans);
break;
case NFT_MSG_DELSETELEM:
+ nft_trans_elem_set(trans)->nelems++;
nft_trans_destroy(trans);
break;
}