Message ID | 20161013002020.3062-5-lstoakes@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Thu 13-10-16 01:20:14, Lorenzo Stoakes wrote: > This patch removes the write and force parameters from get_user_pages_locked() > and replaces them with a gup_flags parameter to make the use of FOLL_FORCE > explicit in callers as use of this flag can result in surprising behaviour (and > hence bugs) within the mm subsystem. > > Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com> > --- > include/linux/mm.h | 2 +- > mm/frame_vector.c | 8 +++++++- > mm/gup.c | 12 +++--------- > mm/nommu.c | 5 ++++- > 4 files changed, 15 insertions(+), 12 deletions(-) > > diff --git a/include/linux/mm.h b/include/linux/mm.h > index 6adc4bc..27ab538 100644 > --- a/include/linux/mm.h > +++ b/include/linux/mm.h > @@ -1282,7 +1282,7 @@ long get_user_pages(unsigned long start, unsigned long nr_pages, > int write, int force, struct page **pages, > struct vm_area_struct **vmas); > long get_user_pages_locked(unsigned long start, unsigned long nr_pages, > - int write, int force, struct page **pages, int *locked); > + unsigned int gup_flags, struct page **pages, int *locked); Hum, the prototype is inconsistent with e.g. __get_user_pages_unlocked() where gup_flags come after **pages argument. Actually it makes more sense to have it before **pages so that input arguments come first and output arguments second but I don't care that much. But it definitely should be consistent... Honza
On Tue, Oct 18, 2016 at 02:54:25PM +0200, Jan Kara wrote: > > @@ -1282,7 +1282,7 @@ long get_user_pages(unsigned long start, unsigned long nr_pages, > > int write, int force, struct page **pages, > > struct vm_area_struct **vmas); > > long get_user_pages_locked(unsigned long start, unsigned long nr_pages, > > - int write, int force, struct page **pages, int *locked); > > + unsigned int gup_flags, struct page **pages, int *locked); > > Hum, the prototype is inconsistent with e.g. __get_user_pages_unlocked() > where gup_flags come after **pages argument. Actually it makes more sense > to have it before **pages so that input arguments come first and output > arguments second but I don't care that much. But it definitely should be > consistent... It was difficult to decide quite how to arrange parameters as there was inconsitency with regards to parameter ordering already - for example __get_user_pages() places its flags argument before pages whereas, as you note, __get_user_pages_unlocked() puts them afterwards. I ended up compromising by trying to match the existing ordering of the function as much as I could by replacing write, force pairs with gup_flags in the same location (with the exception of get_user_pages_unlocked() which I felt should match __get_user_pages_unlocked() in signature) or if there was already a gup_flags parameter as in the case of __get_user_pages_unlocked() I simply removed the write, force pair and left the flags as the last parameter. I am happy to rearrange parameters as needed, however I am not sure if it'd be worthwhile for me to do so (I am keen to try to avoid adding too much noise here :) If we were to rearrange parameters for consistency I'd suggest adjusting __get_user_pages_unlocked() to put gup_flags before pages and do the same with get_user_pages_unlocked(), let me know what you think.
On Tue 18-10-16 14:56:09, Lorenzo Stoakes wrote: > On Tue, Oct 18, 2016 at 02:54:25PM +0200, Jan Kara wrote: > > > @@ -1282,7 +1282,7 @@ long get_user_pages(unsigned long start, unsigned long nr_pages, > > > int write, int force, struct page **pages, > > > struct vm_area_struct **vmas); > > > long get_user_pages_locked(unsigned long start, unsigned long nr_pages, > > > - int write, int force, struct page **pages, int *locked); > > > + unsigned int gup_flags, struct page **pages, int *locked); > > > > Hum, the prototype is inconsistent with e.g. __get_user_pages_unlocked() > > where gup_flags come after **pages argument. Actually it makes more sense > > to have it before **pages so that input arguments come first and output > > arguments second but I don't care that much. But it definitely should be > > consistent... > > It was difficult to decide quite how to arrange parameters as there was > inconsitency with regards to parameter ordering already - for example > __get_user_pages() places its flags argument before pages whereas, as you note, > __get_user_pages_unlocked() puts them afterwards. > > I ended up compromising by trying to match the existing ordering of the function > as much as I could by replacing write, force pairs with gup_flags in the same > location (with the exception of get_user_pages_unlocked() which I felt should > match __get_user_pages_unlocked() in signature) or if there was already a > gup_flags parameter as in the case of __get_user_pages_unlocked() I simply > removed the write, force pair and left the flags as the last parameter. > > I am happy to rearrange parameters as needed, however I am not sure if it'd be > worthwhile for me to do so (I am keen to try to avoid adding too much noise here > :) > > If we were to rearrange parameters for consistency I'd suggest adjusting > __get_user_pages_unlocked() to put gup_flags before pages and do the same with > get_user_pages_unlocked(), let me know what you think. Yeah, ok. If the inconsistency is already there, just leave it for now. Honza
On Thu 13-10-16 01:20:14, Lorenzo Stoakes wrote: > This patch removes the write and force parameters from get_user_pages_locked() > and replaces them with a gup_flags parameter to make the use of FOLL_FORCE > explicit in callers as use of this flag can result in surprising behaviour (and > hence bugs) within the mm subsystem. > > Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com> After our discussion the patch looks good to me. You can add: Reviewed-by: Jan Kara <jack@suse.cz> Honza
diff --git a/include/linux/mm.h b/include/linux/mm.h index 6adc4bc..27ab538 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1282,7 +1282,7 @@ long get_user_pages(unsigned long start, unsigned long nr_pages, int write, int force, struct page **pages, struct vm_area_struct **vmas); long get_user_pages_locked(unsigned long start, unsigned long nr_pages, - int write, int force, struct page **pages, int *locked); + unsigned int gup_flags, struct page **pages, int *locked); long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, struct page **pages, unsigned int gup_flags); diff --git a/mm/frame_vector.c b/mm/frame_vector.c index 381bb07..81b6749 100644 --- a/mm/frame_vector.c +++ b/mm/frame_vector.c @@ -41,10 +41,16 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames, int ret = 0; int err; int locked; + unsigned int gup_flags = 0; if (nr_frames == 0) return 0; + if (write) + gup_flags |= FOLL_WRITE; + if (force) + gup_flags |= FOLL_FORCE; + if (WARN_ON_ONCE(nr_frames > vec->nr_allocated)) nr_frames = vec->nr_allocated; @@ -59,7 +65,7 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames, vec->got_ref = true; vec->is_pfns = false; ret = get_user_pages_locked(start, nr_frames, - write, force, (struct page **)(vec->ptrs), &locked); + gup_flags, (struct page **)(vec->ptrs), &locked); goto out; } diff --git a/mm/gup.c b/mm/gup.c index cfcb014..7a0d033 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -838,18 +838,12 @@ static __always_inline long __get_user_pages_locked(struct task_struct *tsk, * up_read(&mm->mmap_sem); */ long get_user_pages_locked(unsigned long start, unsigned long nr_pages, - int write, int force, struct page **pages, + unsigned int gup_flags, struct page **pages, int *locked) { - unsigned int flags = FOLL_TOUCH; - - if (write) - flags |= FOLL_WRITE; - if (force) - flags |= FOLL_FORCE; - return __get_user_pages_locked(current, current->mm, start, nr_pages, - pages, NULL, locked, true, flags); + pages, NULL, locked, true, + gup_flags | FOLL_TOUCH); } EXPORT_SYMBOL(get_user_pages_locked); diff --git a/mm/nommu.c b/mm/nommu.c index 7e27add..842cfdd 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -176,9 +176,12 @@ long get_user_pages(unsigned long start, unsigned long nr_pages, EXPORT_SYMBOL(get_user_pages); long get_user_pages_locked(unsigned long start, unsigned long nr_pages, - int write, int force, struct page **pages, + unsigned int gup_flags, struct page **pages, int *locked) { + int write = gup_flags & FOLL_WRITE; + int force = gup_flags & FOLL_FORCE; + return get_user_pages(start, nr_pages, write, force, pages, NULL); } EXPORT_SYMBOL(get_user_pages_locked);
This patch removes the write and force parameters from get_user_pages_locked() and replaces them with a gup_flags parameter to make the use of FOLL_FORCE explicit in callers as use of this flag can result in surprising behaviour (and hence bugs) within the mm subsystem. Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com> --- include/linux/mm.h | 2 +- mm/frame_vector.c | 8 +++++++- mm/gup.c | 12 +++--------- mm/nommu.c | 5 ++++- 4 files changed, 15 insertions(+), 12 deletions(-)