/*
- * Copyright (c) 2007, 2008, 2009, 2010 Nicira Networks.
+ * Copyright (c) 2007, 2008, 2009, 2010, 2011 Nicira Networks.
* Distributed under the terms of the GNU GPL version 2.
*
* Significant portions of this file may be copied from parts of the Linux
#include "table.h"
#include "vport-internal_dev.h"
-#include "compat.h"
-
int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd);
EXPORT_SYMBOL(dp_ioctl_hook);
return dp;
}
-static struct tbl *get_table_protected(const struct datapath *dp)
+static struct tbl *get_table_protected(struct datapath *dp)
{
return rcu_dereference_protected(dp->table,
lockdep_is_held(&dp->mutex));
}
-static struct vport *get_vport_protected(const struct datapath *dp,
- u16 port_no)
+static struct vport *get_vport_protected(struct datapath *dp, u16 port_no)
{
return rcu_dereference_protected(dp->ports[port_no],
lockdep_is_held(&dp->mutex));
const struct vport *port,
int event, unsigned int flags)
{
- const struct datapath *dp = port->dp;
+ struct datapath *dp = port->dp;
int ifindex = vport_get_ifindex(port);
int iflink = vport_get_iflink(port);
struct ifinfomsg *hdr;
goto err_put_module;
INIT_LIST_HEAD(&dp->port_list);
mutex_init(&dp->mutex);
+ mutex_lock(&dp->mutex);
dp->dp_idx = dp_idx;
for (i = 0; i < DP_N_QUEUES; i++)
skb_queue_head_init(&dp->queues[i]);
rcu_assign_pointer(dps[dp_idx], dp);
dp_sysfs_add_dp(dp);
+ mutex_unlock(&dp->mutex);
mutex_unlock(&dp_mutex);
rtnl_unlock();
err_destroy_table:
tbl_destroy(get_table_protected(dp), NULL);
err_free_dp:
+ mutex_unlock(&dp->mutex);
kfree(dp);
err_put_module:
module_put(THIS_MODULE);
return err;
}
-static void do_destroy_dp(struct datapath *dp)
+static void destroy_dp_rcu(struct rcu_head *rcu)
{
- struct vport *p, *n;
+ struct datapath *dp = container_of(rcu, struct datapath, rcu);
int i;
- list_for_each_entry_safe (p, n, &dp->port_list, node)
- if (p->port_no != ODPP_LOCAL)
- dp_detach_port(p);
-
- dp_sysfs_del_dp(dp);
-
- rcu_assign_pointer(dps[dp->dp_idx], NULL);
-
- dp_detach_port(get_vport_protected(dp, ODPP_LOCAL));
- tbl_destroy(get_table_protected(dp), flow_free_tbl);
-
for (i = 0; i < DP_N_QUEUES; i++)
skb_queue_purge(&dp->queues[i]);
+
+ tbl_destroy((struct tbl __force *)dp->table, flow_free_tbl);
free_percpu(dp->stats_percpu);
kobject_put(&dp->ifobj);
- module_put(THIS_MODULE);
}
static int destroy_dp(int dp_idx)
{
struct datapath *dp;
- int err;
+ int err = 0;
+ struct vport *p, *n;
rtnl_lock();
mutex_lock(&dp_mutex);
dp = get_dp(dp_idx);
- err = -ENODEV;
- if (!dp)
- goto err_unlock;
+ if (!dp) {
+ err = -ENODEV;
+ goto out;
+ }
- do_destroy_dp(dp);
- err = 0;
+ mutex_lock(&dp->mutex);
-err_unlock:
+ list_for_each_entry_safe (p, n, &dp->port_list, node)
+ if (p->port_no != ODPP_LOCAL)
+ dp_detach_port(p);
+
+ dp_sysfs_del_dp(dp);
+ rcu_assign_pointer(dps[dp->dp_idx], NULL);
+ dp_detach_port(get_vport_protected(dp, ODPP_LOCAL));
+
+ mutex_unlock(&dp->mutex);
+ call_rcu(&dp->rcu, destroy_dp_rcu);
+ module_put(THIS_MODULE);
+
+out:
mutex_unlock(&dp_mutex);
rtnl_unlock();
return err;
}
-/* Called with RTNL lock and dp_mutex. */
+/* Called with RTNL lock and dp->mutex. */
static int new_vport(struct datapath *dp, struct odp_port *odp_port, int port_no)
{
struct vport_parms parms;
struct tbl_node *flow_node;
struct sw_flow *flow;
struct tbl *table;
+ struct sw_flow_actions *acts = NULL;
int error;
u32 hash;
flow_node = tbl_lookup(table, &uf->flow.key, hash, flow_cmp);
if (!flow_node) {
/* No such flow. */
- struct sw_flow_actions *acts;
-
error = -ENOENT;
if (!(uf->flags & ODPPF_CREATE))
goto error;
return 0;
error_free_flow_acts:
- kfree(flow->sf_acts);
+ kfree(acts);
error_free_flow:
flow->sf_acts = NULL;
flow_put(flow);
}
static struct file_operations openvswitch_fops = {
+ .owner = THIS_MODULE,
.read = openvswitch_read,
.poll = openvswitch_poll,
.unlocked_ioctl = openvswitch_ioctl,