From: shamir rabinovitch Date: Wed, 16 Mar 2016 13:57:19 +0000 (-0400) Subject: rds: rds-stress show all zeros after few minutes X-Git-Tag: v4.1.12-92~175^2~2 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=ba6f5276631ab95981b540bbcbf9113e928adc33;p=users%2Fjedix%2Flinux-maple.git rds: rds-stress show all zeros after few minutes Issue can be seen on platforms that use 8K and above page size while rds fragment size is 4K. On those platforms single page is shared between 2 or more rds fragments. Each fragment has it's own offeset and rds cong map code need to take this offset to account. Not taking this offset to account lead to reading the data fragment as congestion map fragment and hang of the rds transmit due to far cong map corruption. Orabug: 23045970 Reviewed-by: Wengang Wang Reviewed-by: Ajaykumar Hotchandani Acked-by: Santosh Shilimkar Tested-by: Anand Bibhuti Signed-off-by: shamir rabinovitch --- diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index cf6b63b0eac7..6eb1b3f795ec 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -1029,7 +1029,7 @@ static void rds_ib_cong_recv(struct rds_connection *conn, addr = kmap_atomic(sg_page(&frag->f_sg)); - src = addr + frag_off; + src = addr + frag->f_sg.offset + frag_off; dst = (void *)map->m_page_addrs[map_page] + map_off; for (k = 0; k < to_copy; k += 8) { /* Record ports that became uncongested, ie diff --git a/net/rds/iw_recv.c b/net/rds/iw_recv.c index ec21cc5b21eb..7da890685c55 100644 --- a/net/rds/iw_recv.c +++ b/net/rds/iw_recv.c @@ -586,7 +586,7 @@ static void rds_iw_cong_recv(struct rds_connection *conn, addr = kmap_atomic(frag->f_page); - src = addr + frag_off; + src = addr + frag->f_offset + frag_off; dst = (void *)map->m_page_addrs[map_page] + map_off; for (k = 0; k < to_copy; k += 8) { /* Record ports that became uncongested, ie diff --git a/net/rds/page.c b/net/rds/page.c index c09f29655dfd..1dae84883291 100644 --- a/net/rds/page.c +++ b/net/rds/page.c @@ -156,8 +156,9 @@ int rds_page_remainder_alloc(struct scatterlist *scat, unsigned long bytes, if (rem->r_offset != 0) rds_stats_inc(s_page_remainder_hit); - rem->r_offset += bytes; - if (rem->r_offset == PAGE_SIZE) { + /* some hw (e.g. sparc) require aligned memory */ + rem->r_offset += ALIGN(bytes, 8); + if (rem->r_offset >= PAGE_SIZE) { __free_page(rem->r_page); rem->r_page = NULL; }