* [PATCH v2 7/7] gianfar: Basic Support for programming hash rules
From: Sandeep Gopalpet @ 2009-10-27 16:55 UTC (permalink / raw)
To: netdev; +Cc: davem, Sandeep Gopalpet
This patch provides basic hash rules programming via the ethtool
interface.
Signed-off-by: Sandeep Gopalpet <sandeep.kumar@freescale.com>
---
drivers/net/gianfar.c | 73 +++++++++++++
drivers/net/gianfar.h | 93 ++++++++++++++++
drivers/net/gianfar_ethtool.c | 236 +++++++++++++++++++++++++++++++++++++++++
include/linux/ethtool.h | 2 +
4 files changed, 404 insertions(+), 0 deletions(-)
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index daff741..1b1a8b4 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -416,6 +416,9 @@ static const struct net_device_ops gfar_netdev_ops = {
#endif
};
+unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];
+unsigned int ftp_rqfcr[MAX_FILER_IDX + 1];
+
inline void lock_rx_qs(struct gfar_private *priv)
{
int i = 0x0;
@@ -751,6 +754,73 @@ static unsigned int reverse_bitmap(unsigned int bit_map, unsigned int max_qs)
}
return new_bit_map;
}
+
+u32 cluster_entry_per_class(struct gfar_private *priv, u32 rqfar, u32 class)
+{
+ u32 rqfpr = FPR_FILER_MASK;
+ u32 rqfcr = 0x0;
+
+ rqfar--;
+ rqfcr = RQFCR_CLE | RQFCR_PID_MASK | RQFCR_CMP_EXACT;
+ ftp_rqfpr[rqfar] = rqfpr;
+ ftp_rqfcr[rqfar] = rqfcr;
+ gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
+
+ rqfar--;
+ rqfcr = RQFCR_CMP_NOMATCH;
+ ftp_rqfpr[rqfar] = rqfpr;
+ ftp_rqfcr[rqfar] = rqfcr;
+ gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
+
+ rqfar--;
+ rqfcr = RQFCR_CMP_EXACT | RQFCR_PID_PARSE | RQFCR_CLE | RQFCR_AND;
+ rqfpr = class;
+ ftp_rqfcr[rqfar] = rqfcr;
+ ftp_rqfpr[rqfar] = rqfpr;
+ gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
+
+ rqfar--;
+ rqfcr = RQFCR_CMP_EXACT | RQFCR_PID_MASK | RQFCR_AND;
+ rqfpr = class;
+ ftp_rqfcr[rqfar] = rqfcr;
+ ftp_rqfpr[rqfar] = rqfpr;
+ gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
+
+ return rqfar;
+}
+
+static void gfar_init_filer_table(struct gfar_private *priv)
+{
+ int i = 0x0;
+ u32 rqfar = MAX_FILER_IDX;
+ u32 rqfcr = 0x0;
+ u32 rqfpr = FPR_FILER_MASK;
+
+ /* Default rule */
+ rqfcr = RQFCR_CMP_MATCH;
+ ftp_rqfcr[rqfar] = rqfcr;
+ ftp_rqfpr[rqfar] = rqfpr;
+ gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
+
+ rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6);
+ rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6 | RQFPR_UDP);
+ rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6 | RQFPR_TCP);
+ rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4);
+ rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4 | RQFPR_UDP);
+ rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4 | RQFPR_TCP);
+
+ /* cur_filer_idx indicated the fisrt non-masked rule */
+ priv->cur_filer_idx = rqfar;
+
+ /* Rest are masked rules */
+ rqfcr = RQFCR_CMP_NOMATCH;
+ for (i = 0; i < rqfar; i++) {
+ ftp_rqfcr[i] = rqfcr;
+ ftp_rqfpr[i] = rqfpr;
+ gfar_write_filer(priv, i, rqfcr, rqfpr);
+ }
+}
+
/* Set up the ethernet device structure, private data,
* and anything else we need before we start */
static int gfar_probe(struct of_device *ofdev,
@@ -990,6 +1060,9 @@ static int gfar_probe(struct of_device *ofdev,
priv->gfargrp[i].int_name_tx[len_devname] = '\0';
}
+ /* Initialize the filer table */
+ gfar_init_filer_table(priv);
+
/* Create all the sysfs files */
gfar_init_sysfs(dev);
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index a43b238..1c9fdea 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -381,6 +381,84 @@ extern const char gfar_driver_version[];
#define BD_LFLAG(flags) ((flags) << 16)
#define BD_LENGTH_MASK 0x0000ffff
+#define CLASS_CODE_UNRECOG 0x00
+#define CLASS_CODE_DUMMY1 0x01
+#define CLASS_CODE_ETHERTYPE1 0x02
+#define CLASS_CODE_ETHERTYPE2 0x03
+#define CLASS_CODE_USER_PROG1 0x04
+#define CLASS_CODE_USER_PROG2 0x05
+#define CLASS_CODE_USER_PROG3 0x06
+#define CLASS_CODE_USER_PROG4 0x07
+#define CLASS_CODE_TCP_IPV4 0x08
+#define CLASS_CODE_UDP_IPV4 0x09
+#define CLASS_CODE_AH_ESP_IPV4 0x0a
+#define CLASS_CODE_SCTP_IPV4 0x0b
+#define CLASS_CODE_TCP_IPV6 0x0c
+#define CLASS_CODE_UDP_IPV6 0x0d
+#define CLASS_CODE_AH_ESP_IPV6 0x0e
+#define CLASS_CODE_SCTP_IPV6 0x0f
+
+#define FPR_FILER_MASK 0xFFFFFFFF
+#define MAX_FILER_IDX 0xFF
+
+/* RQFCR register bits */
+#define RQFCR_GPI 0x80000000
+#define RQFCR_HASHTBL_Q 0x00000000
+#define RQFCR_HASHTBL_0 0x00020000
+#define RQFCR_HASHTBL_1 0x00040000
+#define RQFCR_HASHTBL_2 0x00060000
+#define RQFCR_HASHTBL_3 0x00080000
+#define RQFCR_HASH 0x00010000
+#define RQFCR_CLE 0x00000200
+#define RQFCR_RJE 0x00000100
+#define RQFCR_AND 0x00000080
+#define RQFCR_CMP_EXACT 0x00000000
+#define RQFCR_CMP_MATCH 0x00000020
+#define RQFCR_CMP_NOEXACT 0x00000040
+#define RQFCR_CMP_NOMATCH 0x00000060
+
+/* RQFCR PID values */
+#define RQFCR_PID_MASK 0x00000000
+#define RQFCR_PID_PARSE 0x00000001
+#define RQFCR_PID_ARB 0x00000002
+#define RQFCR_PID_DAH 0x00000003
+#define RQFCR_PID_DAL 0x00000004
+#define RQFCR_PID_SAH 0x00000005
+#define RQFCR_PID_SAL 0x00000006
+#define RQFCR_PID_ETY 0x00000007
+#define RQFCR_PID_VID 0x00000008
+#define RQFCR_PID_PRI 0x00000009
+#define RQFCR_PID_TOS 0x0000000A
+#define RQFCR_PID_L4P 0x0000000B
+#define RQFCR_PID_DIA 0x0000000C
+#define RQFCR_PID_SIA 0x0000000D
+#define RQFCR_PID_DPT 0x0000000E
+#define RQFCR_PID_SPT 0x0000000F
+
+/* RQFPR when PID is 0x0001 */
+#define RQFPR_HDR_GE_512 0x00200000
+#define RQFPR_LERR 0x00100000
+#define RQFPR_RAR 0x00080000
+#define RQFPR_RARQ 0x00040000
+#define RQFPR_AR 0x00020000
+#define RQFPR_ARQ 0x00010000
+#define RQFPR_EBC 0x00008000
+#define RQFPR_VLN 0x00004000
+#define RQFPR_CFI 0x00002000
+#define RQFPR_JUM 0x00001000
+#define RQFPR_IPF 0x00000800
+#define RQFPR_FIF 0x00000400
+#define RQFPR_IPV4 0x00000200
+#define RQFPR_IPV6 0x00000100
+#define RQFPR_ICC 0x00000080
+#define RQFPR_ICV 0x00000040
+#define RQFPR_TCP 0x00000020
+#define RQFPR_UDP 0x00000010
+#define RQFPR_TUC 0x00000008
+#define RQFPR_TUV 0x00000004
+#define RQFPR_PER 0x00000002
+#define RQFPR_EER 0x00000001
+
/* TxBD status field bits */
#define TXBD_READY 0x8000
#define TXBD_PADCRC 0x4000
@@ -958,6 +1036,8 @@ struct gfar_private {
unsigned int rx_stash_size;
unsigned int rx_stash_index;
+ u32 cur_filer_idx;
+
struct sk_buff_head rx_recycle;
struct vlan_group *vlgrp;
@@ -1001,6 +1081,9 @@ struct gfar_private {
struct gfar_extra_stats extra_stats;
};
+extern unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];
+extern unsigned int ftp_rqfcr[MAX_FILER_IDX + 1];
+
static inline u32 gfar_read(volatile unsigned __iomem *addr)
{
u32 val;
@@ -1013,6 +1096,16 @@ static inline void gfar_write(volatile unsigned __iomem *addr, u32 val)
out_be32(addr, val);
}
+static inline void gfar_write_filer(struct gfar_private *priv,
+ unsigned int far, unsigned int fcr, unsigned int fpr)
+{
+ struct gfar __iomem *regs = priv->gfargrp[0].regs;
+
+ gfar_write(®s->rqfar, far);
+ gfar_write(®s->rqfcr, fcr);
+ gfar_write(®s->rqfpr, fpr);
+}
+
extern inline void lock_rx_qs(struct gfar_private *priv);
extern inline void lock_tx_qs(struct gfar_private *priv);
extern inline void unlock_rx_qs(struct gfar_private *priv);
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 562f6c2..1010367 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -645,6 +645,241 @@ static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
}
#endif
+static int gfar_ethflow_to_class(int flow_type, u64 *class)
+{
+ switch (flow_type) {
+ case TCP_V4_FLOW:
+ *class = CLASS_CODE_TCP_IPV4;
+ break;
+ case UDP_V4_FLOW:
+ *class = CLASS_CODE_UDP_IPV4;
+ break;
+ case AH_V4_FLOW:
+ case ESP_V4_FLOW:
+ *class = CLASS_CODE_AH_ESP_IPV4;
+ break;
+ case SCTP_V4_FLOW:
+ *class = CLASS_CODE_SCTP_IPV4;
+ break;
+ case TCP_V6_FLOW:
+ *class = CLASS_CODE_TCP_IPV6;
+ break;
+ case UDP_V6_FLOW:
+ *class = CLASS_CODE_UDP_IPV6;
+ break;
+ case AH_V6_FLOW:
+ case ESP_V6_FLOW:
+ *class = CLASS_CODE_AH_ESP_IPV6;
+ break;
+ case SCTP_V6_FLOW:
+ *class = CLASS_CODE_SCTP_IPV6;
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow)
+{
+ u32 fcr = 0x0, fpr = FPR_FILER_MASK;
+
+ if (ethflow & RXH_L2DA) {
+ fcr = RQFCR_PID_DAH |RQFCR_CMP_NOMATCH |
+ RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0;
+ ftp_rqfpr[priv->cur_filer_idx] = fpr;
+ ftp_rqfcr[priv->cur_filer_idx] = fcr;
+ gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
+ priv->cur_filer_idx = priv->cur_filer_idx - 1;
+
+ fcr = RQFCR_PID_DAL | RQFCR_AND | RQFCR_CMP_NOMATCH |
+ RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0;
+ ftp_rqfpr[priv->cur_filer_idx] = fpr;
+ ftp_rqfcr[priv->cur_filer_idx] = fcr;
+ gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
+ priv->cur_filer_idx = priv->cur_filer_idx - 1;
+ }
+
+ if (ethflow & RXH_VLAN) {
+ fcr = RQFCR_PID_VID | RQFCR_CMP_NOMATCH | RQFCR_HASH |
+ RQFCR_AND | RQFCR_HASHTBL_0;
+ gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
+ ftp_rqfpr[priv->cur_filer_idx] = fpr;
+ ftp_rqfcr[priv->cur_filer_idx] = fcr;
+ priv->cur_filer_idx = priv->cur_filer_idx - 1;
+ }
+
+ if (ethflow & RXH_IP_SRC) {
+ fcr = RQFCR_PID_SIA | RQFCR_CMP_NOMATCH | RQFCR_HASH |
+ RQFCR_AND | RQFCR_HASHTBL_0;
+ ftp_rqfpr[priv->cur_filer_idx] = fpr;
+ ftp_rqfcr[priv->cur_filer_idx] = fcr;
+ gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
+ priv->cur_filer_idx = priv->cur_filer_idx - 1;
+ }
+
+ if (ethflow & (RXH_IP_DST)) {
+ fcr = RQFCR_PID_DIA | RQFCR_CMP_NOMATCH | RQFCR_HASH |
+ RQFCR_AND | RQFCR_HASHTBL_0;
+ ftp_rqfpr[priv->cur_filer_idx] = fpr;
+ ftp_rqfcr[priv->cur_filer_idx] = fcr;
+ gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
+ priv->cur_filer_idx = priv->cur_filer_idx - 1;
+ }
+
+ if (ethflow & RXH_L3_PROTO) {
+ fcr = RQFCR_PID_L4P | RQFCR_CMP_NOMATCH | RQFCR_HASH |
+ RQFCR_AND | RQFCR_HASHTBL_0;
+ ftp_rqfpr[priv->cur_filer_idx] = fpr;
+ ftp_rqfcr[priv->cur_filer_idx] = fcr;
+ gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
+ priv->cur_filer_idx = priv->cur_filer_idx - 1;
+ }
+
+ if (ethflow & RXH_L4_B_0_1) {
+ fcr = RQFCR_PID_SPT | RQFCR_CMP_NOMATCH | RQFCR_HASH |
+ RQFCR_AND | RQFCR_HASHTBL_0;
+ ftp_rqfpr[priv->cur_filer_idx] = fpr;
+ ftp_rqfcr[priv->cur_filer_idx] = fcr;
+ gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
+ priv->cur_filer_idx = priv->cur_filer_idx - 1;
+ }
+
+ if (ethflow & RXH_L4_B_2_3) {
+ fcr = RQFCR_PID_DPT | RQFCR_CMP_NOMATCH | RQFCR_HASH |
+ RQFCR_AND | RQFCR_HASHTBL_0;
+ ftp_rqfpr[priv->cur_filer_idx] = fpr;
+ ftp_rqfcr[priv->cur_filer_idx] = fcr;
+ gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
+ priv->cur_filer_idx = priv->cur_filer_idx - 1;
+ }
+}
+
+static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u64 class)
+{
+ unsigned int last_rule_idx = priv->cur_filer_idx;
+ unsigned int cmp_rqfpr;
+ unsigned int local_rqfpr[MAX_FILER_IDX + 1];
+ unsigned int local_rqfcr[MAX_FILER_IDX + 1];
+ int i = 0x0, k = 0x0;
+ int j = MAX_FILER_IDX, l = 0x0;
+
+ switch (class) {
+ case TCP_V4_FLOW:
+ cmp_rqfpr = RQFPR_IPV4 |RQFPR_TCP;
+ break;
+ case UDP_V4_FLOW:
+ cmp_rqfpr = RQFPR_IPV4 |RQFPR_UDP;
+ break;
+ case TCP_V6_FLOW:
+ cmp_rqfpr = RQFPR_IPV6 |RQFPR_TCP;
+ break;
+ case UDP_V6_FLOW:
+ cmp_rqfpr = RQFPR_IPV6 |RQFPR_UDP;
+ break;
+ case IPV4_FLOW:
+ cmp_rqfpr = RQFPR_IPV4;
+ case IPV6_FLOW:
+ cmp_rqfpr = RQFPR_IPV6;
+ break;
+ default:
+ printk(KERN_ERR "Right now this class is not supported\n");
+ return 0;
+ }
+
+ for (i = 0; i < MAX_FILER_IDX + 1; i++) {
+ local_rqfpr[j] = ftp_rqfpr[i];
+ local_rqfcr[j] = ftp_rqfcr[i];
+ j--;
+ if ((ftp_rqfcr[i] == (RQFCR_PID_PARSE |
+ RQFCR_CLE |RQFCR_AND)) &&
+ (ftp_rqfpr[i] == cmp_rqfpr))
+ break;
+ }
+
+ if (i == MAX_FILER_IDX + 1) {
+ printk(KERN_ERR "No parse rule found, ");
+ printk(KERN_ERR "can't create hash rules\n");
+ return 0;
+ }
+
+ /* If a match was found, then it begins the starting of a cluster rule
+ * if it was already programmed, we need to overwrite these rules
+ */
+ for (l = i+1; l < MAX_FILER_IDX; l++) {
+ if ((ftp_rqfcr[l] & RQFCR_CLE) &&
+ !(ftp_rqfcr[l] & RQFCR_AND)) {
+ ftp_rqfcr[l] = RQFCR_CLE | RQFCR_CMP_EXACT |
+ RQFCR_HASHTBL_0 | RQFCR_PID_MASK;
+ ftp_rqfpr[l] = FPR_FILER_MASK;
+ gfar_write_filer(priv, l, ftp_rqfcr[l], ftp_rqfpr[l]);
+ break;
+ }
+
+ if (!(ftp_rqfcr[l] & RQFCR_CLE) && (ftp_rqfcr[l] & RQFCR_AND))
+ continue;
+ else {
+ local_rqfpr[j] = ftp_rqfpr[l];
+ local_rqfcr[j] = ftp_rqfcr[l];
+ j--;
+ }
+ }
+
+ priv->cur_filer_idx = l - 1;
+ last_rule_idx = l;
+
+ /* hash rules */
+ ethflow_to_filer_rules(priv, ethflow);
+
+ /* Write back the popped out rules again */
+ for (k = j+1; k < MAX_FILER_IDX; k++) {
+ ftp_rqfpr[priv->cur_filer_idx] = local_rqfpr[k];
+ ftp_rqfcr[priv->cur_filer_idx] = local_rqfcr[k];
+ gfar_write_filer(priv, priv->cur_filer_idx,
+ local_rqfcr[k], local_rqfpr[k]);
+ if (!priv->cur_filer_idx)
+ break;
+ priv->cur_filer_idx = priv->cur_filer_idx - 1;
+ }
+
+ return 1;
+}
+
+static int gfar_set_hash_opts(struct gfar_private *priv, struct ethtool_rxnfc *cmd)
+{
+ u64 class;
+
+ if (!gfar_ethflow_to_class(cmd->flow_type, &class))
+ return -EINVAL;
+
+ if (class < CLASS_CODE_USER_PROG1 ||
+ class > CLASS_CODE_SCTP_IPV6)
+ return -EINVAL;
+
+ /* write the filer rules here */
+ if (!gfar_ethflow_to_filer_table(priv, cmd->data, cmd->flow_type))
+ return -1;
+
+ return 0;
+}
+
+static int gfar_set_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ int ret = 0;
+
+ switch(cmd->cmd) {
+ case ETHTOOL_SRXFH:
+ ret = gfar_set_hash_opts(priv, cmd);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
const struct ethtool_ops gfar_ethtool_ops = {
.get_settings = gfar_gsettings,
.set_settings = gfar_ssettings,
@@ -670,4 +905,5 @@ const struct ethtool_ops gfar_ethtool_ops = {
.get_wol = gfar_get_wol,
.set_wol = gfar_set_wol,
#endif
+ .set_rxnfc = gfar_set_nfc,
};
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index eb1a48d..edd03b7 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -674,6 +674,8 @@ struct ethtool_ops {
#define AH_V6_FLOW 0x0b
#define ESP_V6_FLOW 0x0c
#define IP_USER_FLOW 0x0d
+#define IPV4_FLOW 0x10
+#define IPV6_FLOW 0x11
/* L3-L4 network traffic flow hash options */
#define RXH_L2DA (1 << 1)
--
1.5.2.2
^ permalink raw reply related
* Re: [PATCH 4/5] page allocator: Pre-emptively wake kswapd when high-order watermarks are hit
From: Mel Gorman @ 2009-10-27 15:26 UTC (permalink / raw)
To: KOSAKI Motohiro
Cc: Frans Pop, Jiri Kosina, Sven Geggus, Karol Lewandowski,
Tobias Oetiker, Rafael J. Wysocki, David Miller, Reinette Chatre,
Kalle Valo, David Rientjes, Mohamed Abbas, Jens Axboe,
John W. Linville, Pekka Enberg, Bartlomiej Zolnierkiewicz,
Greg Kroah-Hartman, Stephan von Krawczynski, Kernel Testers List,
netdev-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-mm-Bw31MaZKKs3YtjvyW6yDsg@public.gmane.org
In-Reply-To: <20091026235032.2F78.A69D9226-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
On Tue, Oct 27, 2009 at 11:42:58AM +0900, KOSAKI Motohiro wrote:
> > When a high-order allocation fails, kswapd is kicked so that it reclaims
> > at a higher-order to avoid direct reclaimers stall and to help GFP_ATOMIC
> > allocations. Something has changed in recent kernels that affect the timing
> > where high-order GFP_ATOMIC allocations are now failing with more frequency,
> > particularly under pressure.
> >
> > This patch pre-emptively checks if watermarks have been hit after a
> > high-order allocation completes successfully. If the watermarks have been
> > reached, kswapd is woken in the hope it fixes the watermarks before the
> > next GFP_ATOMIC allocation fails.
> >
> > Warning, this patch is somewhat of a band-aid. If this makes a difference,
> > it still implies that something has changed that is either causing more
> > GFP_ATOMIC allocations to occur (such as the case with iwlagn wireless
> > driver) or make them more likely to fail.
>
> hmm, I'm confused. this description addressed generic high order allocation.
> but,
>
> >
> > Signed-off-by: Mel Gorman <mel-wPRd99KPJ+uzQB+pC5nmwQ@public.gmane.org>
> > ---
> > mm/page_alloc.c | 33 ++++++++++++++++++++++-----------
> > 1 files changed, 22 insertions(+), 11 deletions(-)
> >
> > diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> > index 7f2aa3e..851df40 100644
> > --- a/mm/page_alloc.c
> > +++ b/mm/page_alloc.c
> > @@ -1596,6 +1596,17 @@ try_next_zone:
> > return page;
> > }
> >
> > +static inline
> > +void wake_all_kswapd(unsigned int order, struct zonelist *zonelist,
> > + enum zone_type high_zoneidx)
> > +{
> > + struct zoneref *z;
> > + struct zone *zone;
> > +
> > + for_each_zone_zonelist(zone, z, zonelist, high_zoneidx)
> > + wakeup_kswapd(zone, order);
> > +}
> > +
> > static inline int
> > should_alloc_retry(gfp_t gfp_mask, unsigned int order,
> > unsigned long pages_reclaimed)
> > @@ -1730,18 +1741,18 @@ __alloc_pages_high_priority(gfp_t gfp_mask, unsigned int order,
>
> __alloc_pages_high_priority() is only called if ALLOC_NO_WATERMARKS.
> ALLOC_NO_WATERMARKS mean PF_MEMALLOC or TIF_MEMDIE and GFP_ATOMIC don't make
> nested alloc_pages() (= don't make PF_MEMALLOC case).
> Then, I haven't understand why this patch improve iwlagn GFP_ATOMIC case.
>
> hmm, maybe I missed something. I see the code again tommorow.
>
The description is misleading but in the patches current form, it makes
a different to Tobias's testing. I still haven't figured out why.
>
> > congestion_wait(BLK_RW_ASYNC, HZ/50);
> > } while (!page && (gfp_mask & __GFP_NOFAIL));
> >
> > - return page;
> > -}
> > -
> > -static inline
> > -void wake_all_kswapd(unsigned int order, struct zonelist *zonelist,
> > - enum zone_type high_zoneidx)
> > -{
> > - struct zoneref *z;
> > - struct zone *zone;
> > + /*
> > + * If after a high-order allocation we are now below watermarks,
> > + * pre-emptively kick kswapd rather than having the next allocation
> > + * fail and have to wake up kswapd, potentially failing GFP_ATOMIC
> > + * allocations or entering direct reclaim
> > + */
> > + if (unlikely(order) && page && !zone_watermark_ok(preferred_zone, order,
> > + preferred_zone->watermark[ALLOC_WMARK_LOW],
> > + zone_idx(preferred_zone), ALLOC_WMARK_LOW))
> > + wake_all_kswapd(order, zonelist, high_zoneidx);
> >
> > - for_each_zone_zonelist(zone, z, zonelist, high_zoneidx)
> > - wakeup_kswapd(zone, order);
> > + return page;
> > }
> >
> > static inline int
> > --
> > 1.6.3.3
> >
> > --
> > To unsubscribe, send a message with 'unsubscribe linux-mm' in
> > the body to majordomo-Bw31MaZKKs0EbZ0PF+XxCw@public.gmane.org For more info on Linux MM,
> > see: http://www.linux-mm.org/ .
> > Don't email: <a href=mailto:"dont-Bw31MaZKKs3YtjvyW6yDsg@public.gmane.org"> email-Bw31MaZKKs3YtjvyW6yDsg@public.gmane.org </a>
>
>
>
--
Mel Gorman
Part-time Phd Student Linux Technology Center
University of Limerick IBM Dublin Software Lab
^ permalink raw reply
* Re: [PATCH 0/5] Candidate fix for increased number of GFP_ATOMIC failures V2
From: Mel Gorman @ 2009-10-27 15:36 UTC (permalink / raw)
To: Tobias Oetiker
Cc: Frans Pop, Jiri Kosina, Sven Geggus, Karol Lewandowski,
Rafael J. Wysocki, David Miller, Reinette Chatre, Kalle Valo,
David Rientjes, KOSAKI Motohiro, Mohamed Abbas, Jens Axboe,
John W. Linville, Pekka Enberg, Bartlomiej Zolnierkiewicz,
Greg Kroah-Hartman, Stephan von Krawczynski, Kernel Testers List,
netdev, linux-kernel, linux-mm@kvack.org
In-Reply-To: <alpine.DEB.2.00.0910261835440.24625@wbuna.brgvxre.pu>
On Mon, Oct 26, 2009 at 06:37:36PM +0100, Tobias Oetiker wrote:
> Hi Mel,
>
> I have no done additional tests ... and can report the following
>
> Thursday Mel Gorman wrote:
>
> > 1/5 page allocator: Always wake kswapd when restarting an allocation attempt after direct reclaim failed
> > 2/5 page allocator: Do not allow interrupts to use ALLOC_HARDER
> >
> >
> > These patches correct problems introduced by me during the 2.6.31-rc1
> > merge window. The patches were not meant to introduce any functional
> > changes but two were missed.
> >
> > If your problem goes away with just these two patches applied,
> > please tell me.
>
> 1+2 do not help
>
> > Test 3: If you are getting allocation failures, try with the following patch
> >
> > 3/5 vmscan: Force kswapd to take notice faster when high-order watermarks are being hit
> >
> > This is a functional change that causes kswapd to notice sooner
> > when high-order watermarks have been hit. There have been a number
> > of changes in page reclaim since 2.6.30 that might have delayed
> > when kswapd kicks in for higher orders
> >
> > If your problem goes away with these three patches applied, please
> > tell me
>
> 1+2+3 do not help either
>
> > Test 4: If you are still getting failures, apply the following
> > 4/5 page allocator: Pre-emptively wake kswapd when high-order watermarks are hit
> >
> > This patch is very heavy handed and pre-emptively kicks kswapd when
> > watermarks are hit. It should only be necessary if there has been
> > significant changes in the timing and density of page allocations
> > from an unknown source. Tobias, this patch is largely aimed at you.
> > You reported that with patches 3+4 applied that your problems went
> > away. I need to know if patch 3 on its own is enough or if both
> > are required
> >
> > If your problem goes away with these four patches applied, please
> > tell me
>
> 3 allone does not help
> 3+4 does ...
>
This is a bit surprising.....
Tell me, do you have an Intel IO-MMU on your system by any chance? It should
be mentioned in either dmesg or lspci -v (please send the full output of
both). If you do have one of these things, I notice they abuse PF_MEMALLOC
which would explain why this patch makes a difference to your testing.
Thanks
--
Mel Gorman
Part-time Phd Student Linux Technology Center
University of Limerick IBM Dublin Software Lab
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* [PATCH 0/3] net: TCP thin-stream latency-improving modifications
From: Andreas Petlund @ 2009-10-27 16:28 UTC (permalink / raw)
To: netdev; +Cc: linux-kernel, shemminger, ilpo.jarvinen, davem
This is a series of patches enabling non-intrusive, dynamically triggered modifications that improves retransmission latencies for thin streams.
The patches are based on the original modifications posted in this RFC:
http://article.gmane.org/gmane.linux.rt.user/3674/match=
http://article.gmane.org/gmane.linux.kernel/779290/match=
We have done our best to address the feedback from the RFC in the new patch set.
TCP streams with high interarrival time between packets (thin streams) are often found to be produced by interactive/time-dependent applications. Such streams are not able to trigger fast retransmissions, since too few dupACKs are received before a retransmission by timeout occurs. Exponential backoff also leads to large delays. Since the applications producing such data patterns are very often time-dependent, this causes delays that are very disturbing for the application performance/experience. This set of patches introduce two simple modifications that improves the latencies for thin streams:
1) If the stream is thin, fast retransmit on the first dupACK.
2) If the stream is thin, do not apply exponential backoff.
The modifications are only active if specifically enabled by syscontrol or iocontrol. If enabled, the thin-stream detection is dynamically triggering the modifications on and off based on the current number of packets in flight. Thus, regular (greedy) streams do not trigger the modifications.
The modifications are thoroughly tested and found to improve retransmission latency considerably without negatively influencing fairness. This is also the case when very many streams using the modifications share a common bottleneck.
We have also developed a bundling mechanism (see the RFC linked to above) that can be used in thin-stream scenarios where the packet sizes are small. This mechanism is more intrusive, and will be posted for the net-next tree when we have revised the design.
For more information on time-dependent thin streams and the modifications, please refer to the articles linked to below:
http://simula.no/research/networks/publications/Simula.ND.159/simula_pdf_file
http://simula.no/research/networks/publications/Simula.ND.185/simula_pdf_file
http://simula.no/research/networks/publications/Simula.ND.112/simula_pdf_file
http://simula.no/research/networks/publications/Simula.ND.35/simula_pdf_file
Cheers,
Andreas
^ permalink raw reply
* [PATCH 1/3] net: TCP thin-stream detection
From: Andreas Petlund @ 2009-10-27 16:31 UTC (permalink / raw)
To: netdev; +Cc: linux-kernel, shemminger, ilpo.jarvinen, davem
Inline function to dynamically detect thin streams based on the number of packets in flight. Used to trigger thin-stream mechanisms.
Signed-off-by: Andreas Petlund <apetlund@simula.no>
---
include/net/tcp.h | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 03a49c7..7c4482f 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -800,6 +800,14 @@ static inline bool tcp_in_initial_slowstart(const struct tcp_sock *tp)
return tp->snd_ssthresh >= TCP_INFINITE_SSTHRESH;
}
+/* Determines whether this is a thin stream (which may suffer from
+ * increased latency). Used to trigger latency-reducing mechanisms.
+ */
+static inline unsigned int tcp_stream_is_thin(const struct tcp_sock *tp)
+{
+ return tp->packets_out < 4;
+}
+
/* If cwnd > ssthresh, we may raise ssthresh to be half-way to cwnd.
* The exception is rate halving phase, when cwnd is decreasing towards
* ssthresh.
--
1.6.0.4
^ permalink raw reply related
* [PATCH 2/3] net: TCP thin linear timeouts
From: Andreas Petlund @ 2009-10-27 16:31 UTC (permalink / raw)
To: netdev; +Cc: linux-kernel, shemminger, ilpo.jarvinen, davem
This patch will make TCP use only linear timeouts if the stream is thin. This will help to avoid the very high latencies that thin stream suffer because of exponential backoff. This mechanism is only active if enabled by iocontrol or syscontrol and the stream is identified as thin.
Signed-off-by: Andreas Petlund <apetlund@simula.no>
---
include/linux/tcp.h | 3 +++
include/net/tcp.h | 1 +
net/ipv4/sysctl_net_ipv4.c | 8 ++++++++
net/ipv4/tcp.c | 5 +++++
net/ipv4/tcp_timer.c | 17 ++++++++++++++++-
5 files changed, 33 insertions(+), 1 deletions(-)
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 61723a7..e64368d 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -96,6 +96,7 @@ enum {
#define TCP_QUICKACK 12 /* Block/reenable quick acks */
#define TCP_CONGESTION 13 /* Congestion control algorithm */
#define TCP_MD5SIG 14 /* TCP MD5 Signature (RFC2385) */
+#define TCP_THIN_RM_EXPB 15 /* Remove exp. backoff for thin streams*/
#define TCPI_OPT_TIMESTAMPS 1
#define TCPI_OPT_SACK 2
@@ -299,6 +300,8 @@ struct tcp_sock {
u16 advmss; /* Advertised MSS */
u8 frto_counter; /* Number of new acks after RTO */
u8 nonagle; /* Disable Nagle algorithm? */
+ u8 thin_rm_expb:1, /* Remove exp. backoff for thin streams */
+ thin_undef : 7;
/* RTT measurement */
u32 srtt; /* smoothed round trip time << 3 */
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 7c4482f..412c1bd 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -237,6 +237,7 @@ extern int sysctl_tcp_base_mss;
extern int sysctl_tcp_workaround_signed_windows;
extern int sysctl_tcp_slow_start_after_idle;
extern int sysctl_tcp_max_ssthresh;
+extern int sysctl_tcp_force_thin_rm_expb;
extern atomic_t tcp_memory_allocated;
extern struct percpu_counter tcp_sockets_allocated;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 2dcf04d..7458f37 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -713,6 +713,14 @@ static struct ctl_table ipv4_table[] = {
.proc_handler = proc_dointvec,
},
{
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "tcp_force_thin_rm_expb",
+ .data = &sysctl_tcp_force_thin_rm_expb,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+ {
.ctl_name = CTL_UNNUMBERED,
.procname = "udp_mem",
.data = &sysctl_udp_mem,
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 90b2e06..b4b0931 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2134,6 +2134,11 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
}
break;
+ case TCP_THIN_RM_EXPB:
+ if (val)
+ tp->thin_rm_expb = 1;
+ break;
+
case TCP_CORK:
/* When set indicates to always queue non-full frames.
* Later the user clears this option and we transmit
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index cdb2ca7..24d6dc3 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -29,6 +29,7 @@ int sysctl_tcp_keepalive_intvl __read_mostly = TCP_KEEPALIVE_INTVL;
int sysctl_tcp_retries1 __read_mostly = TCP_RETR1;
int sysctl_tcp_retries2 __read_mostly = TCP_RETR2;
int sysctl_tcp_orphan_retries __read_mostly;
+int sysctl_tcp_force_thin_rm_expb __read_mostly;
static void tcp_write_timer(unsigned long);
static void tcp_delack_timer(unsigned long);
@@ -386,7 +387,21 @@ void tcp_retransmit_timer(struct sock *sk)
icsk->icsk_retransmits++;
out_reset_timer:
- icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);
+ if ((tp->thin_rm_expb || sysctl_tcp_force_thin_rm_expb) &&
+ tcp_stream_is_thin(tp) && sk->sk_state == TCP_ESTABLISHED) {
+ /* If stream is thin, remove exponential backoff.
+ * Since 'icsk_backoff' is used to reset timer, set to 0
+ * Recalculate 'icsk_rto' as this might be increased if
+ * stream oscillates between thin and thick, thus the old
+ * value might already be too high compared to the value
+ * set by 'tcp_set_rto' in tcp_input.c which resets the
+ * rto without backoff. */
+ icsk->icsk_backoff = 0;
+ icsk->icsk_rto = min(((tp->srtt >> 3) + tp->rttvar), TCP_RTO_MAX);
+ } else {
+ /* Use normal backoff */
+ icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);
+ }
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX);
if (retransmits_timed_out(sk, sysctl_tcp_retries1 + 1))
__sk_dst_reset(sk);
--
1.6.0.4
^ permalink raw reply related
* [PATCH 3/3] net: TCP thin dupack
From: Andreas Petlund @ 2009-10-27 16:31 UTC (permalink / raw)
To: netdev; +Cc: linux-kernel, shemminger, ilpo.jarvinen, davem
This patch enables fast retransmissions after one dupACK for TCP if the stream is identified as thin. This will reduce latencies for thin streams that are not able to trigger fast retransmissions due to high packet interarrival time. This mechanism is only active if enabled by iocontrol or syscontrol and the stream is identified as thin.
Signed-off-by: Andreas Petlund <apetlund@simula.no>
---
include/linux/tcp.h | 4 +++-
include/net/tcp.h | 1 +
net/ipv4/sysctl_net_ipv4.c | 8 ++++++++
net/ipv4/tcp.c | 5 +++++
net/ipv4/tcp_input.c | 8 ++++++++
5 files changed, 25 insertions(+), 1 deletions(-)
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index e64368d..f4a05ff 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -97,6 +97,7 @@ enum {
#define TCP_CONGESTION 13 /* Congestion control algorithm */
#define TCP_MD5SIG 14 /* TCP MD5 Signature (RFC2385) */
#define TCP_THIN_RM_EXPB 15 /* Remove exp. backoff for thin streams*/
+#define TCP_THIN_DUPACK 16 /* Fast retrans. after 1 dupack */
#define TCPI_OPT_TIMESTAMPS 1
#define TCPI_OPT_SACK 2
@@ -301,7 +302,8 @@ struct tcp_sock {
u8 frto_counter; /* Number of new acks after RTO */
u8 nonagle; /* Disable Nagle algorithm? */
u8 thin_rm_expb:1, /* Remove exp. backoff for thin streams */
- thin_undef : 7;
+ thin_dupack : 1,/* Fast retransmit on first dupack */
+ thin_undef : 6;
/* RTT measurement */
u32 srtt; /* smoothed round trip time << 3 */
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 412c1bd..41f3a5e 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -238,6 +238,7 @@ extern int sysctl_tcp_workaround_signed_windows;
extern int sysctl_tcp_slow_start_after_idle;
extern int sysctl_tcp_max_ssthresh;
extern int sysctl_tcp_force_thin_rm_expb;
+extern int sysctl_tcp_force_thin_dupack;
extern atomic_t tcp_memory_allocated;
extern struct percpu_counter tcp_sockets_allocated;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 7458f37..8653867 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -721,6 +721,14 @@ static struct ctl_table ipv4_table[] = {
.proc_handler = proc_dointvec
},
{
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "tcp_force_thin_dupack",
+ .data = &sysctl_tcp_force_thin_dupack,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+ {
.ctl_name = CTL_UNNUMBERED,
.procname = "udp_mem",
.data = &sysctl_udp_mem,
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index b4b0931..de190db 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2139,6 +2139,11 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
tp->thin_rm_expb = 1;
break;
+ case TCP_THIN_DUPACK:
+ if (val)
+ tp->thin_dupack = 1;
+ break;
+
case TCP_CORK:
/* When set indicates to always queue non-full frames.
* Later the user clears this option and we transmit
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index d86784b..b71eb89 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -89,6 +89,8 @@ int sysctl_tcp_frto __read_mostly = 2;
int sysctl_tcp_frto_response __read_mostly;
int sysctl_tcp_nometrics_save __read_mostly;
+int sysctl_tcp_force_thin_dupack __read_mostly;
+
int sysctl_tcp_moderate_rcvbuf __read_mostly = 1;
int sysctl_tcp_abc __read_mostly;
@@ -2447,6 +2449,12 @@ static int tcp_time_to_recover(struct sock *sk)
return 1;
}
+ /* If a thin stream is detected, retransmit after first
+ * received dupack */
+ if ((tp->thin_dupack || sysctl_tcp_force_thin_dupack) &&
+ tcp_dupack_heurestics(tp) > 1 && tcp_stream_is_thin(tp))
+ return 1;
+
return 0;
}
--
1.6.0.4
^ permalink raw reply related
* Re: [PATCH] dcache: better name hash function
From: Rick Jones @ 2009-10-27 16:38 UTC (permalink / raw)
To: Eric Dumazet
Cc: Stephen Hemminger, Al Viro, Andrew Morton, Linus Torvalds,
Octavian Purdila, netdev, linux-kernel
In-Reply-To: <4AE65EDE.8080605@gmail.com>
Previously Stephen kindly sent me the source and instructions, and attached are
results from 1.0 GHz Itanium "McKinley" processors using an older gcc, both -O2
and -O3, -O2 first:
>>>
>>>
>>> $ ./hashtest 10000000 14 | sort -n -k 3 -k 2
>>> Algorithm Time Ratio Max StdDev
>>> string10 0.234133 1.00 612 0.03
>>> fnv32 0.241471 1.00 689 0.93
>>> fnv64 0.241964 1.00 680 0.85
>>> string_hash17 0.269656 1.00 645 0.36
>>> jhash_string 0.295795 1.00 702 1.00
>>> crc 1.609449 1.00 634 0.41
>>> md5_string 2.479467 1.00 720 0.99
>>> SuperFastHash 0.273793 1.01 900 2.13
>>> djb2 0.265877 1.15 964 9.52
>>> string_hash31 0.259110 1.21 1039 11.39
>>> sdbm 0.369414 2.87 3268 33.77
>>> elf 0.372251 3.71 2907 40.71
>>> pjw 0.401732 3.71 2907 40.71
>>> full_name_hash 0.283508 13.09 8796 85.91
>>> kr_hash 0.220033 499.17 468448 551.55
>>> fletcher 0.267009 499.17 468448 551.55
>>> adler32 0.635047 499.17 468448 551.55
>>> xor 0.220314 854.94 583189 722.12
>>> lastchar 0.155236 1637.61 1000000 999.69
>>
>>
>> here then are both, from a 1.0 GHz McKinley system, 64-bit, using an older
>> gcc
>>
>> raj@oslowest:~/hashtest$ ./hashtest 10000000 14 | sort -n -k 3 -k 2
>> Algorithm Time Ratio Max StdDev
>> string_hash17 0.901319 1.00 645 0.36
>> string10 0.986391 1.00 612 0.03
>> jhash_string 1.422065 1.00 702 1.00
>> fnv32 1.705116 1.00 689 0.93
>> fnv64 1.900326 1.00 680 0.85
>> crc 3.651519 1.00 634 0.41
>> md5_string 14.155621 1.00 720 0.99
>> SuperFastHash 1.185206 1.01 900 2.13
>> djb2 0.977166 1.15 964 9.52
>> string_hash31 0.989804 1.21 1039 11.39
>> sdbm 1.188299 2.87 3268 33.77
>> pjw 1.185963 3.71 2907 40.71
>> elf 1.257023 3.71 2907 40.71
>> full_name_hash 1.231514 13.09 8796 85.91
>> kr_hash 0.890761 499.17 468448 551.55
>> fletcher 1.080981 499.17 468448 551.55
>> adler32 4.141714 499.17 468448 551.55
>> xor 1.061445 854.94 583189 722.12
>> lastchar 0.676697 1637.61 1000000 999.69
>>
>> raj@oslowest:~/hashtest$ ./hashtest 10000000 8 | sort -n -k 3 -k 2
>> Algorithm Time Ratio Max StdDev
>> string_hash17 0.899988 1.00 39497 1.50
>> string10 0.985100 1.00 39064 0.01
>> SuperFastHash 1.141748 1.00 40497 2.17
>> jhash_string 1.376414 1.00 39669 1.04
>> fnv32 1.656967 1.00 39895 2.25
>> fnv64 1.855259 1.00 39215 0.35
>> crc 3.615341 1.00 39088 0.07
>> md5_string 14.113307 1.00 39605 0.98
>> djb2 0.972180 1.15 60681 76.16
>> string_hash31 0.982233 1.21 64950 91.12
>> sdbm 1.181952 2.38 129900 232.22
>> pjw 1.178994 2.45 99990 237.86
>> elf 1.250936 2.45 99990 237.86
>> kr_hash 0.892633 7.80 468451 515.52
>> fletcher 1.082932 7.80 468451 515.52
>> adler32 4.142414 7.80 468451 515.52
>> full_name_hash 1.175324 13.09 562501 687.24
>> xor 1.060091 13.36 583189 694.98
>> lastchar 0.675610 25.60 1000000 980.27
>>
>> raj@oslowest:~/hashtest$ gcc -v
>> Using built-in specs.
>> Target: ia64-linux-gnu
>> Configured with: ../src/configure -v
--enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr
--enable-shared --with-system-zlib --libexecdir=/usr/lib
--without-included-gettext --enable-threads=posix --enable-nls
--program-suffix=-4.1 --enable-__cxa_atexit --enable-clocale=gnu
--enable-libstdcxx-debug --enable-mpfr --disable-libssp --with-system-libunwind
--enable-checking=release ia64-linux-gnu
>> Thread model: posix
>> gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)
>> raj@oslowest:~/hashtest$
>>
>> fnv doesn't seem to do as well there relative to the others as it did in your
>> tests.
>
>
>
> You could try -O3 since then gcc may replace the multiply with shift/add
> or is there something about forcing 32 and 64 bit that makes ia64 suffer.
It seems to speed things up, but the relative ordering remains the same:
oslowest:/home/raj/hashtest# make
cc -O3 -Wall -c -o hashtest.o hashtest.c
cc -O3 -Wall -c -o md5.o md5.c
cc -lm hashtest.o md5.o -o hashtest
oslowest:/home/raj/hashtest# ./hashtest 10000000 14 | sort -n -k 3 -k 2
Algorithm Time Ratio Max StdDev
string_hash17 0.893813 1.00 645 0.36
string10 0.965596 1.00 612 0.03
jhash_string 1.387773 1.00 702 1.00
fnv32 1.699041 1.00 689 0.93
fnv64 1.882314 1.00 680 0.85
crc 3.273676 1.00 634 0.41
md5_string 13.913745 1.00 720 0.99
SuperFastHash 1.135802 1.01 900 2.13
djb2 0.951571 1.15 964 9.52
string_hash31 0.971081 1.21 1039 11.39
sdbm 1.168148 2.87 3268 33.77
pjw 1.159304 3.71 2907 40.71
elf 1.237662 3.71 2907 40.71
full_name_hash 1.212588 13.09 8796 85.91
kr_hash 0.856584 499.17 468448 551.55
fletcher 1.054516 499.17 468448 551.55
adler32 4.123742 499.17 468448 551.55
xor 1.031910 854.94 583189 722.12
lastchar 0.648597 1637.61 1000000 999.69
oslowest:/home/raj/hashtest# ./hashtest 10000000 8 | sort -n -k 3 -k 2
Algorithm Time Ratio Max StdDev
string_hash17 0.884829 1.00 39497 1.50
string10 0.962258 1.00 39064 0.01
SuperFastHash 1.088602 1.00 40497 2.17
jhash_string 1.340878 1.00 39669 1.04
fnv32 1.637096 1.00 39895 2.25
fnv64 1.842330 1.00 39215 0.35
crc 3.230291 1.00 39088 0.07
md5_string 13.863056 1.00 39605 0.98
djb2 0.944159 1.15 60681 76.16
string_hash31 0.961978 1.21 64950 91.12
sdbm 1.159156 2.38 129900 232.22
pjw 1.154286 2.45 99990 237.86
elf 1.232842 2.45 99990 237.86
kr_hash 0.856873 7.80 468451 515.52
fletcher 1.055389 7.80 468451 515.52
adler32 4.123254 7.80 468451 515.52
full_name_hash 1.152628 13.09 562501 687.24
xor 1.033050 13.36 583189 694.98
lastchar 0.647504 25.60 1000000 980.27
^ permalink raw reply
* [PATCH] cnic: Fix L2CTX_STATUSB_NUM offset in context memory.
From: Michael Chan @ 2009-10-27 16:58 UTC (permalink / raw)
To: davem; +Cc: netdev, benli
The BNX2_L2CTX_STATUSB_NUM definition needs to be changed to match
the recent firmware update:
commit 078b0735881c7969aaf21469f3577831cddd9f8c
bnx2: Update firmware to 5.0.0.j3.
Without the fix, bnx2 can crash intermittently in bnx2_rx_int() when
iSCSI is enabled.
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: Benjamin Li <benli@broadcom.com>
---
drivers/net/bnx2.h | 9 ++++++---
drivers/net/cnic.c | 6 +++---
2 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index 6c7f795..a4d8340 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -361,9 +361,12 @@ struct l2_fhdr {
#define BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE (1<<28)
#define BNX2_L2CTX_HOST_BDIDX 0x00000004
-#define BNX2_L2CTX_STATUSB_NUM_SHIFT 16
-#define BNX2_L2CTX_STATUSB_NUM(sb_id) \
- (((sb_id) > 0) ? (((sb_id) + 7) << BNX2_L2CTX_STATUSB_NUM_SHIFT) : 0)
+#define BNX2_L2CTX_L5_STATUSB_NUM_SHIFT 16
+#define BNX2_L2CTX_L2_STATUSB_NUM_SHIFT 24
+#define BNX2_L2CTX_L5_STATUSB_NUM(sb_id) \
+ (((sb_id) > 0) ? (((sb_id) + 7) << BNX2_L2CTX_L5_STATUSB_NUM_SHIFT) : 0)
+#define BNX2_L2CTX_L2_STATUSB_NUM(sb_id) \
+ (((sb_id) > 0) ? (((sb_id) + 7) << BNX2_L2CTX_L2_STATUSB_NUM_SHIFT) : 0)
#define BNX2_L2CTX_HOST_BSEQ 0x00000008
#define BNX2_L2CTX_NX_BSEQ 0x0000000c
#define BNX2_L2CTX_NX_BDHADDR_HI 0x00000010
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 46c87ec..3bf1b04 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -2264,9 +2264,9 @@ static void cnic_init_bnx2_rx_ring(struct cnic_dev *dev)
cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_CTX_TYPE, val);
if (sb_id == 0)
- val = 2 << BNX2_L2CTX_STATUSB_NUM_SHIFT;
+ val = 2 << BNX2_L2CTX_L2_STATUSB_NUM_SHIFT;
else
- val = BNX2_L2CTX_STATUSB_NUM(sb_id);
+ val = BNX2_L2CTX_L2_STATUSB_NUM(sb_id);
cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_HOST_BDIDX, val);
rxbd = (struct rx_bd *) (cp->l2_ring + BCM_PAGE_SIZE);
@@ -2423,7 +2423,7 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
cp->int_num = 0;
if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
u32 sb_id = cp->status_blk_num;
- u32 sb = BNX2_L2CTX_STATUSB_NUM(sb_id);
+ u32 sb = BNX2_L2CTX_L5_STATUSB_NUM(sb_id);
cp->int_num = sb_id << BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT;
cnic_ctx_wr(dev, cp->kwq_cid_addr, L5_KRNLQ_HOST_QIDX, sb);
--
1.6.4.GIT
^ permalink raw reply related
* Re: [PATCH 2/3] net: TCP thin linear timeouts
From: Eric Dumazet @ 2009-10-27 16:56 UTC (permalink / raw)
To: Andreas Petlund; +Cc: netdev, linux-kernel, shemminger, ilpo.jarvinen, davem
In-Reply-To: <4AE72079.4030504@simula.no>
Andreas Petlund a écrit :
> This patch will make TCP use only linear timeouts if the stream is thin. This will help to avoid the very high latencies that thin stream suffer because of exponential backoff. This mechanism is only active if enabled by iocontrol or syscontrol and the stream is identified as thin.
>
Wont this reduce the session timeout to something very small, ie 15 retransmits, way under the minute ?
^ permalink raw reply
* [net-next-2.6 PATCH 0/6] net: Speedup netdevice unregisters
From: Eric Dumazet @ 2009-10-27 17:02 UTC (permalink / raw)
To: David S. Miller; +Cc: Linux Netdev List
netdevice unregisters are serialized and call synchronize_{net|rcu}()
three times per device.
This means it can take a long time to remove a device, if many virtual
devices are attached. (vlan, macvlan, tunnels, ...)
This patch series partially solve the problem by batching several devices in a list,
so that two synchronize_net() calls can be factorized.
Some results on my dev machine (2x4 cpus, HZ=1000, PREEMPT):
modprobe dummy numdummies=10000
# unregister 10000 DOWN netdevices
time rmmod dummy
Before patches :
real 2m0.303s (12 ms per device)
user 0m0.001s
sys 0m0.117s
After patches 1,2,3 :
real 0m1.111s
user 0m0.001s
sys 0m0.922s (mostly sysfs overhead)
modprobe dummy
ip link set dummy0 up
for f in `seq 1 1000`
do
ip link add link dummy0 dummy0.$f type vlan id $f
ip link set dummy0.$f up
done
# Dismantle of 1000 UP vlans (but no IP address)
time rmmod dummy
Before patches :
real 0m40.410s (40 ms per vlan)
user 0m0.000s
sys 0m0.022s
After patches 1,2,3 :
real 0m20.990s
user 0m0.001s
sys 0m0.011s
After patch 4 (vlan: Use unregister_netdevice_many())
real 0m4.392s (-> 4.3 ms per vlan)
user 0m0.000s
sys 0m0.067s
We still have a synchronize_rcu() in dev_deactivate() that could be
factorized in followup patches if there is some interest.
PATCH 1/6 : net: Introduce unregister_netdevice_queue()
PATCH 2/6 : net: Introduce unregister_netdevice_many()
PATCH 3/6 : net: Add a list_head parameter to dellink() method
PATCH 4/6 : vlan: Optimize multiple unregistration
PATCH 5/6 : ipip: Optimize multiple unregistration
PATCH 6/6 : gre: Optimize multiple unregistration
^ permalink raw reply
* [PATCH 1/6] net: Introduce unregister_netdevice_queue()
From: Eric Dumazet @ 2009-10-27 17:03 UTC (permalink / raw)
To: David S. Miller; +Cc: Linux Netdev List
This patchs adds an unreg_list anchor to struct net_device, and
introduces an unregister_netdevice_queue() function, able to queue
a net_device to a list instead of immediately unregister it.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
include/linux/netdevice.h | 9 ++++++++-
net/core/dev.c | 20 +++++++++++++-------
2 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 8380009..0ded0a4 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -683,6 +683,7 @@ struct net_device
struct list_head dev_list;
struct list_head napi_list;
+ struct list_head unreg_list;
/* Net device features */
unsigned long features;
@@ -1116,7 +1117,13 @@ extern int dev_close(struct net_device *dev);
extern void dev_disable_lro(struct net_device *dev);
extern int dev_queue_xmit(struct sk_buff *skb);
extern int register_netdevice(struct net_device *dev);
-extern void unregister_netdevice(struct net_device *dev);
+extern void unregister_netdevice_queue(struct net_device *dev,
+ struct list_head *head);
+static inline void unregister_netdevice(struct net_device *dev)
+{
+ unregister_netdevice_queue(dev, NULL);
+}
+
extern void free_netdev(struct net_device *dev);
extern void synchronize_net(void);
extern int register_netdevice_notifier(struct notifier_block *nb);
diff --git a/net/core/dev.c b/net/core/dev.c
index 950c13f..ff94e2b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5245,25 +5245,31 @@ void synchronize_net(void)
EXPORT_SYMBOL(synchronize_net);
/**
- * unregister_netdevice - remove device from the kernel
+ * unregister_netdevice_queue - remove device from the kernel
* @dev: device
- *
+ * @head: list
+
* This function shuts down a device interface and removes it
* from the kernel tables.
+ * If head not NULL, device is queued to be unregistered later.
*
* Callers must hold the rtnl semaphore. You may want
* unregister_netdev() instead of this.
*/
-void unregister_netdevice(struct net_device *dev)
+void unregister_netdevice_queue(struct net_device *dev, struct list_head *head)
{
ASSERT_RTNL();
- rollback_registered(dev);
- /* Finish processing unregister after unlock */
- net_set_todo(dev);
+ if (head) {
+ list_add_tail(&dev->unreg_list, head);
+ } else {
+ rollback_registered(dev);
+ /* Finish processing unregister after unlock */
+ net_set_todo(dev);
+ }
}
-EXPORT_SYMBOL(unregister_netdevice);
+EXPORT_SYMBOL(unregister_netdevice_queue);
/**
* unregister_netdev - remove device from the kernel
^ permalink raw reply related
* [PATCH 2/6] net: Introduce unregister_netdevice_many()
From: Eric Dumazet @ 2009-10-27 17:04 UTC (permalink / raw)
To: David S. Miller; +Cc: Linux Netdev List
Introduce rollback_registered_many() and unregister_netdevice_many()
rollback_registered_many() is able to perform necessary steps at device dismantle
time, factorizing two expensive synchronize_net() calls.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
include/linux/netdevice.h | 1
net/core/dev.c | 97 ++++++++++++++++++++++++------------
2 files changed, 66 insertions(+), 32 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 0ded0a4..e7c227d 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1119,6 +1119,7 @@ extern int dev_queue_xmit(struct sk_buff *skb);
extern int register_netdevice(struct net_device *dev);
extern void unregister_netdevice_queue(struct net_device *dev,
struct list_head *head);
+extern void unregister_netdevice_many(struct list_head *head);
static inline void unregister_netdevice(struct net_device *dev)
{
unregister_netdevice_queue(dev, NULL);
diff --git a/net/core/dev.c b/net/core/dev.c
index ff94e2b..15d1453 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4637,59 +4637,76 @@ static void net_set_todo(struct net_device *dev)
list_add_tail(&dev->todo_list, &net_todo_list);
}
-static void rollback_registered(struct net_device *dev)
+static void rollback_registered_many(struct list_head *head)
{
+ struct net_device *dev;
+
BUG_ON(dev_boot_phase);
ASSERT_RTNL();
- /* Some devices call without registering for initialization unwind. */
- if (dev->reg_state == NETREG_UNINITIALIZED) {
- printk(KERN_DEBUG "unregister_netdevice: device %s/%p never "
- "was registered\n", dev->name, dev);
+ list_for_each_entry(dev, head, unreg_list) {
+ /* Some devices call without registering
+ * for initialization unwind.
+ */
+ if (dev->reg_state == NETREG_UNINITIALIZED) {
+ pr_debug("unregister_netdevice: device %s/%p never "
+ "was registered\n", dev->name, dev);
- WARN_ON(1);
- return;
- }
+ WARN_ON(1);
+ return;
+ }
- BUG_ON(dev->reg_state != NETREG_REGISTERED);
+ BUG_ON(dev->reg_state != NETREG_REGISTERED);
- /* If device is running, close it first. */
- dev_close(dev);
+ /* If device is running, close it first. */
+ dev_close(dev);
- /* And unlink it from device chain. */
- unlist_netdevice(dev);
+ /* And unlink it from device chain. */
+ unlist_netdevice(dev);
- dev->reg_state = NETREG_UNREGISTERING;
+ dev->reg_state = NETREG_UNREGISTERING;
+ }
synchronize_net();
- /* Shutdown queueing discipline. */
- dev_shutdown(dev);
+ list_for_each_entry(dev, head, unreg_list) {
+ /* Shutdown queueing discipline. */
+ dev_shutdown(dev);
- /* Notify protocols, that we are about to destroy
- this device. They should clean all the things.
- */
- call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
+ /* Notify protocols, that we are about to destroy
+ this device. They should clean all the things.
+ */
+ call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
- /*
- * Flush the unicast and multicast chains
- */
- dev_unicast_flush(dev);
- dev_addr_discard(dev);
+ /*
+ * Flush the unicast and multicast chains
+ */
+ dev_unicast_flush(dev);
+ dev_addr_discard(dev);
- if (dev->netdev_ops->ndo_uninit)
- dev->netdev_ops->ndo_uninit(dev);
+ if (dev->netdev_ops->ndo_uninit)
+ dev->netdev_ops->ndo_uninit(dev);
- /* Notifier chain MUST detach us from master device. */
- WARN_ON(dev->master);
+ /* Notifier chain MUST detach us from master device. */
+ WARN_ON(dev->master);
- /* Remove entries from kobject tree */
- netdev_unregister_kobject(dev);
+ /* Remove entries from kobject tree */
+ netdev_unregister_kobject(dev);
+ }
synchronize_net();
- dev_put(dev);
+ list_for_each_entry(dev, head, unreg_list)
+ dev_put(dev);
+}
+
+static void rollback_registered(struct net_device *dev)
+{
+ LIST_HEAD(single);
+
+ list_add(&dev->unreg_list, &single);
+ rollback_registered_many(&single);
}
static void __netdev_init_queue_locks_one(struct net_device *dev,
@@ -5272,6 +5289,22 @@ void unregister_netdevice_queue(struct net_device *dev, struct list_head *head)
EXPORT_SYMBOL(unregister_netdevice_queue);
/**
+ * unregister_netdevice_many - unregister many devices
+ * @head: list of devices
+ *
+ */
+void unregister_netdevice_many(struct list_head *head)
+{
+ struct net_device *dev;
+
+ if (!list_empty(head)) {
+ rollback_registered_many(head);
+ list_for_each_entry(dev, head, unreg_list)
+ net_set_todo(dev);
+ }
+}
+
+/**
* unregister_netdev - remove device from the kernel
* @dev: device
*
^ permalink raw reply related
* [PATCH 3/6] net: add a list_head parameter to dellink() method
From: Eric Dumazet @ 2009-10-27 17:06 UTC (permalink / raw)
To: David S. Miller; +Cc: Linux Netdev List
Adding a list_head parameter to rtnl_link_ops->dellink() methods
allow us to queue devices on a list, in order to dismantle
them all at once.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
drivers/net/macvlan.c | 6 +++---
drivers/net/veth.c | 2 +-
include/net/rtnetlink.h | 3 ++-
net/8021q/vlan.c | 8 ++++----
net/8021q/vlan.h | 2 +-
net/core/dev.c | 2 +-
net/core/rtnetlink.c | 14 +++++++-------
7 files changed, 19 insertions(+), 18 deletions(-)
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 3aabfd9..20b7707 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -555,13 +555,13 @@ static int macvlan_newlink(struct net_device *dev,
return 0;
}
-static void macvlan_dellink(struct net_device *dev)
+static void macvlan_dellink(struct net_device *dev, struct list_head *head)
{
struct macvlan_dev *vlan = netdev_priv(dev);
struct macvlan_port *port = vlan->port;
list_del(&vlan->list);
- unregister_netdevice(dev);
+ unregister_netdevice_queue(dev, head);
if (list_empty(&port->vlans))
macvlan_port_destroy(port->dev);
@@ -601,7 +601,7 @@ static int macvlan_device_event(struct notifier_block *unused,
break;
case NETDEV_UNREGISTER:
list_for_each_entry_safe(vlan, next, &port->vlans, list)
- macvlan_dellink(vlan->dev);
+ macvlan_dellink(vlan->dev, NULL);
break;
}
return NOTIFY_DONE;
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index ade5b34..ffb502d 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -442,7 +442,7 @@ err_register_peer:
return err;
}
-static void veth_dellink(struct net_device *dev)
+static void veth_dellink(struct net_device *dev, struct list_head *head)
{
struct veth_priv *priv;
struct net_device *peer;
diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h
index c3aa044..cd5af1f 100644
--- a/include/net/rtnetlink.h
+++ b/include/net/rtnetlink.h
@@ -61,7 +61,8 @@ struct rtnl_link_ops {
int (*changelink)(struct net_device *dev,
struct nlattr *tb[],
struct nlattr *data[]);
- void (*dellink)(struct net_device *dev);
+ void (*dellink)(struct net_device *dev,
+ struct list_head *head);
size_t (*get_size)(const struct net_device *dev);
int (*fill_info)(struct sk_buff *skb,
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 8836575..6b5c9dd 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -140,7 +140,7 @@ static void vlan_rcu_free(struct rcu_head *rcu)
vlan_group_free(container_of(rcu, struct vlan_group, rcu));
}
-void unregister_vlan_dev(struct net_device *dev)
+void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
{
struct vlan_dev_info *vlan = vlan_dev_info(dev);
struct net_device *real_dev = vlan->real_dev;
@@ -164,7 +164,7 @@ void unregister_vlan_dev(struct net_device *dev)
synchronize_net();
- unregister_netdevice(dev);
+ unregister_netdevice_queue(dev, head);
/* If the group is now empty, kill off the group. */
if (grp->nr_vlans == 0) {
@@ -535,7 +535,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
if (grp->nr_vlans == 1)
i = VLAN_GROUP_ARRAY_LEN;
- unregister_vlan_dev(vlandev);
+ unregister_vlan_dev(vlandev, NULL);
}
break;
}
@@ -642,7 +642,7 @@ static int vlan_ioctl_handler(struct net *net, void __user *arg)
err = -EPERM;
if (!capable(CAP_NET_ADMIN))
break;
- unregister_vlan_dev(dev);
+ unregister_vlan_dev(dev, NULL);
err = 0;
break;
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index 4ade5ed..68f9290 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -82,7 +82,7 @@ void vlan_dev_get_realdev_name(const struct net_device *dev, char *result);
int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id);
void vlan_setup(struct net_device *dev);
int register_vlan_dev(struct net_device *dev);
-void unregister_vlan_dev(struct net_device *dev);
+void unregister_vlan_dev(struct net_device *dev, struct list_head *head);
static inline u32 vlan_get_ingress_priority(struct net_device *dev,
u16 vlan_tci)
diff --git a/net/core/dev.c b/net/core/dev.c
index 15d1453..dedacd8 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5629,7 +5629,7 @@ restart:
/* Delete virtual devices */
if (dev->rtnl_link_ops && dev->rtnl_link_ops->dellink) {
- dev->rtnl_link_ops->dellink(dev);
+ dev->rtnl_link_ops->dellink(dev, NULL);
goto restart;
}
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 52ea418..391a62c 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -248,7 +248,7 @@ static LIST_HEAD(link_ops);
int __rtnl_link_register(struct rtnl_link_ops *ops)
{
if (!ops->dellink)
- ops->dellink = unregister_netdevice;
+ ops->dellink = unregister_netdevice_queue;
list_add_tail(&ops->list, &link_ops);
return 0;
@@ -277,13 +277,13 @@ EXPORT_SYMBOL_GPL(rtnl_link_register);
static void __rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops)
{
struct net_device *dev;
-restart:
+ LIST_HEAD(list_kill);
+
for_each_netdev(net, dev) {
- if (dev->rtnl_link_ops == ops) {
- ops->dellink(dev);
- goto restart;
- }
+ if (dev->rtnl_link_ops == ops)
+ ops->dellink(dev, &list_kill);
}
+ unregister_netdevice_many(&list_kill);
}
void rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops)
@@ -972,7 +972,7 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
if (!ops)
return -EOPNOTSUPP;
- ops->dellink(dev);
+ ops->dellink(dev, NULL);
return 0;
}
^ permalink raw reply related
* [PATCH 4/6] vlan: Optimize multiple unregistration
From: Eric Dumazet @ 2009-10-27 17:06 UTC (permalink / raw)
To: David S. Miller; +Cc: Linux Netdev List
Use unregister_netdevice_many() to speedup master device unregister.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
include/linux/if_vlan.h | 1
net/8021q/vlan.c | 49 +++++++++++++++++++++++++-------------
net/core/dev.c | 1
3 files changed, 35 insertions(+), 16 deletions(-)
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 8898cbe..71a4870 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -85,6 +85,7 @@ struct vlan_group {
* the vlan is attached to.
*/
unsigned int nr_vlans;
+ int killall;
struct hlist_node hlist; /* linked list */
struct net_device **vlan_devices_arrays[VLAN_GROUP_ARRAY_SPLIT_PARTS];
struct rcu_head rcu;
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 6b5c9dd..511afe7 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -159,11 +159,12 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
ops->ndo_vlan_rx_kill_vid(real_dev, vlan_id);
- vlan_group_set_device(grp, vlan_id, NULL);
grp->nr_vlans--;
- synchronize_net();
-
+ if (!grp->killall) {
+ vlan_group_set_device(grp, vlan_id, NULL);
+ synchronize_net();
+ }
unregister_netdevice_queue(dev, head);
/* If the group is now empty, kill off the group. */
@@ -183,6 +184,34 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
dev_put(real_dev);
}
+void unregister_vlan_dev_alls(struct vlan_group *grp)
+{
+ LIST_HEAD(list);
+ int i;
+ struct net_device *vlandev;
+ struct vlan_group save;
+
+ memcpy(&save, grp, sizeof(save));
+ memset(&grp->vlan_devices_arrays, 0, sizeof(grp->vlan_devices_arrays));
+ grp->killall = 1;
+
+ synchronize_net();
+
+ /* Delete all VLANs for this dev. */
+ for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+ vlandev = vlan_group_get_device(&save, i);
+ if (!vlandev)
+ continue;
+
+ unregister_vlan_dev(vlandev, &list);
+ if (grp->nr_vlans == 0)
+ break;
+ }
+ unregister_netdevice_many(&list);
+ for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++)
+ kfree(save.vlan_devices_arrays[i]);
+}
+
static void vlan_transfer_operstate(const struct net_device *dev,
struct net_device *vlandev)
{
@@ -524,19 +553,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
break;
case NETDEV_UNREGISTER:
- /* Delete all VLANs for this dev. */
- for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
- vlandev = vlan_group_get_device(grp, i);
- if (!vlandev)
- continue;
-
- /* unregistration of last vlan destroys group, abort
- * afterwards */
- if (grp->nr_vlans == 1)
- i = VLAN_GROUP_ARRAY_LEN;
-
- unregister_vlan_dev(vlandev, NULL);
- }
+ unregister_vlan_dev_alls(grp);
break;
}
diff --git a/net/core/dev.c b/net/core/dev.c
index dedacd8..82a3bb9 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5303,6 +5303,7 @@ void unregister_netdevice_many(struct list_head *head)
net_set_todo(dev);
}
}
+EXPORT_SYMBOL(unregister_netdevice_many);
/**
* unregister_netdev - remove device from the kernel
^ permalink raw reply related
* [PATCH 5/6] ipip: Optimize multiple unregistration
From: Eric Dumazet @ 2009-10-27 17:06 UTC (permalink / raw)
To: David S. Miller; +Cc: Linux Netdev List
Speedup module unloading by factorizing synchronize_rcu() calls
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
net/ipv4/ipip.c | 17 +++++++++++------
1 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 3bd6998..a2ca53d 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -754,16 +754,19 @@ static struct xfrm_tunnel ipip_handler = {
static const char banner[] __initconst =
KERN_INFO "IPv4 over IPv4 tunneling driver\n";
-static void ipip_destroy_tunnels(struct ipip_net *ipn)
+static void ipip_destroy_tunnels(struct ipip_net *ipn, struct list_head *head)
{
int prio;
for (prio = 1; prio < 4; prio++) {
int h;
for (h = 0; h < HASH_SIZE; h++) {
- struct ip_tunnel *t;
- while ((t = ipn->tunnels[prio][h]) != NULL)
- unregister_netdevice(t->dev);
+ struct ip_tunnel *t = ipn->tunnels[prio][h];
+
+ while (t != NULL) {
+ unregister_netdevice_queue(t->dev, head);
+ t = t->next;
+ }
}
}
}
@@ -816,11 +819,13 @@ err_alloc:
static void ipip_exit_net(struct net *net)
{
struct ipip_net *ipn;
+ LIST_HEAD(list);
ipn = net_generic(net, ipip_net_id);
rtnl_lock();
- ipip_destroy_tunnels(ipn);
- unregister_netdevice(ipn->fb_tunnel_dev);
+ ipip_destroy_tunnels(ipn, &list);
+ unregister_netdevice_queue(ipn->fb_tunnel_dev, &list);
+ unregister_netdevice_many(&list);
rtnl_unlock();
kfree(ipn);
}
^ permalink raw reply related
* [PATCH 6/6] gre: Optimize multiple unregistration
From: Eric Dumazet @ 2009-10-27 17:07 UTC (permalink / raw)
To: David S. Miller; +Cc: Linux Netdev List
Speedup module unloading by factorizing synchronize_rcu() calls
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
net/ipv4/ip_gre.c | 15 ++++++++++-----
1 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 40f0439..a77807d 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -1290,16 +1290,19 @@ static const struct net_protocol ipgre_protocol = {
.netns_ok = 1,
};
-static void ipgre_destroy_tunnels(struct ipgre_net *ign)
+static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head)
{
int prio;
for (prio = 0; prio < 4; prio++) {
int h;
for (h = 0; h < HASH_SIZE; h++) {
- struct ip_tunnel *t;
- while ((t = ign->tunnels[prio][h]) != NULL)
- unregister_netdevice(t->dev);
+ struct ip_tunnel *t = ign->tunnels[prio][h];
+
+ while (t != NULL) {
+ unregister_netdevice_queue(t->dev, head);
+ t = t->next;
+ }
}
}
}
@@ -1347,10 +1350,12 @@ err_alloc:
static void ipgre_exit_net(struct net *net)
{
struct ipgre_net *ign;
+ LIST_HEAD(list);
ign = net_generic(net, ipgre_net_id);
rtnl_lock();
- ipgre_destroy_tunnels(ign);
+ ipgre_destroy_tunnels(ign, &list);
+ unregister_netdevice_many(&list);
rtnl_unlock();
kfree(ign);
}
^ permalink raw reply related
* Re: [PATCH] dcache: better name hash function
From: Stephen Hemminger @ 2009-10-27 17:07 UTC (permalink / raw)
To: Eric Dumazet
Cc: Stephen Hemminger, Andrew Morton, Linus Torvalds,
Octavian Purdila, netdev, linux-kernel, Al Viro
In-Reply-To: <4AE6A16F.4020002@gmail.com>
On Tue, 27 Oct 2009 08:29:51 +0100
Eric Dumazet <eric.dumazet@gmail.com> wrote:
> Eric Dumazet a écrit :
> >
> >
> > 511 value on 64bit, and 1023 on 32bit arches are nice because
> > hashsz * sizeof(pointer) <= 4096, wasting space for one pointer only.
> >
> > Conclusion : jhash and 511/1023 hashsize for netdevices,
> > no divides, only one multiply for the fold.
>
> Just forget about 511 & 1023, as power of two works too.
>
> -> 512 & 1024 + jhash
>
> Guess what, David already said this :)
Rather than wasting space, or doing expensive, modulus; just folding
the higher bits back with XOR redistributes the bits better.
On fast machine (Nehalam):
100000000 Iterations
256 Slots (order 8)
Algorithm Time Ratio Max StdDev
string10 2.505290 1.00 390628 0.00
xor 2.521329 1.00 392120 2.14
SuperFastHash 2.781745 1.00 397027 4.43
fnv32 2.847892 1.00 392139 0.98
djb2 2.886342 1.00 390827 0.12
string_hash31 2.900980 1.00 391001 0.20
string_hash17 2.938708 1.00 391122 0.20
full_name_hash 3.080886 1.00 390860 0.10
jhash_string 3.092161 1.00 392775 1.08
fnv64 5.340740 1.00 392854 0.88
kr_hash 2.395757 7.30 4379091 1568.25
On slow machine (CULV):
100000000 Iterations
256 Slots (order 8)
Algorithm Time Ratio Max StdDev
string10 10.807174 1.00 390628 0.00
SuperFastHash 11.397303 1.00 397027 4.43
xor 11.660968 1.00 392120 2.14
djb2 11.674707 1.00 390827 0.12
jhash_string 11.997104 1.00 392775 1.08
fnv32 12.289086 1.00 392139 0.98
string_hash17 12.863864 1.00 391122 0.20
full_name_hash 13.249483 1.00 390860 0.10
string_hash31 13.668270 1.00 391001 0.20
fnv64 39.808964 1.00 392854 0.88
kr_hash 10.316305 7.30 4379091 1568.25
So Eric's string10 is fastest for special case of fooNNN style names.
But probably isn't best for general strings. Orignal function
is >20% slower, which is surprising probably because of overhead
of 2 shifts and multipy. jenkins and fnv are both 10% slower.
The following seems to give best results (combination of 16bit trick
and string17).
static unsigned int xor17(const unsigned char *key, unsigned int len)
{
uint32_t h = 0;
unsigned int rem;
rem = len & 1;
len >>= 1;
while (len--) {
h = ((h << 4) + h) ^ get_unaligned16(key);
key += sizeof(uint16_t);
}
if (rem)
h = ((h << 4) + h) ^ *key;
return h;
}
^ permalink raw reply
* [PATCH] net: fold network name hash
From: Stephen Hemminger @ 2009-10-27 17:22 UTC (permalink / raw)
To: David Miller
Cc: netdev, linux-kernel, eric.dumazet, akpm, torvalds, opurdila,
netdev, linux-kernel, viro
In-Reply-To: <20091026.222428.80364204.davem@davemloft.net>
The full_name_hash does not produce a value that is evenly distributed
over the lower 8 bits. This causes name hash to be unbalanced with large
number of names. A simple fix is to just fold in the higher bits
with XOR.
This is independent of possible improvements to full_name_hash()
in future.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/core/dev.c 2009-10-27 09:21:46.127252547 -0700
+++ b/net/core/dev.c 2009-10-27 09:25:14.593313378 -0700
@@ -199,7 +199,11 @@ EXPORT_SYMBOL(dev_base_lock);
static inline struct hlist_head *dev_name_hash(struct net *net, const char *name)
{
unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ));
- return &net->dev_name_head[hash & ((1 << NETDEV_HASHBITS) - 1)];
+
+ hash ^= (hash >> NETDEV_HASHBITS);
+ hash &= NETDEV_HASHENTRIES - 1;
+
+ return &net->dev_name_head[hash];
}
static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex)
^ permalink raw reply
* Re: [PATCH 2/6] net: Introduce unregister_netdevice_many()
From: Octavian Purdila @ 2009-10-27 17:26 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David S. Miller, Linux Netdev List
In-Reply-To: <4AE72813.5080709@gmail.com>
On Tuesday 27 October 2009 19:04:19 you wrote:
> +void unregister_netdevice_many(struct list_head *head)
> +{
> + struct net_device *dev;
> +
> + if (!list_empty(head)) {
> + rollback_registered_many(head);
> + list_for_each_entry(dev, head, unreg_list)
> + net_set_todo(dev);
> + }
> +}
>
Looks like EXPORT_SYMBOL(unregister_netdevice_many) is missing?
Thanks,
tavi
^ permalink raw reply
* Re: [PATCH] dcache: better name hash function
From: Linus Torvalds @ 2009-10-27 17:32 UTC (permalink / raw)
To: Stephen Hemminger
Cc: Eric Dumazet, Stephen Hemminger, Andrew Morton, Octavian Purdila,
netdev, linux-kernel, Al Viro
In-Reply-To: <20091027100736.5303f1ab@nehalam>
On Tue, 27 Oct 2009, Stephen Hemminger wrote:
>
> Rather than wasting space, or doing expensive, modulus; just folding
> the higher bits back with XOR redistributes the bits better.
Please don't make up any new hash functions without having a better input
set than the one you seem to use.
The 'fnv' function I can believe in, because the whole "multiply by big
prime number" thing to spread out the bits is a very traditional model.
But making up a new hash function based on essentially consecutive names
is absolutely the wrong thing to do. You need a much better corpus of path
component names for testing.
> The following seems to give best results (combination of 16bit trick
> and string17).
.. and these kinds of games are likely to work badly on some
architectures. Don't use 16-bit values, and don't use 'get_unaligned()'.
Both tend to work fine on x86, but likely suck on some other
architectures.
Also remember that the critical hash function needs to check for '/' and
'\0' while at it, which is one reason why it does things byte-at-a-time.
If you try to be smart, you'd need to be smart about the end condition
too.
The loop to optimize is _not_ based on 'name+len', it is this code:
this.name = name;
c = *(const unsigned char *)name;
hash = init_name_hash();
do {
name++;
hash = partial_name_hash(c, hash);
c = *(const unsigned char *)name;
} while (c && (c != '/'));
this.len = name - (const char *) this.name;
this.hash = end_name_hash(hash);
(which depends on us having already removed all slashed at the head, and
knowing that the string is not zero-sized)
So doing things multiple bytes at a time is certainly still possible, but
you would always have to find the slashes/NUL's in there first. Doing that
efficiently and portably is not trivial - especially since a lot of
critical path components are short.
(Remember: there may be just a few 'bin' directory names, but if you do
performance analysis, 'bin' as a path component is probably hashed a lot
more than 'five_slutty_bimbos_and_a_donkey.jpg'. So the relative weighting
of importance of the filename should probably include the frequency it
shows up in pathname lookup)
Linus
^ permalink raw reply
* Re: [PATCH] dcache: better name hash function
From: Stephen Hemminger @ 2009-10-27 17:35 UTC (permalink / raw)
To: Eric Dumazet, David Miller; +Cc: netdev, linux-kernel
In-Reply-To: <4AE72B91.7040700@gmail.com>
On Tue, 27 Oct 2009 18:19:13 +0100
Eric Dumazet <eric.dumazet@gmail.com> wrote:
> Stephen Hemminger a écrit :
>
> > So Eric's string10 is fastest for special case of fooNNN style names.
> > But probably isn't best for general strings. Orignal function
> > is >20% slower, which is surprising probably because of overhead
> > of 2 shifts and multipy. jenkins and fnv are both 10% slower.
> >
>
>
> jhash() is faster when strings are longer, being able to process 12 bytes per loop.
>
But jhash is not amenable to usage in namei (with partial_name_hash).
name_hash is rarely done on long strings, the average length of a filename
is fairly short (probably leftover Unix legacy). On my system, average
path component length in /usr is 13 characters; therefore jhash has
no big benefit here.
^ permalink raw reply
* Re: [PATCH 2/6] net: Introduce unregister_netdevice_many()
From: Eric Dumazet @ 2009-10-27 17:40 UTC (permalink / raw)
To: Octavian Purdila; +Cc: David S. Miller, Linux Netdev List
In-Reply-To: <200910271926.41734.opurdila@ixiacom.com>
Octavian Purdila a écrit :
> Looks like EXPORT_SYMBOL(unregister_netdevice_many) is missing?
>
I added it in following patch, when really needed/used
^ permalink raw reply
* Re: wanPMC-CxT1E1
From: Bob Beers @ 2009-10-27 17:48 UTC (permalink / raw)
To: Greg KH; +Cc: netdev
In-Reply-To: <20091026204144.GA28436@kroah.com>
On Mon, Oct 26, 2009 at 4:41 PM, Greg KH <greg@kroah.com> wrote:
> Getting it to build on 2.6.31 is more important than RHEL5, we can't do
> anything with an old kernel like that.
ok, so where do I start, I have a system ready to start
git cloning, and creating patches. I googled for a while
but didn't find a nice recipe for participating in the -staging
process.
I'll try to add something here[1] if I get some good advice.
thanks,
-Bob Beers
[1] <http://www.linuxdriverproject.org/foswiki/bin/view/Main/OutOfTreeDrivers>
^ permalink raw reply
* [PATCH 2/3] [RFC] Add c/r support for connected INET sockets (v3)
From: Dan Smith @ 2009-10-27 17:53 UTC (permalink / raw)
To: containers; +Cc: netdev, Oren Laadan, John Dykstra
In-Reply-To: <1256666008-8231-1-git-send-email-danms@us.ibm.com>
This patch adds basic support for C/R of open INET sockets. I think that
all the important bits of the TCP and ICSK socket structures is saved,
but I think there is still some additional IPv6 stuff that needs to be
handled.
With this patch applied, the following script can be used to demonstrate
the functionality:
https://lists.linux-foundation.org/pipermail/containers/2009-October/021239.html
It shows that this enables migration of a sendmail process with open
connections from one machine to another without dropping.
We probably need comments from the netdev people about the quality of
sanity checking we do on the values in the ckpt_hdr_socket_inet
structure on restart.
Note that this still doesn't address lingering sockets yet.
Changes in v3:
- Prevent restart from allowing a bind on a <1024 port unless the
user is granted that capability
- Add some sanity checking in the inet_precheck() function to make sure
the values read from the checkpoint image are within acceptable ranges
- Check the result of sock_restore_header_info() and fail if needed
Changes in v2:
- Restore saddr, rcv_saddr, daddr, sport, and dport from the sockaddr
structure instead of saving them separately
- Fix 'sock' naming in sock_cptrst()
- Don't take the queue lock before skb_queue_tail() since it is
done for us
- Allow "listen only" restore behavior if RESTART_SOCK_LISTENONLY
flag is specified on sys_restart()
- Pull the implementation of the list of listening sockets back into
this patch
- Fix dangling printk
- Add some comments around the parent/child restore logic
Cc: netdev@vger.kernel.org
Cc: Oren Laadan <orenl@librato.com>
Cc: John Dykstra <jdykstra72@gmail.com>
Signed-off-by: Dan Smith <danms@us.ibm.com>
---
checkpoint/sys.c | 4 +
include/linux/checkpoint.h | 5 +-
include/linux/checkpoint_hdr.h | 95 ++++++++++
include/linux/checkpoint_types.h | 2 +
net/checkpoint.c | 23 ++--
net/ipv4/checkpoint.c | 349 +++++++++++++++++++++++++++++++++++++-
6 files changed, 463 insertions(+), 15 deletions(-)
diff --git a/checkpoint/sys.c b/checkpoint/sys.c
index 260a1ee..df00973 100644
--- a/checkpoint/sys.c
+++ b/checkpoint/sys.c
@@ -221,6 +221,8 @@ static void ckpt_ctx_free(struct ckpt_ctx *ctx)
kfree(ctx->pids_arr);
+ sock_listening_list_free(&ctx->listen_sockets);
+
kfree(ctx);
}
@@ -249,6 +251,8 @@ static struct ckpt_ctx *ckpt_ctx_alloc(int fd, unsigned long uflags,
spin_lock_init(&ctx->lock);
#endif
+ INIT_LIST_HEAD(&ctx->listen_sockets);
+
err = -EBADF;
ctx->file = fget(fd);
if (!ctx->file)
diff --git a/include/linux/checkpoint.h b/include/linux/checkpoint.h
index c2832ac..8702307 100644
--- a/include/linux/checkpoint.h
+++ b/include/linux/checkpoint.h
@@ -19,6 +19,7 @@
#define RESTART_TASKSELF 0x1
#define RESTART_FROZEN 0x2
#define RESTART_GHOST 0x4
+#define RESTART_SOCK_LISTENONLY 0x8
#ifdef __KERNEL__
#ifdef CONFIG_CHECKPOINT
@@ -48,7 +49,8 @@
#define RESTART_USER_FLAGS \
(RESTART_TASKSELF | \
RESTART_FROZEN | \
- RESTART_GHOST)
+ RESTART_GHOST | \
+ RESTART_SOCK_LISTENONLY)
extern int walk_task_subtree(struct task_struct *task,
int (*func)(struct task_struct *, void *),
@@ -102,6 +104,7 @@ extern int ckpt_sock_getnames(struct ckpt_ctx *ctx,
struct sockaddr *rem, unsigned *rem_len);
int sock_restore_header_info(struct sk_buff *skb,
struct ckpt_hdr_socket_buffer *h);
+void sock_listening_list_free(struct list_head *head);
/* ckpt kflags */
#define ckpt_set_ctx_kflag(__ctx, __kflag) \
diff --git a/include/linux/checkpoint_hdr.h b/include/linux/checkpoint_hdr.h
index 3e6cab1..e0f6d25 100644
--- a/include/linux/checkpoint_hdr.h
+++ b/include/linux/checkpoint_hdr.h
@@ -20,6 +20,7 @@
#include <linux/socket.h>
#include <linux/un.h>
#include <linux/in.h>
+#include <linux/in6.h>
#else
#include <sys/socket.h>
#include <sys/un.h>
@@ -569,6 +570,100 @@ struct ckpt_hdr_socket_unix {
struct ckpt_hdr_socket_inet {
struct ckpt_hdr h;
+ __u32 daddr;
+ __u32 rcv_saddr;
+ __u32 saddr;
+ __u16 dport;
+ __u16 num;
+ __u16 sport;
+ __s16 uc_ttl;
+ __u16 cmsg_flags;
+
+ struct {
+ __u64 timeout;
+ __u32 ato;
+ __u32 lrcvtime;
+ __u16 last_seg_size;
+ __u16 rcv_mss;
+ __u8 pending;
+ __u8 quick;
+ __u8 pingpong;
+ __u8 blocked;
+ } icsk_ack __attribute__ ((aligned(8)));
+
+ /* FIXME: Skipped opt, tos, multicast, cork settings */
+
+ struct {
+ __u32 rcv_nxt;
+ __u32 copied_seq;
+ __u32 rcv_wup;
+ __u32 snd_nxt;
+ __u32 snd_una;
+ __u32 snd_sml;
+ __u32 rcv_tstamp;
+ __u32 lsndtime;
+
+ __u32 snd_wl1;
+ __u32 snd_wnd;
+ __u32 max_window;
+ __u32 mss_cache;
+ __u32 window_clamp;
+ __u32 rcv_ssthresh;
+ __u32 frto_highmark;
+
+ __u32 srtt;
+ __u32 mdev;
+ __u32 mdev_max;
+ __u32 rttvar;
+ __u32 rtt_seq;
+
+ __u32 packets_out;
+ __u32 retrans_out;
+
+ __u32 snd_up;
+ __u32 rcv_wnd;
+ __u32 write_seq;
+ __u32 pushed_seq;
+ __u32 lost_out;
+ __u32 sacked_out;
+ __u32 fackets_out;
+ __u32 tso_deferred;
+ __u32 bytes_acked;
+
+ __s32 lost_cnt_hint;
+ __u32 retransmit_high;
+
+ __u32 lost_retrans_low;
+
+ __u32 prior_ssthresh;
+ __u32 high_seq;
+
+ __u32 retrans_stamp;
+ __u32 undo_marker;
+ __s32 undo_retrans;
+ __u32 total_retrans;
+
+ __u32 urg_seq;
+ __u32 keepalive_time;
+ __u32 keepalive_intvl;
+
+ __u16 urg_data;
+ __u16 advmss;
+ __u8 frto_counter;
+ __u8 nonagle;
+
+ __u8 ecn_flags;
+ __u8 reordering;
+
+ __u8 keepalive_probes;
+ } tcp __attribute__ ((aligned(8)));
+
+ struct {
+ struct in6_addr saddr;
+ struct in6_addr rcv_saddr;
+ struct in6_addr daddr;
+ } inet6 __attribute__ ((aligned(8)));
+
__u32 laddr_len;
__u32 raddr_len;
struct sockaddr_in laddr;
diff --git a/include/linux/checkpoint_types.h b/include/linux/checkpoint_types.h
index fa57cdc..91c141b 100644
--- a/include/linux/checkpoint_types.h
+++ b/include/linux/checkpoint_types.h
@@ -65,6 +65,8 @@ struct ckpt_ctx {
struct list_head pgarr_list; /* page array to dump VMA contents */
struct list_head pgarr_pool; /* pool of empty page arrays chain */
+ struct list_head listen_sockets;/* listening parent sockets */
+
/* [multi-process checkpoint] */
struct task_struct **tasks_arr; /* array of all tasks [checkpoint] */
int nr_tasks; /* size of tasks array */
diff --git a/net/checkpoint.c b/net/checkpoint.c
index 50baea9..98ba083 100644
--- a/net/checkpoint.c
+++ b/net/checkpoint.c
@@ -134,6 +134,7 @@ int sock_restore_header_info(struct sk_buff *skb,
static int __sock_write_buffers(struct ckpt_ctx *ctx,
struct sk_buff_head *queue,
+ uint16_t family,
int dst_objref)
{
struct sk_buff *skb;
@@ -142,11 +143,7 @@ static int __sock_write_buffers(struct ckpt_ctx *ctx,
struct ckpt_hdr_socket_buffer *h;
int ret = 0;
- /* FIXME: This could be a false positive for non-unix
- * buffers, so add a type check here in the
- * future
- */
- if (UNIXCB(skb).fp) {
+ if ((family == AF_UNIX) && UNIXCB(skb).fp) {
ckpt_write_err(ctx, "TE", "af_unix: pass fd", -EBUSY);
return -EBUSY;
}
@@ -186,6 +183,7 @@ static int __sock_write_buffers(struct ckpt_ctx *ctx,
static int sock_write_buffers(struct ckpt_ctx *ctx,
struct sk_buff_head *queue,
+ uint16_t family,
int dst_objref)
{
struct ckpt_hdr_socket_queue *h;
@@ -205,7 +203,7 @@ static int sock_write_buffers(struct ckpt_ctx *ctx,
h->skb_count = ret;
ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) h);
if (!ret)
- ret = __sock_write_buffers(ctx, &tmpq, dst_objref);
+ ret = __sock_write_buffers(ctx, &tmpq, family, dst_objref);
out:
ckpt_hdr_put(ctx, h);
@@ -227,12 +225,14 @@ int sock_deferred_write_buffers(void *data)
return dst_objref;
}
- ret = sock_write_buffers(ctx, &dq->sk->sk_receive_queue, dst_objref);
+ ret = sock_write_buffers(ctx, &dq->sk->sk_receive_queue,
+ dq->sk->sk_family, dst_objref);
ckpt_debug("write recv buffers: %i\n", ret);
if (ret < 0)
return ret;
- ret = sock_write_buffers(ctx, &dq->sk->sk_write_queue, dst_objref);
+ ret = sock_write_buffers(ctx, &dq->sk->sk_write_queue,
+ dq->sk->sk_family, dst_objref);
ckpt_debug("write send buffers: %i\n", ret);
return ret;
@@ -757,10 +757,9 @@ struct sock *do_sock_restore(struct ckpt_ctx *ctx)
goto err;
if ((h->sock_common.family == AF_INET) &&
- (h->sock.state != TCP_LISTEN)) {
- /* Temporary hack to enable restore of TCP_LISTEN sockets
- * while forcing anything else to a closed state
- */
+ (h->sock.state != TCP_LISTEN) &&
+ (ctx->uflags & RESTART_SOCK_LISTENONLY)) {
+ ckpt_debug("Forcing open socket closed\n");
sock->sk->sk_state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
}
diff --git a/net/ipv4/checkpoint.c b/net/ipv4/checkpoint.c
index 9cbbf5e..671014b 100644
--- a/net/ipv4/checkpoint.c
+++ b/net/ipv4/checkpoint.c
@@ -17,6 +17,7 @@
#include <linux/deferqueue.h>
#include <net/tcp_states.h>
#include <net/tcp.h>
+#include <net/ipv6.h>
struct dq_sock {
struct ckpt_ctx *ctx;
@@ -28,6 +29,233 @@ struct dq_buffers {
struct sock *sk;
};
+struct listen_item {
+ struct sock *sk;
+ struct list_head list;
+};
+
+void sock_listening_list_free(struct list_head *head)
+{
+ struct listen_item *item, *tmp;
+
+ list_for_each_entry_safe(item, tmp, head, list) {
+ list_del(&item->list);
+ kfree(item);
+ }
+}
+
+static int sock_listening_list_add(struct ckpt_ctx *ctx, struct sock *sk)
+{
+ struct listen_item *item;
+
+ item = kmalloc(sizeof(*item), GFP_KERNEL);
+ if (!item)
+ return -ENOMEM;
+
+ item->sk = sk;
+ list_add(&item->list, &ctx->listen_sockets);
+
+ return 0;
+}
+
+static struct sock *sock_get_parent(struct ckpt_ctx *ctx, struct sock *sk)
+{
+ struct listen_item *item;
+
+ list_for_each_entry(item, &ctx->listen_sockets, list) {
+ if (inet_sk(sk)->sport == inet_sk(item->sk)->sport)
+ return item->sk;
+ }
+
+ return NULL;
+}
+
+static int sock_hash_parent(void *data)
+{
+ struct dq_sock *dq = (struct dq_sock *)data;
+ struct sock *parent;
+
+ ckpt_debug("INET post-restart hash\n");
+
+ dq->sk->sk_prot->hash(dq->sk);
+
+ /* If there is a listening socket with the same source port,
+ * then become a child of that socket [we are the result of an
+ * accept()]. Otherwise hash ourselves directly in [we are
+ * the result of a connect()]
+ */
+
+ parent = sock_get_parent(dq->ctx, dq->sk);
+ if (parent) {
+ inet_sk(dq->sk)->num = ntohs(inet_sk(dq->sk)->sport);
+ local_bh_disable();
+ __inet_inherit_port(parent, dq->sk);
+ local_bh_enable();
+ } else {
+ inet_sk(dq->sk)->num = 0;
+ inet_hash_connect(&tcp_death_row, dq->sk);
+ inet_sk(dq->sk)->num = ntohs(inet_sk(dq->sk)->sport);
+ }
+
+ return 0;
+}
+
+static int sock_defer_hash(struct ckpt_ctx *ctx, struct sock *sock)
+{
+ struct dq_sock dq;
+
+ dq.sk = sock;
+ dq.ctx = ctx;
+
+ return deferqueue_add(ctx->deferqueue, &dq, sizeof(dq),
+ sock_hash_parent, NULL);
+}
+
+static int sock_inet_tcp_cptrst(struct ckpt_ctx *ctx,
+ struct tcp_sock *sk,
+ struct ckpt_hdr_socket_inet *hh,
+ int op)
+{
+ CKPT_COPY(op, hh->tcp.rcv_nxt, sk->rcv_nxt);
+ CKPT_COPY(op, hh->tcp.copied_seq, sk->copied_seq);
+ CKPT_COPY(op, hh->tcp.rcv_wup, sk->rcv_wup);
+ CKPT_COPY(op, hh->tcp.snd_nxt, sk->snd_nxt);
+ CKPT_COPY(op, hh->tcp.snd_una, sk->snd_una);
+ CKPT_COPY(op, hh->tcp.snd_sml, sk->snd_sml);
+ CKPT_COPY(op, hh->tcp.rcv_tstamp, sk->rcv_tstamp);
+ CKPT_COPY(op, hh->tcp.lsndtime, sk->lsndtime);
+
+ CKPT_COPY(op, hh->tcp.snd_wl1, sk->snd_wl1);
+ CKPT_COPY(op, hh->tcp.snd_wnd, sk->snd_wnd);
+ CKPT_COPY(op, hh->tcp.max_window, sk->max_window);
+ CKPT_COPY(op, hh->tcp.mss_cache, sk->mss_cache);
+ CKPT_COPY(op, hh->tcp.window_clamp, sk->window_clamp);
+ CKPT_COPY(op, hh->tcp.rcv_ssthresh, sk->rcv_ssthresh);
+ CKPT_COPY(op, hh->tcp.frto_highmark, sk->frto_highmark);
+ CKPT_COPY(op, hh->tcp.advmss, sk->advmss);
+ CKPT_COPY(op, hh->tcp.frto_counter, sk->frto_counter);
+ CKPT_COPY(op, hh->tcp.nonagle, sk->nonagle);
+
+ CKPT_COPY(op, hh->tcp.srtt, sk->srtt);
+ CKPT_COPY(op, hh->tcp.mdev, sk->mdev);
+ CKPT_COPY(op, hh->tcp.mdev_max, sk->mdev_max);
+ CKPT_COPY(op, hh->tcp.rttvar, sk->rttvar);
+ CKPT_COPY(op, hh->tcp.rtt_seq, sk->rtt_seq);
+
+ CKPT_COPY(op, hh->tcp.packets_out, sk->packets_out);
+ CKPT_COPY(op, hh->tcp.retrans_out, sk->retrans_out);
+
+ CKPT_COPY(op, hh->tcp.urg_data, sk->urg_data);
+ CKPT_COPY(op, hh->tcp.ecn_flags, sk->ecn_flags);
+ CKPT_COPY(op, hh->tcp.reordering, sk->reordering);
+ CKPT_COPY(op, hh->tcp.snd_up, sk->snd_up);
+
+ CKPT_COPY(op, hh->tcp.keepalive_probes, sk->keepalive_probes);
+
+ CKPT_COPY(op, hh->tcp.rcv_wnd, sk->rcv_wnd);
+ CKPT_COPY(op, hh->tcp.write_seq, sk->write_seq);
+ CKPT_COPY(op, hh->tcp.pushed_seq, sk->pushed_seq);
+ CKPT_COPY(op, hh->tcp.lost_out, sk->lost_out);
+ CKPT_COPY(op, hh->tcp.sacked_out, sk->sacked_out);
+ CKPT_COPY(op, hh->tcp.fackets_out, sk->fackets_out);
+ CKPT_COPY(op, hh->tcp.tso_deferred, sk->tso_deferred);
+ CKPT_COPY(op, hh->tcp.bytes_acked, sk->bytes_acked);
+
+ CKPT_COPY(op, hh->tcp.lost_cnt_hint, sk->lost_cnt_hint);
+ CKPT_COPY(op, hh->tcp.retransmit_high, sk->retransmit_high);
+
+ CKPT_COPY(op, hh->tcp.lost_retrans_low, sk->lost_retrans_low);
+
+ CKPT_COPY(op, hh->tcp.prior_ssthresh, sk->prior_ssthresh);
+ CKPT_COPY(op, hh->tcp.high_seq, sk->high_seq);
+
+ CKPT_COPY(op, hh->tcp.retrans_stamp, sk->retrans_stamp);
+ CKPT_COPY(op, hh->tcp.undo_marker, sk->undo_marker);
+ CKPT_COPY(op, hh->tcp.undo_retrans, sk->undo_retrans);
+ CKPT_COPY(op, hh->tcp.total_retrans, sk->total_retrans);
+
+ CKPT_COPY(op, hh->tcp.urg_seq, sk->urg_seq);
+ CKPT_COPY(op, hh->tcp.keepalive_time, sk->keepalive_time);
+ CKPT_COPY(op, hh->tcp.keepalive_intvl, sk->keepalive_intvl);
+
+ return 0;
+}
+
+static int sock_inet_restore_addrs(struct inet_sock *inet,
+ struct ckpt_hdr_socket_inet *hh)
+{
+ inet->daddr = hh->raddr.sin_addr.s_addr;
+ inet->saddr = hh->laddr.sin_addr.s_addr;
+ inet->rcv_saddr = inet->saddr;
+
+ inet->dport = hh->raddr.sin_port;
+ inet->sport = hh->laddr.sin_port;
+
+ return 0;
+}
+
+static int sock_inet_cptrst(struct ckpt_ctx *ctx,
+ struct sock *sk,
+ struct ckpt_hdr_socket_inet *hh,
+ int op)
+{
+ struct inet_sock *inet = inet_sk(sk);
+ struct inet_connection_sock *icsk = inet_csk(sk);
+ int ret;
+
+ if (op == CKPT_CPT) {
+ CKPT_COPY(op, hh->daddr, inet->daddr);
+ CKPT_COPY(op, hh->rcv_saddr, inet->rcv_saddr);
+ CKPT_COPY(op, hh->dport, inet->dport);
+ CKPT_COPY(op, hh->saddr, inet->saddr);
+ CKPT_COPY(op, hh->sport, inet->sport);
+ } else {
+ ret = sock_inet_restore_addrs(inet, hh);
+ if (ret)
+ return ret;
+ }
+
+ CKPT_COPY(op, hh->num, inet->num);
+ CKPT_COPY(op, hh->uc_ttl, inet->uc_ttl);
+ CKPT_COPY(op, hh->cmsg_flags, inet->cmsg_flags);
+
+ CKPT_COPY(op, hh->icsk_ack.pending, icsk->icsk_ack.pending);
+ CKPT_COPY(op, hh->icsk_ack.quick, icsk->icsk_ack.quick);
+ CKPT_COPY(op, hh->icsk_ack.pingpong, icsk->icsk_ack.pingpong);
+ CKPT_COPY(op, hh->icsk_ack.blocked, icsk->icsk_ack.blocked);
+ CKPT_COPY(op, hh->icsk_ack.ato, icsk->icsk_ack.ato);
+ CKPT_COPY(op, hh->icsk_ack.timeout, icsk->icsk_ack.timeout);
+ CKPT_COPY(op, hh->icsk_ack.lrcvtime, icsk->icsk_ack.lrcvtime);
+ CKPT_COPY(op,
+ hh->icsk_ack.last_seg_size, icsk->icsk_ack.last_seg_size);
+ CKPT_COPY(op, hh->icsk_ack.rcv_mss, icsk->icsk_ack.rcv_mss);
+
+ if (sk->sk_protocol == IPPROTO_TCP)
+ ret = sock_inet_tcp_cptrst(ctx, tcp_sk(sk), hh, op);
+ else if (sk->sk_protocol == IPPROTO_UDP)
+ ret = 0;
+ else {
+ ckpt_write_err(ctx, "T", "unknown socket protocol %d",
+ sk->sk_protocol);
+ ret = -EINVAL;
+ }
+
+ if (sk->sk_family == AF_INET6) {
+ struct ipv6_pinfo *inet6 = inet6_sk(sk);
+ if (op == CKPT_CPT) {
+ ipv6_addr_copy(&hh->inet6.saddr, &inet6->saddr);
+ ipv6_addr_copy(&hh->inet6.rcv_saddr, &inet6->rcv_saddr);
+ ipv6_addr_copy(&hh->inet6.daddr, &inet6->daddr);
+ } else {
+ ipv6_addr_copy(&inet6->saddr, &hh->inet6.saddr);
+ ipv6_addr_copy(&inet6->rcv_saddr, &hh->inet6.rcv_saddr);
+ ipv6_addr_copy(&inet6->daddr, &hh->inet6.daddr);
+ }
+ }
+
+ return ret;
+}
+
int inet_checkpoint(struct ckpt_ctx *ctx, struct socket *sock)
{
struct ckpt_hdr_socket_inet *in;
@@ -43,6 +271,10 @@ int inet_checkpoint(struct ckpt_ctx *ctx, struct socket *sock)
if (ret)
goto out;
+ ret = sock_inet_cptrst(ctx, sock->sk, in, CKPT_CPT);
+ if (ret < 0)
+ goto out;
+
ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) in);
out:
ckpt_hdr_put(ctx, in);
@@ -87,9 +319,11 @@ static int inet_read_buffer(struct ckpt_ctx *ctx, struct sk_buff_head *queue)
if (ret < 0)
goto out;
- spin_lock(&queue->lock);
+ ret = sock_restore_header_info(skb, h);
+ if (!ret)
+ goto out;
+
skb_queue_tail(queue, skb);
- spin_unlock(&queue->lock);
out:
ckpt_hdr_put(ctx, h);
@@ -162,6 +396,19 @@ static int inet_defer_restore_buffers(struct ckpt_ctx *ctx, struct sock *sk)
static int inet_precheck(struct socket *sock, struct ckpt_hdr_socket_inet *in)
{
+ __u8 icsk_ack_mask = ICSK_ACK_SCHED | ICSK_ACK_TIMER |
+ ICSK_ACK_PUSHED | ICSK_ACK_PUSHED2;
+ __u16 urg_mask = TCP_URG_VALID | TCP_URG_NOTYET | TCP_URG_READ;
+ __u8 nonagle_mask = TCP_NAGLE_OFF | TCP_NAGLE_CORK | TCP_NAGLE_PUSH;
+ __u8 ecn_mask = TCP_ECN_OK | TCP_ECN_QUEUE_CWR | TCP_ECN_DEMAND_CWR;
+
+ if ((htons(in->laddr.sin_port) < PROT_SOCK) &&
+ !capable(CAP_NET_BIND_SERVICE)) {
+ ckpt_debug("unable to bind to port %hu\n",
+ htons(in->laddr.sin_port));
+ return -EINVAL;
+ }
+
if (in->laddr_len > sizeof(struct sockaddr_in)) {
ckpt_debug("laddr_len is too big\n");
return -EINVAL;
@@ -172,6 +419,77 @@ static int inet_precheck(struct socket *sock, struct ckpt_hdr_socket_inet *in)
return -EINVAL;
}
+ /* Set ato to the default */
+ in->icsk_ack.ato = TCP_ATO_MIN;
+
+ /* No quick acks are scheduled after a restart */
+ in->icsk_ack.quick = 0;
+
+ if (in->icsk_ack.pending & ~icsk_ack_mask) {
+ ckpt_debug("invalid pending flags 0x%x\n",
+ in->icsk_ack.pending & ~icsk_ack_mask);
+ return -EINVAL;
+ }
+
+ if (in->icsk_ack.pingpong > 1) {
+ ckpt_debug("invalid icsk_ack.pingpong value\n");
+ return -EINVAL;
+ }
+
+ if (in->icsk_ack.blocked > 1) {
+ ckpt_debug("invalid icsk_ack.blocked value\n");
+ return -EINVAL;
+ }
+
+ /* do_tcp_setsockopt() quietly makes this coercion */
+ if (in->tcp.window_clamp < (SOCK_MIN_RCVBUF / 2))
+ in->tcp.window_clamp = SOCK_MIN_RCVBUF / 2;
+ else if (in->tcp.window_clamp > 65535U) {
+ ckpt_debug("invalid window_clamp value\n");
+ return -EINVAL;
+ }
+
+ if (in->tcp.rcv_ssthresh > (4U * in->tcp.advmss))
+ in->tcp.rcv_ssthresh = 4U * in->tcp.advmss;
+
+ /* These will all be recalculated on the next call to
+ * tcp_rtt_estimator()
+ */
+ in->tcp.srtt = in->tcp.mdev = in->tcp.mdev_max = 0;
+ in->tcp.rttvar = in->tcp.rtt_seq = 0;
+
+ /* Might want to set packets_out to zero ? */
+
+ if (in->tcp.rcv_wnd > MAX_TCP_WINDOW)
+ in->tcp.rcv_wnd = MAX_TCP_WINDOW;
+
+ if (in->tcp.keepalive_intvl > MAX_TCP_KEEPINTVL) {
+ ckpt_debug("keepalive_intvl %i out of range\n",
+ in->tcp.keepalive_intvl);
+ return -EINVAL;
+ }
+
+ if (in->tcp.keepalive_probes > MAX_TCP_KEEPCNT) {
+ ckpt_debug("Invalid keepalive_probes value %i\n",
+ in->tcp.keepalive_probes);
+ return -EINVAL;
+ }
+
+ if (in->tcp.urg_data & ~urg_mask) {
+ ckpt_debug("Invalid urg_data value\n");
+ return -EINVAL;
+ }
+
+ if (in->tcp.nonagle & ~nonagle_mask) {
+ ckpt_debug("Invalid nonagle value\n");
+ return -EINVAL;
+ }
+
+ if (in->tcp.ecn_flags & ~ecn_mask) {
+ ckpt_debug("Invalid ecn_flags value\n");
+ return -EINVAL;
+ }
+
return 0;
}
@@ -209,8 +527,35 @@ int inet_restore(struct ckpt_ctx *ctx,
ckpt_debug("inet listen: %i\n", ret);
if (ret < 0)
goto out;
+
+ /* We are a listening socket, so add ourselves
+ * to the list of parent sockets. This will
+ * allow our children to find us later and
+ * link up
+ */
+
+ ret = sock_listening_list_add(ctx, sock->sk);
+ if (ret < 0)
+ goto out;
}
} else {
+ ret = sock_inet_cptrst(ctx, sock->sk, in, CKPT_RST);
+ if (ret)
+ goto out;
+
+ if ((h->sock.state == TCP_ESTABLISHED) &&
+ (h->sock.protocol == IPPROTO_TCP)) {
+ /* A connected socket that was spawned from an
+ * accept() needs to be hashed with its parent
+ * listening socket in order to receive
+ * traffic on the original port. Since we may
+ * not have restarted the parent yet, we defer
+ * this until later when we know we have all
+ * the listening sockets accounted for.
+ */
+ ret = sock_defer_hash(ctx, sock->sk);
+ }
+
if (!sock_flag(sock->sk, SOCK_DEAD))
ret = inet_defer_restore_buffers(ctx, sock->sk);
}
--
1.6.2.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox