Re: [PATCH 5/8] mm/gup: add FOLL_UNLOCK

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 1/17/23 07:58, Jason Gunthorpe wrote:
> Setting FOLL_UNLOCK allows GUP to lock/unlock the mmap lock on its own. It
> is a more explicit replacement for locked != NULL. This clears the way for
> passing in locked = 1, without intending that the lock can be unlocked.
> 
> Set the flag in all cases where it is used, eg locked is present in the
> external interface or locked is used internally with locked = 0.
> 
> Signed-off-by: Jason Gunthorpe <jgg@xxxxxxxxxx>
> ---
>  include/linux/mm.h |  1 +
>  mm/gup.c           | 31 +++++++++++++++++++------------
>  2 files changed, 20 insertions(+), 12 deletions(-)
> 
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index f3f196e4d66d6f..7496a5c8acede1 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -3089,6 +3089,7 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address,
>  #define FOLL_FAST_ONLY	0x80000	/* gup_fast: prevent fall-back to slow gup */
>  #define FOLL_PCI_P2PDMA	0x100000 /* allow returning PCI P2PDMA pages */
>  #define FOLL_INTERRUPTIBLE  0x200000 /* allow interrupts from generic signals */
> +#define FOLL_UNLOCK	0x400000 /* allow unlocking the mmap lock */

Looks good. Admin note: that this will conflict with commit b5054174ac7c
("mm: move FOLL_* defs to mm_types.h), which is in mm-stable. Because
the FOLL_* items were moved.

Reviewed-by: John Hubbard <jhubbard@xxxxxxxxxx>

thanks,
-- 
John Hubbard
NVIDIA

>  
>  /*
>   * FOLL_PIN and FOLL_LONGTERM may be used in various combinations with each
> diff --git a/mm/gup.c b/mm/gup.c
> index d203e268793b9c..4c360fb05cf3e4 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -896,7 +896,7 @@ static int faultin_page(struct vm_area_struct *vma,
>  		fault_flags |= FAULT_FLAG_WRITE;
>  	if (*flags & FOLL_REMOTE)
>  		fault_flags |= FAULT_FLAG_REMOTE;
> -	if (locked) {
> +	if (*flags & FOLL_UNLOCK) {
>  		fault_flags |= FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
>  		/*
>  		 * FAULT_FLAG_INTERRUPTIBLE is opt-in. GUP callers must set
> @@ -1379,9 +1379,11 @@ static __always_inline long __get_user_pages_locked(struct mm_struct *mm,
>  	for (;;) {
>  		ret = __get_user_pages(mm, start, nr_pages, flags, pages,
>  				       vmas, locked);
> -		if (!locked)
> +		if (!(flags & FOLL_UNLOCK)) {
>  			/* VM_FAULT_RETRY couldn't trigger, bypass */
> -			return ret;
> +			pages_done = ret;
> +			break;
> +		}
>  
>  		/* VM_FAULT_RETRY or VM_FAULT_COMPLETED cannot return errors */
>  		if (!*locked) {
> @@ -2106,12 +2108,20 @@ static bool is_valid_gup_args(struct page **pages, struct vm_area_struct **vmas,
>  	 * interfaces:
>  	 * - FOLL_PIN/FOLL_TRIED/FOLL_FAST_ONLY is internal only
>  	 * - FOLL_REMOTE is internal only and used on follow_page()
> +	 * - FOLL_UNLOCK is internal only and used if locked is !NULL
>  	 */
> -	if (WARN_ON_ONCE(gup_flags & (FOLL_PIN | FOLL_TRIED |
> +	if (WARN_ON_ONCE(gup_flags & (FOLL_PIN | FOLL_TRIED | FOLL_UNLOCK |
>  				      FOLL_REMOTE | FOLL_FAST_ONLY)))
>  		return false;
>  
>  	gup_flags |= to_set;
> +	if (locked) {
> +		/* At the external interface locked must be set */
> +		if (WARN_ON_ONCE(*locked != 1))
> +			return false;
> +
> +		gup_flags |= FOLL_UNLOCK;
> +	}
>  
>  	/* FOLL_GET and FOLL_PIN are mutually exclusive. */
>  	if (WARN_ON_ONCE((gup_flags & (FOLL_PIN | FOLL_GET)) ==
> @@ -2126,10 +2136,6 @@ static bool is_valid_gup_args(struct page **pages, struct vm_area_struct **vmas,
>  	if (WARN_ON_ONCE((gup_flags & (FOLL_GET | FOLL_PIN)) && !pages))
>  		return false;
>  
> -	/* At the external interface locked must be set */
> -	if (WARN_ON_ONCE(locked && *locked != 1))
> -		return false;
> -
>  	/* We want to allow the pgmap to be hot-unplugged at all times */
>  	if (WARN_ON_ONCE((gup_flags & FOLL_LONGTERM) &&
>  			 (gup_flags & FOLL_PCI_P2PDMA)))
> @@ -2139,7 +2145,7 @@ static bool is_valid_gup_args(struct page **pages, struct vm_area_struct **vmas,
>  	 * Can't use VMAs with locked, as locked allows GUP to unlock
>  	 * which invalidates the vmas array
>  	 */
> -	if (WARN_ON_ONCE(vmas && locked))
> +	if (WARN_ON_ONCE(vmas && (gup_flags & FOLL_UNLOCK)))
>  		return false;
>  
>  	*gup_flags_p = gup_flags;
> @@ -2279,7 +2285,8 @@ long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages,
>  {
>  	int locked = 0;
>  
> -	if (!is_valid_gup_args(pages, NULL, NULL, &gup_flags, FOLL_TOUCH))
> +	if (!is_valid_gup_args(pages, NULL, NULL, &gup_flags,
> +			       FOLL_TOUCH | FOLL_UNLOCK))
>  		return -EINVAL;
>  
>  	return __get_user_pages_locked(current->mm, start, nr_pages, pages,
> @@ -2967,7 +2974,7 @@ static int internal_get_user_pages_fast(unsigned long start,
>  	pages += nr_pinned;
>  	ret = __gup_longterm_locked(current->mm, start, nr_pages - nr_pinned,
>  				    pages, NULL, &locked,
> -				    gup_flags | FOLL_TOUCH);
> +				    gup_flags | FOLL_TOUCH | FOLL_UNLOCK);
>  	if (ret < 0) {
>  		/*
>  		 * The caller has to unpin the pages we already pinned so
> @@ -3194,7 +3201,7 @@ long pin_user_pages_unlocked(unsigned long start, unsigned long nr_pages,
>  	int locked = 0;
>  
>  	if (!is_valid_gup_args(pages, NULL, NULL, &gup_flags,
> -			       FOLL_PIN | FOLL_TOUCH))
> +			       FOLL_PIN | FOLL_TOUCH | FOLL_UNLOCK))
>  		return 0;
>  
>  	return __gup_longterm_locked(current->mm, start, nr_pages, pages, NULL,






[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux