Skip to content

Commit d8f9cc3

Browse files
Jack Morgensteinjgunthorpe
authored andcommitted
IB/mlx4: Mark user MR as writable if actual virtual memory is writable
To allow rereg_user_mr to modify the MR from read-only to writable without using get_user_pages again, we needed to define the initial MR as writable. However, this was originally done unconditionally, without taking into account the writability of the underlying virtual memory. As a result, any attempt to register a read-only MR over read-only virtual memory failed. To fix this, do not add the writable flag bit when the user virtual memory is not writable (e.g. const memory). However, when the underlying memory is NOT writable (and we therefore do not define the initial MR as writable), the IB core adds a "force writable" flag to its user-pages request. If this succeeds, the reg_user_mr caller gets a writable copy of the original pages. If the user-space caller then does a rereg_user_mr operation to enable writability, this will succeed. This should not be allowed, since the original virtual memory was not writable. Cc: <[email protected]> Fixes: 9376932 ("IB/mlx4_ib: Add support for user MR re-registration") Signed-off-by: Jason Gunthorpe <[email protected]> Signed-off-by: Jack Morgenstein <[email protected]> Signed-off-by: Leon Romanovsky <[email protected]>
1 parent 08bb558 commit d8f9cc3

File tree

1 file changed

+42
-8
lines changed
  • drivers/infiniband/hw/mlx4

1 file changed

+42
-8
lines changed

drivers/infiniband/hw/mlx4/mr.c

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,40 @@ int mlx4_ib_umem_calc_optimal_mtt_size(struct ib_umem *umem, u64 start_va,
367367
return block_shift;
368368
}
369369

370+
static struct ib_umem *mlx4_get_umem_mr(struct ib_ucontext *context, u64 start,
371+
u64 length, u64 virt_addr,
372+
int access_flags)
373+
{
374+
/*
375+
* Force registering the memory as writable if the underlying pages
376+
* are writable. This is so rereg can change the access permissions
377+
* from readable to writable without having to run through ib_umem_get
378+
* again
379+
*/
380+
if (!ib_access_writable(access_flags)) {
381+
struct vm_area_struct *vma;
382+
383+
down_read(&current->mm->mmap_sem);
384+
/*
385+
* FIXME: Ideally this would iterate over all the vmas that
386+
* cover the memory, but for now it requires a single vma to
387+
* entirely cover the MR to support RO mappings.
388+
*/
389+
vma = find_vma(current->mm, start);
390+
if (vma && vma->vm_end >= start + length &&
391+
vma->vm_start <= start) {
392+
if (vma->vm_flags & VM_WRITE)
393+
access_flags |= IB_ACCESS_LOCAL_WRITE;
394+
} else {
395+
access_flags |= IB_ACCESS_LOCAL_WRITE;
396+
}
397+
398+
up_read(&current->mm->mmap_sem);
399+
}
400+
401+
return ib_umem_get(context, start, length, access_flags, 0);
402+
}
403+
370404
struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
371405
u64 virt_addr, int access_flags,
372406
struct ib_udata *udata)
@@ -381,10 +415,8 @@ struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
381415
if (!mr)
382416
return ERR_PTR(-ENOMEM);
383417

384-
/* Force registering the memory as writable. */
385-
/* Used for memory re-registeration. HCA protects the access */
386-
mr->umem = ib_umem_get(pd->uobject->context, start, length,
387-
access_flags | IB_ACCESS_LOCAL_WRITE, 0);
418+
mr->umem = mlx4_get_umem_mr(pd->uobject->context, start, length,
419+
virt_addr, access_flags);
388420
if (IS_ERR(mr->umem)) {
389421
err = PTR_ERR(mr->umem);
390422
goto err_free;
@@ -454,6 +486,9 @@ int mlx4_ib_rereg_user_mr(struct ib_mr *mr, int flags,
454486
}
455487

456488
if (flags & IB_MR_REREG_ACCESS) {
489+
if (ib_access_writable(mr_access_flags) && !mmr->umem->writable)
490+
return -EPERM;
491+
457492
err = mlx4_mr_hw_change_access(dev->dev, *pmpt_entry,
458493
convert_access(mr_access_flags));
459494

@@ -467,10 +502,9 @@ int mlx4_ib_rereg_user_mr(struct ib_mr *mr, int flags,
467502

468503
mlx4_mr_rereg_mem_cleanup(dev->dev, &mmr->mmr);
469504
ib_umem_release(mmr->umem);
470-
mmr->umem = ib_umem_get(mr->uobject->context, start, length,
471-
mr_access_flags |
472-
IB_ACCESS_LOCAL_WRITE,
473-
0);
505+
mmr->umem =
506+
mlx4_get_umem_mr(mr->uobject->context, start, length,
507+
virt_addr, mr_access_flags);
474508
if (IS_ERR(mmr->umem)) {
475509
err = PTR_ERR(mmr->umem);
476510
/* Prevent mlx4_ib_dereg_mr from free'ing invalid pointer */

0 commit comments

Comments
 (0)