dp = kzalloc(sizeof *dp, GFP_KERNEL);
if (dp == NULL)
goto err_put_module;
-
+ INIT_LIST_HEAD(&dp->port_list);
mutex_init(&dp->mutex);
dp->dp_idx = dp_idx;
for (i = 0; i < DP_N_QUEUES; i++)
skb_queue_head_init(&dp->queues[i]);
init_waitqueue_head(&dp->waitqueue);
+ /* Allocate table. */
+ err = -ENOMEM;
+ rcu_assign_pointer(dp->table, dp_table_create(DP_L1_SIZE));
+ if (!dp->table)
+ goto err_free_dp;
+
/* Setup our datapath device */
dp_dev = dp_dev_create(dp, devname, ODPP_LOCAL);
err = PTR_ERR(dp_dev);
if (IS_ERR(dp_dev))
- goto err_free_dp;
-
- err = -ENOMEM;
- rcu_assign_pointer(dp->table, dp_table_create(DP_L1_SIZE));
- if (!dp->table)
- goto err_destroy_dp_dev;
- INIT_LIST_HEAD(&dp->port_list);
+ goto err_destroy_table;
err = new_nbp(dp, dp_dev, ODPP_LOCAL);
- if (err)
+ if (err) {
+ dp_dev_destroy(dp_dev);
goto err_destroy_table;
+ }
dp->drop_frags = 0;
dp->stats_percpu = alloc_percpu(struct dp_stats_percpu);
return 0;
err_destroy_local_port:
- dp_del_port(dp->ports[ODPP_LOCAL], NULL);
+ dp_del_port(dp->ports[ODPP_LOCAL]);
err_destroy_table:
dp_table_destroy(dp->table, 0);
-err_destroy_dp_dev:
- dp_dev_destroy(dp_dev);
err_free_dp:
kfree(dp);
err_put_module:
return err;
}
-static void do_destroy_dp(struct datapath *dp, struct list_head *dp_devs)
+static void do_destroy_dp(struct datapath *dp)
{
struct net_bridge_port *p, *n;
int i;
+ list_for_each_entry_safe (p, n, &dp->port_list, node)
+ if (p->port_no != ODPP_LOCAL)
+ dp_del_port(p);
+
if (dp_del_dp_hook)
dp_del_dp_hook(dp);
- /* Drop references to DP. */
- list_for_each_entry_safe (p, n, &dp->port_list, node)
- dp_del_port(p, dp_devs);
-
rcu_assign_pointer(dps[dp->dp_idx], NULL);
- synchronize_rcu();
- /* Wait until no longer in use, then destroy it. */
- synchronize_rcu();
+ dp_del_port(dp->ports[ODPP_LOCAL]);
+
dp_table_destroy(dp->table, 1);
+
for (i = 0; i < DP_N_QUEUES; i++)
skb_queue_purge(&dp->queues[i]);
for (i = 0; i < DP_MAX_GROUPS; i++)
static int destroy_dp(int dp_idx)
{
- struct dp_dev *dp_dev, *next;
struct datapath *dp;
- LIST_HEAD(dp_devs);
int err;
rtnl_lock();
if (!dp)
goto err_unlock;
- do_destroy_dp(dp, &dp_devs);
+ do_destroy_dp(dp);
err = 0;
err_unlock:
mutex_unlock(&dp_mutex);
rtnl_unlock();
- list_for_each_entry_safe (dp_dev, next, &dp_devs, list)
- free_netdev(dp_dev->dev);
return err;
}
return err;
}
-int dp_del_port(struct net_bridge_port *p, struct list_head *dp_devs)
+int dp_del_port(struct net_bridge_port *p)
{
ASSERT_RTNL();
if (is_dp_dev(p->dev)) {
dp_dev_destroy(p->dev);
- if (dp_devs) {
- struct dp_dev *dp_dev = dp_dev_priv(p->dev);
- list_add(&dp_dev->list, dp_devs);
- }
}
if (p->port_no != ODPP_LOCAL && dp_del_if_hook) {
dp_del_if_hook(p);
static int del_port(int dp_idx, int port_no)
{
- struct dp_dev *dp_dev, *next;
struct net_bridge_port *p;
struct datapath *dp;
LIST_HEAD(dp_devs);
if (!p)
goto out_unlock_dp;
- err = dp_del_port(p, &dp_devs);
+ err = dp_del_port(p);
out_unlock_dp:
mutex_unlock(&dp->mutex);
out_unlock_rtnl:
rtnl_unlock();
out:
- list_for_each_entry_safe (dp_dev, next, &dp_devs, list)
- free_netdev(dp_dev->dev);
return err;
}
struct sw_flow *flow;
WARN_ON_ONCE(skb_shared(skb));
- WARN_ON_ONCE(skb->destructor);
/* BHs are off so we don't have to use get_cpu()/put_cpu() here. */
stats = percpu_ptr(dp->stats_percpu, smp_processor_id());
ssize_t openvswitch_read(struct file *f, char __user *buf, size_t nbytes,
loff_t *ppos)
{
+ /* XXX is there sufficient synchronization here? */
int listeners = (int) f->private_data;
int dp_idx = iminor(f->f_dentry->d_inode);
struct datapath *dp = get_dp(dp_idx);
static unsigned int openvswitch_poll(struct file *file, poll_table *wait)
{
+ /* XXX is there sufficient synchronization here? */
int dp_idx = iminor(file->f_dentry->d_inode);
struct datapath *dp = get_dp(dp_idx);
unsigned int mask;