From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3CE86C11F69 for ; Tue, 29 Jun 2021 08:40:20 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 21F1C61DBA for ; Tue, 29 Jun 2021 08:40:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232604AbhF2Imo (ORCPT ); Tue, 29 Jun 2021 04:42:44 -0400 Received: from mail.kernel.org ([198.145.29.99]:53468 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232572AbhF2Imn (ORCPT ); Tue, 29 Jun 2021 04:42:43 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 55FD961DC8; Tue, 29 Jun 2021 08:40:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1624956017; bh=3W16h0Qhvidbw6bBtrkPf3V2LDrQFbXK3ZE6M+o2jOA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bFtOB5wgziMB+XPuW1ialu+x8Esvk+SRs1GI7KTt+YmudpGimFmDTK+EKQIWik8th tslHjwCFUzchkpLWL0Jf5DgY4Yd5ae+BAK8i3OoM6+59W0e0YFth3sw8F3pe5NGcdP 4KpSaKfhWevBR3+rv8y71tn+CWuzt3FSRJ5g7iW+N4twIbjCSzu5q6ZABD0JRA+tif WFAO1lRKqhkWQvTvAR907aLsmQwIwObolaO8skATqtgeotDI7TrdsdqFBMXDh0l68A +S7YIsQBuk0+8f3smn2pl7WDq8IWw4oIWeY0V5rdHzD34RnjGu1K2lgN9kGx8X/yyG wJkKctdLoIsdg== From: Leon Romanovsky To: Doug Ledford , Jason Gunthorpe Cc: Maor Gottlieb , Dennis Dalessandro , linux-kernel@vger.kernel.org, linux-rdma@vger.kernel.org, Mike Marciniszyn , Yishai Hadas , Zhu Yanjun Subject: [PATCH rdma-next v1 1/2] lib/scatterlist: Fix wrong update of orig_nents Date: Tue, 29 Jun 2021 11:40:01 +0300 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-rdma@vger.kernel.org From: Maor Gottlieb orig_nents should represent the number of entries with pages, but __sg_alloc_table_from_pages sets orig_nents as the number of total entries in the table. This is wrong when the API is used for dynamic allocation where not all the table entries are mapped with pages. It wasn't observed until now, since RDMA umem who uses this API in the dynamic form doesn't use orig_nents implicit or explicit by the scatterlist APIs. Fix it by: 1. Set orig_nents as number of entries with pages also in __sg_alloc_table_from_pages. 2. Add a new field total_nents to reflect the total number of entries in the table. This is required for the release flow (sg_free_table). This filed should be used internally only by scatterlist. Fixes: 07da1223ec93 ("lib/scatterlist: Add support in dynamic allocation of SG table from pages") Signed-off-by: Maor Gottlieb Signed-off-by: Leon Romanovsky --- include/linux/scatterlist.h | 8 ++++++-- lib/scatterlist.c | 32 ++++++++------------------------ 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h index 6f70572b2938..1c889141eb91 100644 --- a/include/linux/scatterlist.h +++ b/include/linux/scatterlist.h @@ -35,8 +35,12 @@ struct scatterlist { struct sg_table { struct scatterlist *sgl; /* the list */ - unsigned int nents; /* number of mapped entries */ - unsigned int orig_nents; /* original size of list */ + unsigned int nents; /* number of DMA mapped entries */ + unsigned int orig_nents; /* number of CPU mapped entries */ + /* The fields below should be used internally only by + * scatterlist implementation. + */ + unsigned int total_nents; /* number of total entries in the table */ }; /* diff --git a/lib/scatterlist.c b/lib/scatterlist.c index a59778946404..6db70a1e7dd0 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c @@ -192,33 +192,26 @@ static void sg_kfree(struct scatterlist *sg, unsigned int nents) void __sg_free_table(struct sg_table *table, unsigned int max_ents, unsigned int nents_first_chunk, sg_free_fn *free_fn) { - struct scatterlist *sgl, *next; + struct scatterlist *sgl, *next = NULL; unsigned curr_max_ents = nents_first_chunk ?: max_ents; if (unlikely(!table->sgl)) return; sgl = table->sgl; - while (table->orig_nents) { - unsigned int alloc_size = table->orig_nents; - unsigned int sg_size; + while (table->total_nents) { + unsigned int alloc_size = table->total_nents; /* * If we have more than max_ents segments left, * then assign 'next' to the sg table after the current one. - * sg_size is then one less than alloc size, since the last - * element is the chain pointer. */ if (alloc_size > curr_max_ents) { next = sg_chain_ptr(&sgl[curr_max_ents - 1]); alloc_size = curr_max_ents; - sg_size = alloc_size - 1; - } else { - sg_size = alloc_size; - next = NULL; } - table->orig_nents -= sg_size; + table->total_nents -= alloc_size; if (nents_first_chunk) nents_first_chunk = 0; else @@ -301,20 +294,11 @@ int __sg_alloc_table(struct sg_table *table, unsigned int nents, } else { sg = alloc_fn(alloc_size, gfp_mask); } - if (unlikely(!sg)) { - /* - * Adjust entry count to reflect that the last - * entry of the previous table won't be used for - * linkage. Without this, sg_kfree() may get - * confused. - */ - if (prv) - table->nents = ++table->orig_nents; - + if (unlikely(!sg)) return -ENOMEM; - } sg_init_table(sg, alloc_size); + table->total_nents += alloc_size; table->nents = table->orig_nents += sg_size; /* @@ -385,12 +369,11 @@ static struct scatterlist *get_next_sg(struct sg_table *table, if (!new_sg) return ERR_PTR(-ENOMEM); sg_init_table(new_sg, alloc_size); + table->total_nents += alloc_size; if (cur) { __sg_chain(next_sg, new_sg); - table->orig_nents += alloc_size - 1; } else { table->sgl = new_sg; - table->orig_nents = alloc_size; table->nents = 0; } return new_sg; @@ -515,6 +498,7 @@ struct scatterlist *__sg_alloc_table_from_pages(struct sg_table *sgt, cur_page = j; } sgt->nents += added_nents; + sgt->orig_nents = sgt->nents; out: if (!left_pages) sg_mark_end(s); -- 2.31.1