aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-01-22 02:19:26 -0500
committerDavid S. Miller <davem@davemloft.net>2014-01-22 02:19:26 -0500
commit374d1125237e94f16ffa3185cff62df03977a988 (patch)
tree3bb15ec5b897df4ea197339478bb5d76049a2761
parent6cd28f044b47aeeba91807d97d6f3ea5a048e88d (diff)
parent809fa972fd90ff27225294b17a027e908b2d7b7a (diff)
Merge branch 'reciprocal'
Hannes Frederic Sowa says: ==================== reciprocal_divide update This patch is on top of aee636c4809fa5 ("bpf: do not use reciprocal divide") from Eric that sits in net tree. It will not create a merge conflict, but it depends on this one, so we suggest, if possible, to merge net into net-next. We are proposing this change with only small modifications from the v2 version, namely updating the name of trim to reciprocal_scale (as commented on by Ben Hutchings and Eric Dumazet, thanks!). We thought about introducing the reciprocal_divide algorithm in parallel to the one already used by the kernel but faced organizational issues, leading us to the conclusion that it is best to just replace the old one: We could not come up with names for the different implementations and also with a way to describe the differences to guide developers which one to choose in which situation. This is because we cannot specify the correct semantics for the version which is currently used by the kernel. Altough it seems to not be causing problems in the kernel, we cannot surely say so in the case of flex_array for the future. Current usage seems ok, but future users could run into problems. Changelog: v1->v2: - changed name to prandom_u32_max in p1 - changed name to trim in p2 - reworked code in p3 v2->v3: - p1 and p3 stays unchanged, only small update in commit message in p3 - changed name to reciprocal_scale in p2 - fixed kernel doc format v3->v4: - pseduo -> pseudo (thanks to Tilman Schmidt) v4->v5: - fix pseduo -> pseudo for real now, sorry for the noise ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/bonding/bond_main.c24
-rw-r--r--drivers/net/bonding/bond_netlink.c4
-rw-r--r--drivers/net/bonding/bond_options.c15
-rw-r--r--drivers/net/bonding/bond_sysfs.c5
-rw-r--r--drivers/net/bonding/bonding.h3
-rw-r--r--drivers/net/team/team_mode_random.c8
-rw-r--r--include/linux/flex_array.h3
-rw-r--r--include/linux/kernel.h19
-rw-r--r--include/linux/random.h18
-rw-r--r--include/linux/reciprocal_div.h39
-rw-r--r--include/linux/slab_def.h4
-rw-r--r--include/net/codel.h4
-rw-r--r--include/net/red.h3
-rw-r--r--lib/flex_array.c7
-rw-r--r--lib/reciprocal_div.c24
-rw-r--r--net/packet/af_packet.c5
-rw-r--r--net/sched/sch_choke.c9
-rw-r--r--net/sched/sch_netem.c6
18 files changed, 129 insertions, 71 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 3220b488dd1e..f100bd958b88 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -79,7 +79,6 @@
79#include <net/pkt_sched.h> 79#include <net/pkt_sched.h>
80#include <linux/rculist.h> 80#include <linux/rculist.h>
81#include <net/flow_keys.h> 81#include <net/flow_keys.h>
82#include <linux/reciprocal_div.h>
83#include "bonding.h" 82#include "bonding.h"
84#include "bond_3ad.h" 83#include "bond_3ad.h"
85#include "bond_alb.h" 84#include "bond_alb.h"
@@ -3596,8 +3595,9 @@ static void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int sl
3596 */ 3595 */
3597static u32 bond_rr_gen_slave_id(struct bonding *bond) 3596static u32 bond_rr_gen_slave_id(struct bonding *bond)
3598{ 3597{
3599 int packets_per_slave = bond->params.packets_per_slave;
3600 u32 slave_id; 3598 u32 slave_id;
3599 struct reciprocal_value reciprocal_packets_per_slave;
3600 int packets_per_slave = bond->params.packets_per_slave;
3601 3601
3602 switch (packets_per_slave) { 3602 switch (packets_per_slave) {
3603 case 0: 3603 case 0:
@@ -3607,8 +3607,10 @@ static u32 bond_rr_gen_slave_id(struct bonding *bond)
3607 slave_id = bond->rr_tx_counter; 3607 slave_id = bond->rr_tx_counter;
3608 break; 3608 break;
3609 default: 3609 default:
3610 reciprocal_packets_per_slave =
3611 bond->params.reciprocal_packets_per_slave;
3610 slave_id = reciprocal_divide(bond->rr_tx_counter, 3612 slave_id = reciprocal_divide(bond->rr_tx_counter,
3611 packets_per_slave); 3613 reciprocal_packets_per_slave);
3612 break; 3614 break;
3613 } 3615 }
3614 bond->rr_tx_counter++; 3616 bond->rr_tx_counter++;
@@ -4343,10 +4345,18 @@ static int bond_check_params(struct bond_params *params)
4343 params->resend_igmp = resend_igmp; 4345 params->resend_igmp = resend_igmp;
4344 params->min_links = min_links; 4346 params->min_links = min_links;
4345 params->lp_interval = lp_interval; 4347 params->lp_interval = lp_interval;
4346 if (packets_per_slave > 1) 4348 params->packets_per_slave = packets_per_slave;
4347 params->packets_per_slave = reciprocal_value(packets_per_slave); 4349 if (packets_per_slave > 0) {
4348 else 4350 params->reciprocal_packets_per_slave =
4349 params->packets_per_slave = packets_per_slave; 4351 reciprocal_value(packets_per_slave);
4352 } else {
4353 /* reciprocal_packets_per_slave is unused if
4354 * packets_per_slave is 0 or 1, just initialize it
4355 */
4356 params->reciprocal_packets_per_slave =
4357 (struct reciprocal_value) { 0 };
4358 }
4359
4350 if (primary) { 4360 if (primary) {
4351 strncpy(params->primary, primary, IFNAMSIZ); 4361 strncpy(params->primary, primary, IFNAMSIZ);
4352 params->primary[IFNAMSIZ - 1] = 0; 4362 params->primary[IFNAMSIZ - 1] = 0;
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index 21c648854a8c..e8526552790c 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -19,7 +19,6 @@
19#include <linux/if_ether.h> 19#include <linux/if_ether.h>
20#include <net/netlink.h> 20#include <net/netlink.h>
21#include <net/rtnetlink.h> 21#include <net/rtnetlink.h>
22#include <linux/reciprocal_div.h>
23#include "bonding.h" 22#include "bonding.h"
24 23
25int bond_get_slave(struct net_device *slave_dev, struct sk_buff *skb) 24int bond_get_slave(struct net_device *slave_dev, struct sk_buff *skb)
@@ -452,9 +451,6 @@ static int bond_fill_info(struct sk_buff *skb,
452 goto nla_put_failure; 451 goto nla_put_failure;
453 452
454 packets_per_slave = bond->params.packets_per_slave; 453 packets_per_slave = bond->params.packets_per_slave;
455 if (packets_per_slave > 1)
456 packets_per_slave = reciprocal_value(packets_per_slave);
457
458 if (nla_put_u32(skb, IFLA_BOND_PACKETS_PER_SLAVE, 454 if (nla_put_u32(skb, IFLA_BOND_PACKETS_PER_SLAVE,
459 packets_per_slave)) 455 packets_per_slave))
460 goto nla_put_failure; 456 goto nla_put_failure;
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index 945a6668da83..85e434886f2e 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -16,7 +16,6 @@
16#include <linux/netdevice.h> 16#include <linux/netdevice.h>
17#include <linux/rwlock.h> 17#include <linux/rwlock.h>
18#include <linux/rcupdate.h> 18#include <linux/rcupdate.h>
19#include <linux/reciprocal_div.h>
20#include "bonding.h" 19#include "bonding.h"
21 20
22int bond_option_mode_set(struct bonding *bond, int mode) 21int bond_option_mode_set(struct bonding *bond, int mode)
@@ -671,11 +670,17 @@ int bond_option_packets_per_slave_set(struct bonding *bond,
671 pr_warn("%s: Warning: packets_per_slave has effect only in balance-rr mode\n", 670 pr_warn("%s: Warning: packets_per_slave has effect only in balance-rr mode\n",
672 bond->dev->name); 671 bond->dev->name);
673 672
674 if (packets_per_slave > 1) 673 bond->params.packets_per_slave = packets_per_slave;
675 bond->params.packets_per_slave = 674 if (packets_per_slave > 0) {
675 bond->params.reciprocal_packets_per_slave =
676 reciprocal_value(packets_per_slave); 676 reciprocal_value(packets_per_slave);
677 else 677 } else {
678 bond->params.packets_per_slave = packets_per_slave; 678 /* reciprocal_packets_per_slave is unused if
679 * packets_per_slave is 0 or 1, just initialize it
680 */
681 bond->params.reciprocal_packets_per_slave =
682 (struct reciprocal_value) { 0 };
683 }
679 684
680 return 0; 685 return 0;
681} 686}
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 011f163c2c67..c083e9a66ece 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -39,7 +39,6 @@
39#include <net/net_namespace.h> 39#include <net/net_namespace.h>
40#include <net/netns/generic.h> 40#include <net/netns/generic.h>
41#include <linux/nsproxy.h> 41#include <linux/nsproxy.h>
42#include <linux/reciprocal_div.h>
43 42
44#include "bonding.h" 43#include "bonding.h"
45 44
@@ -1374,10 +1373,6 @@ static ssize_t bonding_show_packets_per_slave(struct device *d,
1374{ 1373{
1375 struct bonding *bond = to_bond(d); 1374 struct bonding *bond = to_bond(d);
1376 unsigned int packets_per_slave = bond->params.packets_per_slave; 1375 unsigned int packets_per_slave = bond->params.packets_per_slave;
1377
1378 if (packets_per_slave > 1)
1379 packets_per_slave = reciprocal_value(packets_per_slave);
1380
1381 return sprintf(buf, "%u\n", packets_per_slave); 1376 return sprintf(buf, "%u\n", packets_per_slave);
1382} 1377}
1383 1378
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 8a935f8f2b3c..0a616c41dc94 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -23,6 +23,8 @@
23#include <linux/netpoll.h> 23#include <linux/netpoll.h>
24#include <linux/inetdevice.h> 24#include <linux/inetdevice.h>
25#include <linux/etherdevice.h> 25#include <linux/etherdevice.h>
26#include <linux/reciprocal_div.h>
27
26#include "bond_3ad.h" 28#include "bond_3ad.h"
27#include "bond_alb.h" 29#include "bond_alb.h"
28 30
@@ -171,6 +173,7 @@ struct bond_params {
171 int resend_igmp; 173 int resend_igmp;
172 int lp_interval; 174 int lp_interval;
173 int packets_per_slave; 175 int packets_per_slave;
176 struct reciprocal_value reciprocal_packets_per_slave;
174}; 177};
175 178
176struct bond_parm_tbl { 179struct bond_parm_tbl {
diff --git a/drivers/net/team/team_mode_random.c b/drivers/net/team/team_mode_random.c
index 7f032e211343..cd2f692b8074 100644
--- a/drivers/net/team/team_mode_random.c
+++ b/drivers/net/team/team_mode_random.c
@@ -13,20 +13,14 @@
13#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/init.h> 14#include <linux/init.h>
15#include <linux/skbuff.h> 15#include <linux/skbuff.h>
16#include <linux/reciprocal_div.h>
17#include <linux/if_team.h> 16#include <linux/if_team.h>
18 17
19static u32 random_N(unsigned int N)
20{
21 return reciprocal_divide(prandom_u32(), N);
22}
23
24static bool rnd_transmit(struct team *team, struct sk_buff *skb) 18static bool rnd_transmit(struct team *team, struct sk_buff *skb)
25{ 19{
26 struct team_port *port; 20 struct team_port *port;
27 int port_index; 21 int port_index;
28 22
29 port_index = random_N(team->en_port_count); 23 port_index = prandom_u32_max(team->en_port_count);
30 port = team_get_port_by_index_rcu(team, port_index); 24 port = team_get_port_by_index_rcu(team, port_index);
31 if (unlikely(!port)) 25 if (unlikely(!port))
32 goto drop; 26 goto drop;
diff --git a/include/linux/flex_array.h b/include/linux/flex_array.h
index 6843cf193a44..b6efb0c64408 100644
--- a/include/linux/flex_array.h
+++ b/include/linux/flex_array.h
@@ -2,6 +2,7 @@
2#define _FLEX_ARRAY_H 2#define _FLEX_ARRAY_H
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include <linux/reciprocal_div.h>
5#include <asm/page.h> 6#include <asm/page.h>
6 7
7#define FLEX_ARRAY_PART_SIZE PAGE_SIZE 8#define FLEX_ARRAY_PART_SIZE PAGE_SIZE
@@ -22,7 +23,7 @@ struct flex_array {
22 int element_size; 23 int element_size;
23 int total_nr_elements; 24 int total_nr_elements;
24 int elems_per_part; 25 int elems_per_part;
25 u32 reciprocal_elems; 26 struct reciprocal_value reciprocal_elems;
26 struct flex_array_part *parts[]; 27 struct flex_array_part *parts[];
27 }; 28 };
28 /* 29 /*
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index ecb87544cc5d..03d8a6b0e2e8 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -193,6 +193,25 @@ extern int _cond_resched(void);
193 (__x < 0) ? -__x : __x; \ 193 (__x < 0) ? -__x : __x; \
194 }) 194 })
195 195
196/**
197 * reciprocal_scale - "scale" a value into range [0, ep_ro)
198 * @val: value
199 * @ep_ro: right open interval endpoint
200 *
201 * Perform a "reciprocal multiplication" in order to "scale" a value into
202 * range [0, ep_ro), where the upper interval endpoint is right-open.
203 * This is useful, e.g. for accessing a index of an array containing
204 * ep_ro elements, for example. Think of it as sort of modulus, only that
205 * the result isn't that of modulo. ;) Note that if initial input is a
206 * small value, then result will return 0.
207 *
208 * Return: a result based on val in interval [0, ep_ro).
209 */
210static inline u32 reciprocal_scale(u32 val, u32 ep_ro)
211{
212 return (u32)(((u64) val * ep_ro) >> 32);
213}
214
196#if defined(CONFIG_MMU) && \ 215#if defined(CONFIG_MMU) && \
197 (defined(CONFIG_PROVE_LOCKING) || defined(CONFIG_DEBUG_ATOMIC_SLEEP)) 216 (defined(CONFIG_PROVE_LOCKING) || defined(CONFIG_DEBUG_ATOMIC_SLEEP))
198void might_fault(void); 217void might_fault(void);
diff --git a/include/linux/random.h b/include/linux/random.h
index 4002b3df4c85..1cfce0e24dbd 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -8,7 +8,6 @@
8 8
9#include <uapi/linux/random.h> 9#include <uapi/linux/random.h>
10 10
11
12extern void add_device_randomness(const void *, unsigned int); 11extern void add_device_randomness(const void *, unsigned int);
13extern void add_input_randomness(unsigned int type, unsigned int code, 12extern void add_input_randomness(unsigned int type, unsigned int code,
14 unsigned int value); 13 unsigned int value);
@@ -38,6 +37,23 @@ struct rnd_state {
38u32 prandom_u32_state(struct rnd_state *state); 37u32 prandom_u32_state(struct rnd_state *state);
39void prandom_bytes_state(struct rnd_state *state, void *buf, int nbytes); 38void prandom_bytes_state(struct rnd_state *state, void *buf, int nbytes);
40 39
40/**
41 * prandom_u32_max - returns a pseudo-random number in interval [0, ep_ro)
42 * @ep_ro: right open interval endpoint
43 *
44 * Returns a pseudo-random number that is in interval [0, ep_ro). Note
45 * that the result depends on PRNG being well distributed in [0, ~0U]
46 * u32 space. Here we use maximally equidistributed combined Tausworthe
47 * generator, that is, prandom_u32(). This is useful when requesting a
48 * random index of an array containing ep_ro elements, for example.
49 *
50 * Returns: pseudo-random number in interval [0, ep_ro)
51 */
52static inline u32 prandom_u32_max(u32 ep_ro)
53{
54 return (u32)(((u64) prandom_u32() * ep_ro) >> 32);
55}
56
41/* 57/*
42 * Handle minimum values for seeds 58 * Handle minimum values for seeds
43 */ 59 */
diff --git a/include/linux/reciprocal_div.h b/include/linux/reciprocal_div.h
index f9c90b33285b..8c5a3fb6c6c5 100644
--- a/include/linux/reciprocal_div.h
+++ b/include/linux/reciprocal_div.h
@@ -4,29 +4,32 @@
4#include <linux/types.h> 4#include <linux/types.h>
5 5
6/* 6/*
7 * This file describes reciprocical division. 7 * This algorithm is based on the paper "Division by Invariant
8 * Integers Using Multiplication" by Torbjörn Granlund and Peter
9 * L. Montgomery.
8 * 10 *
9 * This optimizes the (A/B) problem, when A and B are two u32 11 * The assembler implementation from Agner Fog, which this code is
10 * and B is a known value (but not known at compile time) 12 * based on, can be found here:
13 * http://www.agner.org/optimize/asmlib.zip
11 * 14 *
12 * The math principle used is : 15 * This optimization for A/B is helpful if the divisor B is mostly
13 * Let RECIPROCAL_VALUE(B) be (((1LL << 32) + (B - 1))/ B) 16 * runtime invariant. The reciprocal of B is calculated in the
14 * Then A / B = (u32)(((u64)(A) * (R)) >> 32) 17 * slow-path with reciprocal_value(). The fast-path can then just use
15 * 18 * a much faster multiplication operation with a variable dividend A
16 * This replaces a divide by a multiply (and a shift), and 19 * to calculate the division A/B.
17 * is generally less expensive in CPU cycles.
18 */ 20 */
19 21
20/* 22struct reciprocal_value {
21 * Computes the reciprocal value (R) for the value B of the divisor. 23 u32 m;
22 * Should not be called before each reciprocal_divide(), 24 u8 sh1, sh2;
23 * or else the performance is slower than a normal divide. 25};
24 */
25extern u32 reciprocal_value(u32 B);
26 26
27struct reciprocal_value reciprocal_value(u32 d);
27 28
28static inline u32 reciprocal_divide(u32 A, u32 R) 29static inline u32 reciprocal_divide(u32 a, struct reciprocal_value R)
29{ 30{
30 return (u32)(((u64)A * R) >> 32); 31 u32 t = (u32)(((u64)a * R.m) >> 32);
32 return (t + ((a - t) >> R.sh1)) >> R.sh2;
31} 33}
32#endif 34
35#endif /* _LINUX_RECIPROCAL_DIV_H */
diff --git a/include/linux/slab_def.h b/include/linux/slab_def.h
index 09bfffb08a56..96e8abae19a9 100644
--- a/include/linux/slab_def.h
+++ b/include/linux/slab_def.h
@@ -1,6 +1,8 @@
1#ifndef _LINUX_SLAB_DEF_H 1#ifndef _LINUX_SLAB_DEF_H
2#define _LINUX_SLAB_DEF_H 2#define _LINUX_SLAB_DEF_H
3 3
4#include <linux/reciprocal_div.h>
5
4/* 6/*
5 * Definitions unique to the original Linux SLAB allocator. 7 * Definitions unique to the original Linux SLAB allocator.
6 */ 8 */
@@ -12,7 +14,7 @@ struct kmem_cache {
12 unsigned int shared; 14 unsigned int shared;
13 15
14 unsigned int size; 16 unsigned int size;
15 u32 reciprocal_buffer_size; 17 struct reciprocal_value reciprocal_buffer_size;
16/* 2) touched by every alloc & free from the backend */ 18/* 2) touched by every alloc & free from the backend */
17 19
18 unsigned int flags; /* constant flags */ 20 unsigned int flags; /* constant flags */
diff --git a/include/net/codel.h b/include/net/codel.h
index 3b04ff5f6f8d..fe0eab32ce76 100644
--- a/include/net/codel.h
+++ b/include/net/codel.h
@@ -46,7 +46,6 @@
46#include <linux/skbuff.h> 46#include <linux/skbuff.h>
47#include <net/pkt_sched.h> 47#include <net/pkt_sched.h>
48#include <net/inet_ecn.h> 48#include <net/inet_ecn.h>
49#include <linux/reciprocal_div.h>
50 49
51/* Controlling Queue Delay (CoDel) algorithm 50/* Controlling Queue Delay (CoDel) algorithm
52 * ========================================= 51 * =========================================
@@ -211,10 +210,9 @@ static codel_time_t codel_control_law(codel_time_t t,
211 codel_time_t interval, 210 codel_time_t interval,
212 u32 rec_inv_sqrt) 211 u32 rec_inv_sqrt)
213{ 212{
214 return t + reciprocal_divide(interval, rec_inv_sqrt << REC_INV_SQRT_SHIFT); 213 return t + reciprocal_scale(interval, rec_inv_sqrt << REC_INV_SQRT_SHIFT);
215} 214}
216 215
217
218static bool codel_should_drop(const struct sk_buff *skb, 216static bool codel_should_drop(const struct sk_buff *skb,
219 struct Qdisc *sch, 217 struct Qdisc *sch,
220 struct codel_vars *vars, 218 struct codel_vars *vars,
diff --git a/include/net/red.h b/include/net/red.h
index 168bb2f495f2..76e0b5f922c6 100644
--- a/include/net/red.h
+++ b/include/net/red.h
@@ -130,7 +130,8 @@ struct red_parms {
130 u32 qth_max; /* Max avg length threshold: Wlog scaled */ 130 u32 qth_max; /* Max avg length threshold: Wlog scaled */
131 u32 Scell_max; 131 u32 Scell_max;
132 u32 max_P; /* probability, [0 .. 1.0] 32 scaled */ 132 u32 max_P; /* probability, [0 .. 1.0] 32 scaled */
133 u32 max_P_reciprocal; /* reciprocal_value(max_P / qth_delta) */ 133 /* reciprocal_value(max_P / qth_delta) */
134 struct reciprocal_value max_P_reciprocal;
134 u32 qth_delta; /* max_th - min_th */ 135 u32 qth_delta; /* max_th - min_th */
135 u32 target_min; /* min_th + 0.4*(max_th - min_th) */ 136 u32 target_min; /* min_th + 0.4*(max_th - min_th) */
136 u32 target_max; /* min_th + 0.6*(max_th - min_th) */ 137 u32 target_max; /* min_th + 0.6*(max_th - min_th) */
diff --git a/lib/flex_array.c b/lib/flex_array.c
index 6948a6692fc4..2eed22fa507c 100644
--- a/lib/flex_array.c
+++ b/lib/flex_array.c
@@ -90,8 +90,8 @@ struct flex_array *flex_array_alloc(int element_size, unsigned int total,
90{ 90{
91 struct flex_array *ret; 91 struct flex_array *ret;
92 int elems_per_part = 0; 92 int elems_per_part = 0;
93 int reciprocal_elems = 0;
94 int max_size = 0; 93 int max_size = 0;
94 struct reciprocal_value reciprocal_elems = { 0 };
95 95
96 if (element_size) { 96 if (element_size) {
97 elems_per_part = FLEX_ARRAY_ELEMENTS_PER_PART(element_size); 97 elems_per_part = FLEX_ARRAY_ELEMENTS_PER_PART(element_size);
@@ -119,6 +119,11 @@ EXPORT_SYMBOL(flex_array_alloc);
119static int fa_element_to_part_nr(struct flex_array *fa, 119static int fa_element_to_part_nr(struct flex_array *fa,
120 unsigned int element_nr) 120 unsigned int element_nr)
121{ 121{
122 /*
123 * if element_size == 0 we don't get here, so we never touch
124 * the zeroed fa->reciprocal_elems, which would yield invalid
125 * results
126 */
122 return reciprocal_divide(element_nr, fa->reciprocal_elems); 127 return reciprocal_divide(element_nr, fa->reciprocal_elems);
123} 128}
124 129
diff --git a/lib/reciprocal_div.c b/lib/reciprocal_div.c
index 75510e94f7d0..464152410c51 100644
--- a/lib/reciprocal_div.c
+++ b/lib/reciprocal_div.c
@@ -1,11 +1,27 @@
1#include <linux/kernel.h>
1#include <asm/div64.h> 2#include <asm/div64.h>
2#include <linux/reciprocal_div.h> 3#include <linux/reciprocal_div.h>
3#include <linux/export.h> 4#include <linux/export.h>
4 5
5u32 reciprocal_value(u32 k) 6/*
7 * For a description of the algorithm please have a look at
8 * include/linux/reciprocal_div.h
9 */
10
11struct reciprocal_value reciprocal_value(u32 d)
6{ 12{
7 u64 val = (1LL << 32) + (k - 1); 13 struct reciprocal_value R;
8 do_div(val, k); 14 u64 m;
9 return (u32)val; 15 int l;
16
17 l = fls(d - 1);
18 m = ((1ULL << 32) * ((1ULL << l) - d));
19 do_div(m, d);
20 ++m;
21 R.m = (u32)m;
22 R.sh1 = min(l, 1);
23 R.sh2 = max(l - 1, 0);
24
25 return R;
10} 26}
11EXPORT_SYMBOL(reciprocal_value); 27EXPORT_SYMBOL(reciprocal_value);
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 59fb3db2e713..97346162803d 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -88,7 +88,6 @@
88#include <linux/virtio_net.h> 88#include <linux/virtio_net.h>
89#include <linux/errqueue.h> 89#include <linux/errqueue.h>
90#include <linux/net_tstamp.h> 90#include <linux/net_tstamp.h>
91#include <linux/reciprocal_div.h>
92#include <linux/percpu.h> 91#include <linux/percpu.h>
93#ifdef CONFIG_INET 92#ifdef CONFIG_INET
94#include <net/inet_common.h> 93#include <net/inet_common.h>
@@ -1262,7 +1261,7 @@ static unsigned int fanout_demux_hash(struct packet_fanout *f,
1262 struct sk_buff *skb, 1261 struct sk_buff *skb,
1263 unsigned int num) 1262 unsigned int num)
1264{ 1263{
1265 return reciprocal_divide(skb->rxhash, num); 1264 return reciprocal_scale(skb->rxhash, num);
1266} 1265}
1267 1266
1268static unsigned int fanout_demux_lb(struct packet_fanout *f, 1267static unsigned int fanout_demux_lb(struct packet_fanout *f,
@@ -1289,7 +1288,7 @@ static unsigned int fanout_demux_rnd(struct packet_fanout *f,
1289 struct sk_buff *skb, 1288 struct sk_buff *skb,
1290 unsigned int num) 1289 unsigned int num)
1291{ 1290{
1292 return reciprocal_divide(prandom_u32(), num); 1291 return prandom_u32_max(num);
1293} 1292}
1294 1293
1295static unsigned int fanout_demux_rollover(struct packet_fanout *f, 1294static unsigned int fanout_demux_rollover(struct packet_fanout *f,
diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c
index ddd73cb2d7ba..2aee02802c27 100644
--- a/net/sched/sch_choke.c
+++ b/net/sched/sch_choke.c
@@ -14,7 +14,6 @@
14#include <linux/types.h> 14#include <linux/types.h>
15#include <linux/kernel.h> 15#include <linux/kernel.h>
16#include <linux/skbuff.h> 16#include <linux/skbuff.h>
17#include <linux/reciprocal_div.h>
18#include <linux/vmalloc.h> 17#include <linux/vmalloc.h>
19#include <net/pkt_sched.h> 18#include <net/pkt_sched.h>
20#include <net/inet_ecn.h> 19#include <net/inet_ecn.h>
@@ -77,12 +76,6 @@ struct choke_sched_data {
77 struct sk_buff **tab; 76 struct sk_buff **tab;
78}; 77};
79 78
80/* deliver a random number between 0 and N - 1 */
81static u32 random_N(unsigned int N)
82{
83 return reciprocal_divide(prandom_u32(), N);
84}
85
86/* number of elements in queue including holes */ 79/* number of elements in queue including holes */
87static unsigned int choke_len(const struct choke_sched_data *q) 80static unsigned int choke_len(const struct choke_sched_data *q)
88{ 81{
@@ -233,7 +226,7 @@ static struct sk_buff *choke_peek_random(const struct choke_sched_data *q,
233 int retrys = 3; 226 int retrys = 3;
234 227
235 do { 228 do {
236 *pidx = (q->head + random_N(choke_len(q))) & q->tab_mask; 229 *pidx = (q->head + prandom_u32_max(choke_len(q))) & q->tab_mask;
237 skb = q->tab[*pidx]; 230 skb = q->tab[*pidx];
238 if (skb) 231 if (skb)
239 return skb; 232 return skb;
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index a2bfc371b44a..de1059af6da1 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -91,7 +91,7 @@ struct netem_sched_data {
91 u64 rate; 91 u64 rate;
92 s32 packet_overhead; 92 s32 packet_overhead;
93 u32 cell_size; 93 u32 cell_size;
94 u32 cell_size_reciprocal; 94 struct reciprocal_value cell_size_reciprocal;
95 s32 cell_overhead; 95 s32 cell_overhead;
96 96
97 struct crndstate { 97 struct crndstate {
@@ -725,9 +725,11 @@ static void get_rate(struct Qdisc *sch, const struct nlattr *attr)
725 q->rate = r->rate; 725 q->rate = r->rate;
726 q->packet_overhead = r->packet_overhead; 726 q->packet_overhead = r->packet_overhead;
727 q->cell_size = r->cell_size; 727 q->cell_size = r->cell_size;
728 q->cell_overhead = r->cell_overhead;
728 if (q->cell_size) 729 if (q->cell_size)
729 q->cell_size_reciprocal = reciprocal_value(q->cell_size); 730 q->cell_size_reciprocal = reciprocal_value(q->cell_size);
730 q->cell_overhead = r->cell_overhead; 731 else
732 q->cell_size_reciprocal = (struct reciprocal_value) { 0 };
731} 733}
732 734
733static int get_loss_clg(struct Qdisc *sch, const struct nlattr *attr) 735static int get_loss_clg(struct Qdisc *sch, const struct nlattr *attr)