Skip to content

Commit 8392bc2

Browse files
josefbacikjankara
authored andcommitted
fsnotify: generate pre-content permission event on page fault
FS_PRE_ACCESS will be generated on page fault depending on the faulting method. This pre-content event is meant to be used by hierarchical storage managers that want to fill in the file content on first read access. Export a simple helper that file systems that have their own ->fault() will use, and have a more complicated helper to be do fancy things in filemap_fault. Signed-off-by: Josef Bacik <[email protected]> Signed-off-by: Jan Kara <[email protected]> Link: https://patch.msgid.link/aa56c50ce81b1fd18d7f5d71dd2dfced5eba9687.1731684329.git.josef@toxicpanda.com
1 parent 20bf82a commit 8392bc2

File tree

3 files changed

+82
-0
lines changed

3 files changed

+82
-0
lines changed

include/linux/mm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3420,6 +3420,7 @@ extern vm_fault_t filemap_fault(struct vm_fault *vmf);
34203420
extern vm_fault_t filemap_map_pages(struct vm_fault *vmf,
34213421
pgoff_t start_pgoff, pgoff_t end_pgoff);
34223422
extern vm_fault_t filemap_page_mkwrite(struct vm_fault *vmf);
3423+
extern vm_fault_t filemap_fsnotify_fault(struct vm_fault *vmf);
34233424

34243425
extern unsigned long stack_guard_gap;
34253426
/* Generic expand stack which grows the stack according to GROWS{UP,DOWN} */

mm/filemap.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include <linux/splice.h>
4848
#include <linux/rcupdate_wait.h>
4949
#include <linux/sched/mm.h>
50+
#include <linux/fsnotify.h>
5051
#include <asm/pgalloc.h>
5152
#include <asm/tlbflush.h>
5253
#include "internal.h"
@@ -3288,6 +3289,48 @@ static vm_fault_t filemap_fault_recheck_pte_none(struct vm_fault *vmf)
32883289
return ret;
32893290
}
32903291

3292+
/**
3293+
* filemap_fsnotify_fault - maybe emit a pre-content event.
3294+
* @vmf: struct vm_fault containing details of the fault.
3295+
*
3296+
* If we have a pre-content watch on this file we will emit an event for this
3297+
* range. If we return anything the fault caller should return immediately, we
3298+
* will return VM_FAULT_RETRY if we had to emit an event, which will trigger the
3299+
* fault again and then the fault handler will run the second time through.
3300+
*
3301+
* Return: a bitwise-OR of %VM_FAULT_ codes, 0 if nothing happened.
3302+
*/
3303+
vm_fault_t filemap_fsnotify_fault(struct vm_fault *vmf)
3304+
{
3305+
struct file *fpin = NULL;
3306+
int mask = (vmf->flags & FAULT_FLAG_WRITE) ? MAY_WRITE : MAY_ACCESS;
3307+
loff_t pos = vmf->pgoff >> PAGE_SHIFT;
3308+
size_t count = PAGE_SIZE;
3309+
int err;
3310+
3311+
/*
3312+
* We already did this and now we're retrying with everything locked,
3313+
* don't emit the event and continue.
3314+
*/
3315+
if (vmf->flags & FAULT_FLAG_TRIED)
3316+
return 0;
3317+
3318+
/* No watches, we're done. */
3319+
if (likely(!FMODE_FSNOTIFY_HSM(vmf->vma->vm_file->f_mode)))
3320+
return 0;
3321+
3322+
fpin = maybe_unlock_mmap_for_io(vmf, fpin);
3323+
if (!fpin)
3324+
return VM_FAULT_SIGBUS;
3325+
3326+
err = fsnotify_file_area_perm(fpin, mask, &pos, count);
3327+
fput(fpin);
3328+
if (err)
3329+
return VM_FAULT_SIGBUS;
3330+
return VM_FAULT_RETRY;
3331+
}
3332+
EXPORT_SYMBOL_GPL(filemap_fsnotify_fault);
3333+
32913334
/**
32923335
* filemap_fault - read in file data for page fault handling
32933336
* @vmf: struct vm_fault containing details of the fault
@@ -3391,6 +3434,37 @@ vm_fault_t filemap_fault(struct vm_fault *vmf)
33913434
* or because readahead was otherwise unable to retrieve it.
33923435
*/
33933436
if (unlikely(!folio_test_uptodate(folio))) {
3437+
/*
3438+
* If this is a precontent file we have can now emit an event to
3439+
* try and populate the folio.
3440+
*/
3441+
if (!(vmf->flags & FAULT_FLAG_TRIED) &&
3442+
unlikely(FMODE_FSNOTIFY_HSM(file->f_mode))) {
3443+
loff_t pos = folio_pos(folio);
3444+
size_t count = folio_size(folio);
3445+
3446+
/* We're NOWAIT, we have to retry. */
3447+
if (vmf->flags & FAULT_FLAG_RETRY_NOWAIT) {
3448+
folio_unlock(folio);
3449+
goto out_retry;
3450+
}
3451+
3452+
if (mapping_locked)
3453+
filemap_invalidate_unlock_shared(mapping);
3454+
mapping_locked = false;
3455+
3456+
folio_unlock(folio);
3457+
fpin = maybe_unlock_mmap_for_io(vmf, fpin);
3458+
if (!fpin)
3459+
goto out_retry;
3460+
3461+
error = fsnotify_file_area_perm(fpin, MAY_ACCESS, &pos,
3462+
count);
3463+
if (error)
3464+
ret = VM_FAULT_SIGBUS;
3465+
goto out_retry;
3466+
}
3467+
33943468
/*
33953469
* If the invalidate lock is not held, the folio was in cache
33963470
* and uptodate and now it is not. Strange but possible since we

mm/nommu.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1613,6 +1613,13 @@ int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
16131613
}
16141614
EXPORT_SYMBOL(remap_vmalloc_range);
16151615

1616+
vm_fault_t filemap_fsnotify_fault(struct vm_fault *vmf)
1617+
{
1618+
BUG();
1619+
return 0;
1620+
}
1621+
EXPORT_SYMBOL_GPL(filemap_fsnotify_fault);
1622+
16161623
vm_fault_t filemap_fault(struct vm_fault *vmf)
16171624
{
16181625
BUG();

0 commit comments

Comments
 (0)