Skip to content

Commit af67038

Browse files
ljskernelakpm00
authored andcommitted
mm: specify separate file and vm_file params in vm_area_desc
Patch series "mm: do not assume file == vma->vm_file in compat_vma_mmap_prepare()", v2. As part of the efforts to eliminate the problematic f_op->mmap callback, a new callback - f_op->mmap_prepare was provided. While we are converting these callbacks, we must deal with 'stacked' filesystems and drivers - those which in their own f_op->mmap callback invoke an inner f_op->mmap callback. To accomodate for this, a compatibility layer is provided that, via vfs_mmap(), detects if f_op->mmap_prepare is provided and if so, generates a vm_area_desc containing the VMA's metadata and invokes the call. So far, we have provided desc->file equal to vma->vm_file. However this is not necessarily valid, especially in the case of stacked drivers which wish to assign a new file after the inner hook is invoked. To account for this, we adjust vm_area_desc to have both file and vm_file fields. The .vm_file field is strictly set to vma->vm_file (or in the case of a new mapping, what will become vma->vm_file). However, .file is set to whichever file vfs_mmap() is invoked with when using the compatibilty layer. Therefore, if the VMA's file needs to be updated in .mmap_prepare, desc->vm_file should be assigned, whilst desc->file should be read. No current f_op->mmap_prepare users assign desc->file so this is safe to do. This makes the .mmap_prepare callback in the context of a stacked filesystem or driver completely consistent with the existing .mmap implementations. While we're here, we do a few small cleanups, and ensure that we const-ify things correctly in the vm_area_desc struct to avoid hooks accidentally trying to assign fields they should not. This patch (of 2): Stacked filesystems and drivers may invoke mmap hooks with a struct file pointer that differs from the overlying file. We will make this functionality possible in a subsequent patch. In order to prepare for this, let's update vm_area_struct to separately provide desc->file and desc->vm_file parameters. The desc->file parameter is the file that the hook is expected to operate upon, and is not assignable (though the hok may wish to e.g. update the file's accessed time for instance). The desc->vm_file defaults to what will become vma->vm_file and is what the hook must reassign should it wish to change the VMA"s vma->vm_file. For now we keep desc->file, vm_file the same to remain consistent. No f_op->mmap_prepare() callback sets a new vma->vm_file currently, so this is safe to change. While we're here, make the mm_struct desc->mm pointers at immutable as well as the desc->mm field itself. As part of this change, also update the single hook which this would otherwise break - mlock_future_ok(), invoked by secretmem_mmap_prepare()). We additionally update set_vma_from_desc() to compare fields in a more logical fashion, checking the (possibly) user-modified fields as the first operand against the existing value as the second one. Additionally, update VMA tests to accommodate changes. Link: https://lkml.kernel.org/r/cover.1756920635.git.lorenzo.stoakes@oracle.com Link: https://lkml.kernel.org/r/3fa15a861bb7419f033d22970598aa61850ea267.1756920635.git.lorenzo.stoakes@oracle.com Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Christian Brauner <brauner@kernel.org> Cc: David Hildenbrand <david@redhat.com> Cc: Jan Kara <jack@suse.cz> Cc: Jann Horn <jannh@google.com> Cc: Liam Howlett <liam.howlett@oracle.com> Cc: Michal Hocko <mhocko@suse.com> Cc: Mike Rapoport <rppt@kernel.org> Cc: Suren Baghdasaryan <surenb@google.com> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: Pedro Falcato <pfalcato@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 473b732 commit af67038

7 files changed

Lines changed: 43 additions & 43 deletions

File tree

