]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - net/core/net-sysfs.c
Merge tag 'v2.6.37' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / net / core / net-sysfs.c
index af4dfbadf2a09ea496653990ae8e1da823a059e1..7f902cad10f8b13d7096f53905e3a47bb3c12d25 100644 (file)
@@ -515,7 +515,7 @@ static ssize_t rx_queue_attr_store(struct kobject *kobj, struct attribute *attr,
        return attribute->store(queue, attribute, buf, count);
 }
 
-static struct sysfs_ops rx_queue_sysfs_ops = {
+static const struct sysfs_ops rx_queue_sysfs_ops = {
        .show = rx_queue_attr_show,
        .store = rx_queue_attr_store,
 };
@@ -598,7 +598,8 @@ static ssize_t store_rps_map(struct netdev_rx_queue *queue,
        }
 
        spin_lock(&rps_map_lock);
-       old_map = queue->rps_map;
+       old_map = rcu_dereference_protected(queue->rps_map,
+                                           lockdep_is_held(&rps_map_lock));
        rcu_assign_pointer(queue->rps_map, map);
        spin_unlock(&rps_map_lock);
 
@@ -677,7 +678,8 @@ static ssize_t store_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue,
                table = NULL;
 
        spin_lock(&rps_dev_flow_lock);
-       old_table = queue->rps_flow_table;
+       old_table = rcu_dereference_protected(queue->rps_flow_table,
+                                             lockdep_is_held(&rps_dev_flow_lock));
        rcu_assign_pointer(queue->rps_flow_table, table);
        spin_unlock(&rps_dev_flow_lock);
 
@@ -705,16 +707,26 @@ static void rx_queue_release(struct kobject *kobj)
 {
        struct netdev_rx_queue *queue = to_rx_queue(kobj);
        struct netdev_rx_queue *first = queue->first;
+       struct rps_map *map;
+       struct rps_dev_flow_table *flow_table;
 
-       if (queue->rps_map)
-               call_rcu(&queue->rps_map->rcu, rps_map_release);
 
-       if (queue->rps_flow_table)
-               call_rcu(&queue->rps_flow_table->rcu,
-                   rps_dev_flow_table_release);
+       map = rcu_dereference_raw(queue->rps_map);
+       if (map) {
+               RCU_INIT_POINTER(queue->rps_map, NULL);
+               call_rcu(&map->rcu, rps_map_release);
+       }
+
+       flow_table = rcu_dereference_raw(queue->rps_flow_table);
+       if (flow_table) {
+               RCU_INIT_POINTER(queue->rps_flow_table, NULL);
+               call_rcu(&flow_table->rcu, rps_dev_flow_table_release);
+       }
 
        if (atomic_dec_and_test(&first->count))
                kfree(first);
+       else
+               memset(kobj, 0, sizeof(*kobj));
 }
 
 static struct kobj_type rx_queue_ktype = {
@@ -726,6 +738,7 @@ static struct kobj_type rx_queue_ktype = {
 static int rx_queue_add_kobject(struct net_device *net, int index)
 {
        struct netdev_rx_queue *queue = net->_rx + index;
+       struct netdev_rx_queue *first = queue->first;
        struct kobject *kobj = &queue->kobj;
        int error = 0;
 
@@ -738,38 +751,43 @@ static int rx_queue_add_kobject(struct net_device *net, int index)
        }
 
        kobject_uevent(kobj, KOBJ_ADD);
+       atomic_inc(&first->count);
 
        return error;
 }
 
-static int rx_queue_register_kobjects(struct net_device *net)
+int
+net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num)
 {
        int i;
        int error = 0;
 
-       net->queues_kset = kset_create_and_add("queues",
-           NULL, &net->dev.kobj);
-       if (!net->queues_kset)
-               return -ENOMEM;
-       for (i = 0; i < net->num_rx_queues; i++) {
+       for (i = old_num; i < new_num; i++) {
                error = rx_queue_add_kobject(net, i);
-               if (error)
+               if (error) {
+                       new_num = old_num;
                        break;
+               }
        }
 
-       if (error)
-               while (--i >= 0)
-                       kobject_put(&net->_rx[i].kobj);
+       while (--i >= new_num)
+               kobject_put(&net->_rx[i].kobj);
 
        return error;
 }
 
-static void rx_queue_remove_kobjects(struct net_device *net)
+static int rx_queue_register_kobjects(struct net_device *net)
 {
-       int i;
+       net->queues_kset = kset_create_and_add("queues",
+           NULL, &net->dev.kobj);
+       if (!net->queues_kset)
+               return -ENOMEM;
+       return net_rx_queue_update_kobjects(net, 0, net->real_num_rx_queues);
+}
 
-       for (i = 0; i < net->num_rx_queues; i++)
-               kobject_put(&net->_rx[i].kobj);
+static void rx_queue_remove_kobjects(struct net_device *net)
+{
+       net_rx_queue_update_kobjects(net, net->real_num_rx_queues, 0);
        kset_unregister(net->queues_kset);
 }
 #endif /* CONFIG_RPS */
@@ -789,12 +807,13 @@ static const void *net_netlink_ns(struct sock *sk)
        return sock_net(sk);
 }
 
-static struct kobj_ns_type_operations net_ns_type_operations = {
+struct kobj_ns_type_operations net_ns_type_operations = {
        .type = KOBJ_NS_TYPE_NET,
        .current_ns = net_current_ns,
        .netlink_ns = net_netlink_ns,
        .initial_ns = net_initial_ns,
 };
+EXPORT_SYMBOL_GPL(net_ns_type_operations);
 
 static void net_kobj_ns_exit(struct net *net)
 {