RDMA/odp: Check for overflow when computing the umem_odp end
Since the page size can be extended in the ODP case by IB_ACCESS_HUGETLB the existing overflow checks done by ib_umem_get() are not sufficient. Check for overflow again. Further, remove the unchecked math from the inlines and just use the precomputed value stored in the interval_tree_node. Link: https://lore.kernel.org/r/20190819111710.18440-9-leon@kernel.org Signed-off-by: Leon Romanovsky <leonro@mellanox.com> Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
This commit is contained in:
Родитель
0446cad9ca
Коммит
204e3e5630
|
@ -287,19 +287,32 @@ static inline int ib_init_umem_odp(struct ib_umem_odp *umem_odp,
|
|||
|
||||
umem_odp->umem.is_odp = 1;
|
||||
if (!umem_odp->is_implicit_odp) {
|
||||
size_t pages = ib_umem_odp_num_pages(umem_odp);
|
||||
size_t page_size = 1UL << umem_odp->page_shift;
|
||||
size_t pages;
|
||||
|
||||
umem_odp->interval_tree.start =
|
||||
ALIGN_DOWN(umem_odp->umem.address, page_size);
|
||||
if (check_add_overflow(umem_odp->umem.address,
|
||||
umem_odp->umem.length,
|
||||
&umem_odp->interval_tree.last))
|
||||
return -EOVERFLOW;
|
||||
umem_odp->interval_tree.last =
|
||||
ALIGN(umem_odp->interval_tree.last, page_size);
|
||||
if (unlikely(umem_odp->interval_tree.last < page_size))
|
||||
return -EOVERFLOW;
|
||||
|
||||
pages = (umem_odp->interval_tree.last -
|
||||
umem_odp->interval_tree.start) >>
|
||||
umem_odp->page_shift;
|
||||
if (!pages)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Note that the representation of the intervals in the
|
||||
* interval tree considers the ending point as contained in
|
||||
* the interval, while the function ib_umem_end returns the
|
||||
* first address which is not contained in the umem.
|
||||
* the interval.
|
||||
*/
|
||||
umem_odp->interval_tree.start = ib_umem_start(umem_odp);
|
||||
umem_odp->interval_tree.last = ib_umem_end(umem_odp) - 1;
|
||||
umem_odp->interval_tree.last--;
|
||||
|
||||
umem_odp->page_list = vzalloc(
|
||||
array_size(sizeof(*umem_odp->page_list), pages));
|
||||
|
|
|
@ -91,14 +91,13 @@ static inline struct ib_umem_odp *to_ib_umem_odp(struct ib_umem *umem)
|
|||
/* Returns the first page of an ODP umem. */
|
||||
static inline unsigned long ib_umem_start(struct ib_umem_odp *umem_odp)
|
||||
{
|
||||
return ALIGN_DOWN(umem_odp->umem.address, 1UL << umem_odp->page_shift);
|
||||
return umem_odp->interval_tree.start;
|
||||
}
|
||||
|
||||
/* Returns the address of the page after the last one of an ODP umem. */
|
||||
static inline unsigned long ib_umem_end(struct ib_umem_odp *umem_odp)
|
||||
{
|
||||
return ALIGN(umem_odp->umem.address + umem_odp->umem.length,
|
||||
1UL << umem_odp->page_shift);
|
||||
return umem_odp->interval_tree.last + 1;
|
||||
}
|
||||
|
||||
static inline size_t ib_umem_odp_num_pages(struct ib_umem_odp *umem_odp)
|
||||
|
|
Загрузка…
Ссылка в новой задаче