spin_lock_irqsave(&rds_cong_lock, flags);
list_for_each_entry(conn, &map->m_conn_list, c_map_item) {
- if (!test_and_set_bit(0, &conn->c_map_queued)) {
+ if (!test_and_set_bit(RCMQ_BITOFF_CONGU_PENDING,
+ &conn->c_map_queued)) {
rds_stats_inc(s_cong_update_queued);
queue_delayed_work(conn->c_path[0].cp_wq,
&conn->c_path[0].cp_send_w, 0);
if (rds_conn_up(conn) &&
(!test_bit(RDS_LL_SEND_FULL, &conn->c_flags) ||
- test_bit(0, &conn->c_map_queued)))
+ test_bit(RCMQ_BITOFF_CONGU_PENDING, &conn->c_map_queued)))
rds_send_xmit(&ic->conn->c_path[0]);
}
uint64_t uncongested = 0;
void *addr;
+ map = conn->c_fcong;
+
/* catch completely corrupt packets */
- if (be32_to_cpu(ibinc->ii_inc.i_hdr.h_len) != RDS_CONG_MAP_BYTES)
+ if (be32_to_cpu(ibinc->ii_inc.i_hdr.h_len) != RDS_CONG_MAP_BYTES) {
+ pr_warn_ratelimited("RDS: received corrupt congestion update, expected header length: %d, received header length: %d on conn %p <%pI6c, %pI6c, %d> remote map %p remote IP %pI6c\n",
+ RDS_CONG_MAP_BYTES,
+ be32_to_cpu(ibinc->ii_inc.i_hdr.h_len),
+ conn, &conn->c_laddr, &conn->c_faddr,
+ conn->c_tos, map, &map->m_addr);
return;
+ }
- map = conn->c_fcong;
map_page = 0;
map_off = 0;
struct rds_cong_map *c_fcong;
struct list_head c_map_item;
+
+ /* c_map_queued: bit map field */
unsigned long c_map_queued;
+ /** bit 0: set indicates congestion update
+ * pending to send to peer.
+ * bit 1: set indicates last alloc attempt(GFP_NOWAIT)
+ * for congestion update message failed
+ * and update was deferred
+ */
+#define RCMQ_BITOFF_CONGU_PENDING 0
+#define RCMQ_BITOFF_CONGU_ALLOC_DEFER 1
+
/* Protocol version */
unsigned int c_proposed_version;
unsigned int c_version;
}
/*
- * If between sending messages, we can send a pending congestion
- * map update.
+ * If between sending messages, we can send a pending
+ * congestion map update.
*/
- if (!rm && test_and_clear_bit(0, &conn->c_map_queued)) {
+ if (!rm && test_bit(RCMQ_BITOFF_CONGU_PENDING,
+ &conn->c_map_queued)) {
rm = rds_cong_update_alloc(conn);
if (IS_ERR(rm)) {
+ pr_warn_ratelimited("RDS: Congestion update allocation deferred: conn %p<%pI6c, %pI6c, %d>\n",
+ conn, &conn->c_laddr,
+ &conn->c_faddr,
+ conn->c_tos);
+ /* Set bit to mark deferred cong update */
+ set_bit(RCMQ_BITOFF_CONGU_ALLOC_DEFER,
+ &conn->c_map_queued);
ret = PTR_ERR(rm);
+
+ /** Note: pending congestion update
+ * remains set!
+ */
break;
}
rm->data.op_active = 1;
rm->m_inc.i_conn = cp->cp_conn;
cp->cp_xmit_rm = rm;
+
+ /* clear deferred alloc if set */
+ if (test_and_clear_bit(RCMQ_BITOFF_CONGU_ALLOC_DEFER,
+ &conn->c_map_queued)) {
+ pr_warn_ratelimited("RDS: Deferred congestion update allocated: conn %p<%pI6c, %pI6c, %d>\n",
+ conn, &conn->c_laddr,
+ &conn->c_faddr,
+ conn->c_tos);
+ }
+
+ /* clear pending congestion update */
+ clear_bit(RCMQ_BITOFF_CONGU_PENDING,
+ &conn->c_map_queued);
}
/*
* We have an extra generation check here so that if someone manages
* to jump in after our release_in_xmit, we'll see that they have done
* some work and we will skip our goto
+ *
+ * (Note: We check not just for more messages on send queue but also
+ * for congestion update that might still be pending if GFP_NOWAIT
+ * allocation failed earlier. Retrying for it in this call will also
+ * be capped at "send_batch_count" attempts as it is for data messages
+ * before getting rescheduled.)
*/
if (ret == 0) {
bool raced;
smp_mb();
raced = send_gen != READ_ONCE(cp->cp_send_gen);
- if ((test_bit(0, &conn->c_map_queued) ||
- !list_empty(&cp->cp_send_queue)) && !raced) {
+ if ((test_bit(RCMQ_BITOFF_CONGU_PENDING,
+ &conn->c_map_queued) ||
+ !list_empty(&cp->cp_send_queue)) && !raced) {
if (batch_count < send_batch_count)
goto restart;
queue_delayed_work(cp->cp_wq, &cp->cp_send_w, 1);
conn, &conn->c_laddr, &conn->c_faddr, conn->c_tos);
cp->cp_reconnect_jiffies = 0;
- set_bit(0, &conn->c_map_queued);
+ set_bit(RCMQ_BITOFF_CONGU_PENDING, &conn->c_map_queued);
queue_delayed_work(cp->cp_wq, &cp->cp_send_w, 0);
queue_delayed_work(cp->cp_wq, &cp->cp_recv_w, 0);
queue_delayed_work(cp->cp_wq, &cp->cp_hb_w, 0);