include/linux/mm_types.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -777,13 +777,14 @@ struct pfnmap_track_ctx {
777777
*/
778778
struct vm_area_desc {
779779
/* Immutable state. */
780-
struct mm_struct *mm;
780+
const struct mm_struct *const mm;
781+
struct file *const file; /* May vary from vm_file in stacked callers. */
781782
unsigned long start;
782783
unsigned long end;
783784

784785
/* Mutable fields. Populated with initial state. */
785786
pgoff_t pgoff;
786-
struct file *file;
787+
struct file *vm_file;
787788
vm_flags_t vm_flags;
788789
pgprot_t page_prot;
789790

mm/internal.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -962,8 +962,8 @@ extern long populate_vma_page_range(struct vm_area_struct *vma,
962962
unsigned long start, unsigned long end, int *locked);
963963
extern long faultin_page_range(struct mm_struct *mm, unsigned long start,
964964
unsigned long end, bool write, int *locked);
965-
extern bool mlock_future_ok(struct mm_struct *mm, vm_flags_t vm_flags,
966-
unsigned long bytes);
965+
bool mlock_future_ok(const struct mm_struct *mm, vm_flags_t vm_flags,
966+
unsigned long bytes);
967967

968968
/*
969969
* NOTE: This function can't tell whether the folio is "fully mapped" in the

mm/mmap.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ static inline unsigned long round_hint_to_min(unsigned long hint)
225225
return hint;
226226
}
227227

228-
bool mlock_future_ok(struct mm_struct *mm, vm_flags_t vm_flags,
228+
bool mlock_future_ok(const struct mm_struct *mm, vm_flags_t vm_flags,
229229
unsigned long bytes)
230230
{
231231
unsigned long locked_pages, limit_pages;

mm/util.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,10 +1161,20 @@ EXPORT_SYMBOL(flush_dcache_folio);
11611161
*/
11621162
int compat_vma_mmap_prepare(struct file *file, struct vm_area_struct *vma)
11631163
{
1164-
struct vm_area_desc desc;
1164+
struct vm_area_desc desc = {
1165+
.mm = vma->vm_mm,
1166+
.file = vma->vm_file,
1167+
.start = vma->vm_start,
1168+
.end = vma->vm_end,
1169+
1170+
.pgoff = vma->vm_pgoff,
1171+
.vm_file = vma->vm_file,
1172+
.vm_flags = vma->vm_flags,
1173+
.page_prot = vma->vm_page_prot,
1174+
};
11651175
int err;
11661176

1167-
err = file->f_op->mmap_prepare(vma_to_desc(vma, &desc));
1177+
err = file->f_op->mmap_prepare(&desc);
11681178
if (err)
11691179
return err;
11701180
set_vma_from_desc(vma, &desc);

mm/vma.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2572,11 +2572,12 @@ static int call_mmap_prepare(struct mmap_state *map)
25722572
int err;
25732573
struct vm_area_desc desc = {
25742574
.mm = map->mm,
2575+
.file = map->file,
25752576
.start = map->addr,
25762577
.end = map->end,
25772578

25782579
.pgoff = map->pgoff,
2579-
.file = map->file,
2580+
.vm_file = map->file,
25802581
.vm_flags = map->vm_flags,
25812582
.page_prot = map->page_prot,
25822583
};
@@ -2588,7 +2589,7 @@ static int call_mmap_prepare(struct mmap_state *map)
25882589

25892590
/* Update fields permitted to be changed. */
25902591
map->pgoff = desc.pgoff;
2591-
map->file = desc.file;
2592+
map->file = desc.vm_file;
25922593
map->vm_flags = desc.vm_flags;
25932594
map->page_prot = desc.page_prot;
25942595
/* User-defined fields. */

mm/vma.h

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -222,31 +222,11 @@ static inline int vma_iter_store_gfp(struct vma_iterator *vmi,
222222
return 0;
223223
}
224224

225-
226225
/*
227-
* Temporary helper functions for file systems which wrap an invocation of
226+
* Temporary helper function for stacked mmap handlers which specify
228227
* f_op->mmap() but which might have an underlying file system which implements
229228
* f_op->mmap_prepare().
230229
*/
231-
232-
static inline struct vm_area_desc *vma_to_desc(struct vm_area_struct *vma,
233-
struct vm_area_desc *desc)
234-
{
235-
desc->mm = vma->vm_mm;
236-
desc->start = vma->vm_start;
237-
desc->end = vma->vm_end;
238-
239-
desc->pgoff = vma->vm_pgoff;
240-
desc->file = vma->vm_file;
241-
desc->vm_flags = vma->vm_flags;
242-
desc->page_prot = vma->vm_page_prot;
243-
244-
desc->vm_ops = NULL;
245-
desc->private_data = NULL;
246-
247-
return desc;
248-
}
249-
250230
static inline void set_vma_from_desc(struct vm_area_struct *vma,
251231
struct vm_area_desc *desc)
252232
{
@@ -258,9 +238,9 @@ static inline void set_vma_from_desc(struct vm_area_struct *vma,
258238

259239
/* Mutable fields. Populated with initial state. */
260240
vma->vm_pgoff = desc->pgoff;
261-
if (vma->vm_file != desc->file)
262-
vma_set_file(vma, desc->file);
263-
if (vma->vm_flags != desc->vm_flags)
241+
if (desc->vm_file != vma->vm_file)
242+
vma_set_file(vma, desc->vm_file);
243+
if (desc->vm_flags != vma->vm_flags)
264244
vm_flags_set(vma, desc->vm_flags);
265245
vma->vm_page_prot = desc->page_prot;
266246

tools/testing/vma/vma_internal.h

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -283,13 +283,14 @@ struct vm_area_struct;
283283
*/
284284
struct vm_area_desc {
285285
/* Immutable state. */
286-
struct mm_struct *mm;
286+
const struct mm_struct *const mm;
287+
struct file *const file; /* May vary from vm_file in stacked callers. */
287288
unsigned long start;
288289
unsigned long end;
289290

290291
/* Mutable fields. Populated with initial state. */
291292
pgoff_t pgoff;
292-
struct file *file;
293+
struct file *vm_file;
293294
vm_flags_t vm_flags;
294295
pgprot_t page_prot;
295296

@@ -1299,8 +1300,8 @@ static inline bool capable(int cap)
12991300
return true;
13001301
}
13011302

1302-
static inline bool mlock_future_ok(struct mm_struct *mm, vm_flags_t vm_flags,
1303-
unsigned long bytes)
1303+
static inline bool mlock_future_ok(const struct mm_struct *mm,
1304+
vm_flags_t vm_flags, unsigned long bytes)
13041305
{
13051306
unsigned long locked_pages, limit_pages;
13061307

@@ -1465,16 +1466,23 @@ static inline void free_anon_vma_name(struct vm_area_struct *vma)
14651466
static inline void set_vma_from_desc(struct vm_area_struct *vma,
14661467
struct vm_area_desc *desc);
14671468

1468-
static inline struct vm_area_desc *vma_to_desc(struct vm_area_struct *vma,
1469-
struct vm_area_desc *desc);
1470-
1471-
static int compat_vma_mmap_prepare(struct file *file,
1469+
static inline int compat_vma_mmap_prepare(struct file *file,
14721470
struct vm_area_struct *vma)
14731471
{
1474-
struct vm_area_desc desc;
1472+
struct vm_area_desc desc = {
1473+
.mm = vma->vm_mm,
1474+
.file = vma->vm_file,
1475+
.start = vma->vm_start,
1476+
.end = vma->vm_end,
1477+
1478+
.pgoff = vma->vm_pgoff,
1479+
.vm_file = vma->vm_file,
1480+
.vm_flags = vma->vm_flags,
1481+
.page_prot = vma->vm_page_prot,
1482+
};
14751483
int err;
14761484

1477-
err = file->f_op->mmap_prepare(vma_to_desc(vma, &desc));
1485+
err = file->f_op->mmap_prepare(&desc);
14781486
if (err)
14791487
return err;
14801488
set_vma_from_desc(vma, &desc);

0 commit comments

Comments
 (0)