diff options
Diffstat (limited to 'net/core')
| -rw-r--r-- | net/core/dev.c | 11 | ||||
| -rw-r--r-- | net/core/net_namespace.c | 4 | ||||
| -rw-r--r-- | net/core/netprio_cgroup.c | 78 | ||||
| -rw-r--r-- | net/core/scm.c | 22 | ||||
| -rw-r--r-- | net/core/skbuff.c | 2 | 
5 files changed, 73 insertions, 44 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 84f01ba81a3..1cb0d8a6aa6 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2444,8 +2444,12 @@ static void skb_update_prio(struct sk_buff *skb)  {  	struct netprio_map *map = rcu_dereference_bh(skb->dev->priomap); -	if ((!skb->priority) && (skb->sk) && map) -		skb->priority = map->priomap[skb->sk->sk_cgrp_prioidx]; +	if (!skb->priority && skb->sk && map) { +		unsigned int prioidx = skb->sk->sk_cgrp_prioidx; + +		if (prioidx < map->priomap_len) +			skb->priority = map->priomap[prioidx]; +	}  }  #else  #define skb_update_prio(skb) @@ -6279,7 +6283,8 @@ static struct hlist_head *netdev_create_hash(void)  /* Initialize per network namespace state */  static int __net_init netdev_init(struct net *net)  { -	INIT_LIST_HEAD(&net->dev_base_head); +	if (net != &init_net) +		INIT_LIST_HEAD(&net->dev_base_head);  	net->dev_name_head = netdev_create_hash();  	if (net->dev_name_head == NULL) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index dddbacb8f28..42f1e1c7514 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -27,7 +27,9 @@ static DEFINE_MUTEX(net_mutex);  LIST_HEAD(net_namespace_list);  EXPORT_SYMBOL_GPL(net_namespace_list); -struct net init_net; +struct net init_net = { +	.dev_base_head = LIST_HEAD_INIT(init_net.dev_base_head), +};  EXPORT_SYMBOL(init_net);  #define INITIAL_NET_GEN_PTRS	13 /* +1 for len +2 for rcu_head */ diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c index 5b8aa2fae48..b2e9caa1ad1 100644 --- a/net/core/netprio_cgroup.c +++ b/net/core/netprio_cgroup.c @@ -49,8 +49,9 @@ static int get_prioidx(u32 *prio)  		return -ENOSPC;  	}  	set_bit(prioidx, prioidx_map); +	if (atomic_read(&max_prioidx) < prioidx) +		atomic_set(&max_prioidx, prioidx);  	spin_unlock_irqrestore(&prioidx_map_lock, flags); -	atomic_set(&max_prioidx, prioidx);  	*prio = prioidx;  	return 0;  } @@ -64,7 +65,7 @@ static void put_prioidx(u32 idx)  	spin_unlock_irqrestore(&prioidx_map_lock, flags);  } -static void extend_netdev_table(struct net_device *dev, u32 new_len) +static int extend_netdev_table(struct net_device *dev, u32 new_len)  {  	size_t new_size = sizeof(struct netprio_map) +  			   ((sizeof(u32) * new_len)); @@ -76,7 +77,7 @@ static void extend_netdev_table(struct net_device *dev, u32 new_len)  	if (!new_priomap) {  		pr_warn("Unable to alloc new priomap!\n"); -		return; +		return -ENOMEM;  	}  	for (i = 0; @@ -89,46 +90,79 @@ static void extend_netdev_table(struct net_device *dev, u32 new_len)  	rcu_assign_pointer(dev->priomap, new_priomap);  	if (old_priomap)  		kfree_rcu(old_priomap, rcu); +	return 0;  } -static void update_netdev_tables(void) +static int write_update_netdev_table(struct net_device *dev)  { +	int ret = 0; +	u32 max_len; +	struct netprio_map *map; + +	rtnl_lock(); +	max_len = atomic_read(&max_prioidx) + 1; +	map = rtnl_dereference(dev->priomap); +	if (!map || map->priomap_len < max_len) +		ret = extend_netdev_table(dev, max_len); +	rtnl_unlock(); + +	return ret; +} + +static int update_netdev_tables(void) +{ +	int ret = 0;  	struct net_device *dev; -	u32 max_len = atomic_read(&max_prioidx) + 1; +	u32 max_len;  	struct netprio_map *map;  	rtnl_lock(); +	max_len = atomic_read(&max_prioidx) + 1;  	for_each_netdev(&init_net, dev) {  		map = rtnl_dereference(dev->priomap); -		if ((!map) || -		    (map->priomap_len < max_len)) -			extend_netdev_table(dev, max_len); +		/* +		 * don't allocate priomap if we didn't +		 * change net_prio.ifpriomap (map == NULL), +		 * this will speed up skb_update_prio. +		 */ +		if (map && map->priomap_len < max_len) { +			ret = extend_netdev_table(dev, max_len); +			if (ret < 0) +				break; +		}  	}  	rtnl_unlock(); +	return ret;  }  static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp)  {  	struct cgroup_netprio_state *cs; -	int ret; +	int ret = -EINVAL;  	cs = kzalloc(sizeof(*cs), GFP_KERNEL);  	if (!cs)  		return ERR_PTR(-ENOMEM); -	if (cgrp->parent && cgrp_netprio_state(cgrp->parent)->prioidx) { -		kfree(cs); -		return ERR_PTR(-EINVAL); -	} +	if (cgrp->parent && cgrp_netprio_state(cgrp->parent)->prioidx) +		goto out;  	ret = get_prioidx(&cs->prioidx); -	if (ret != 0) { +	if (ret < 0) {  		pr_warn("No space in priority index array\n"); -		kfree(cs); -		return ERR_PTR(ret); +		goto out; +	} + +	ret = update_netdev_tables(); +	if (ret < 0) { +		put_prioidx(cs->prioidx); +		goto out;  	}  	return &cs->css; +out: +	kfree(cs); +	return ERR_PTR(ret);  }  static void cgrp_destroy(struct cgroup *cgrp) @@ -141,7 +175,7 @@ static void cgrp_destroy(struct cgroup *cgrp)  	rtnl_lock();  	for_each_netdev(&init_net, dev) {  		map = rtnl_dereference(dev->priomap); -		if (map) +		if (map && cs->prioidx < map->priomap_len)  			map->priomap[cs->prioidx] = 0;  	}  	rtnl_unlock(); @@ -165,7 +199,7 @@ static int read_priomap(struct cgroup *cont, struct cftype *cft,  	rcu_read_lock();  	for_each_netdev_rcu(&init_net, dev) {  		map = rcu_dereference(dev->priomap); -		priority = map ? map->priomap[prioidx] : 0; +		priority = (map && prioidx < map->priomap_len) ? map->priomap[prioidx] : 0;  		cb->fill(cb, dev->name, priority);  	}  	rcu_read_unlock(); @@ -220,13 +254,17 @@ static int write_priomap(struct cgroup *cgrp, struct cftype *cft,  	if (!dev)  		goto out_free_devname; -	update_netdev_tables(); -	ret = 0; +	ret = write_update_netdev_table(dev); +	if (ret < 0) +		goto out_put_dev; +  	rcu_read_lock();  	map = rcu_dereference(dev->priomap);  	if (map)  		map->priomap[prioidx] = priority;  	rcu_read_unlock(); + +out_put_dev:  	dev_put(dev);  out_free_devname: diff --git a/net/core/scm.c b/net/core/scm.c index 611c5efd4cb..8f6ccfd68ef 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -109,25 +109,9 @@ void __scm_destroy(struct scm_cookie *scm)  	if (fpl) {  		scm->fp = NULL; -		if (current->scm_work_list) { -			list_add_tail(&fpl->list, current->scm_work_list); -		} else { -			LIST_HEAD(work_list); - -			current->scm_work_list = &work_list; - -			list_add(&fpl->list, &work_list); -			while (!list_empty(&work_list)) { -				fpl = list_first_entry(&work_list, struct scm_fp_list, list); - -				list_del(&fpl->list); -				for (i=fpl->count-1; i>=0; i--) -					fput(fpl->fp[i]); -				kfree(fpl); -			} - -			current->scm_work_list = NULL; -		} +		for (i=fpl->count-1; i>=0; i--) +			fput(fpl->fp[i]); +		kfree(fpl);  	}  }  EXPORT_SYMBOL(__scm_destroy); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 46a3d23d259..d124306b81f 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -353,7 +353,7 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev,  	unsigned int fragsz = SKB_DATA_ALIGN(length + NET_SKB_PAD) +  			      SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); -	if (fragsz <= PAGE_SIZE && !(gfp_mask & __GFP_WAIT)) { +	if (fragsz <= PAGE_SIZE && !(gfp_mask & (__GFP_WAIT | GFP_DMA))) {  		void *data = netdev_alloc_frag(fragsz);  		if (likely(data)) {  |