Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e77b0a5

Browse files
committed
fuse: add PAGE_MKWRITE opcode
Add PAGE_MKWRITE fuse request to allow FUSE daemon to acquire DLM lock for protecting dirty page creation. Allow read_folio to return EAGAIN error and translate it to AOP_TRUNCATE_PAGE to retry page fault and read operations. This is used to prevent deadlock of folio lock/DLM lock order reversal: - Fault or read operations acquire folio lock first, then DLM lock. - FUSE daemon blocks new DLM lock acquisition while it invalidating page cache. invalidate_inode_pages2_range() acquires folio lock To prevent deadlock, the FUSE daemon will fail its DLM lock acquisition with EAGAIN if it detects an in-flight page cache invalidating operation. This enables memory mapping across cluster nodes with proper distributed locking coordination.
1 parent 1157436 commit e77b0a5

File tree

4 files changed

+50
-1
lines changed

4 files changed

+50
-1
lines changed

fs/fuse/file.c

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -882,8 +882,11 @@ static int fuse_do_readpage(struct file *file, struct page *page)
882882

883883
fuse_read_args_fill(&ia, file, pos, desc.length, FUSE_READ);
884884
res = fuse_simple_request(fm, &ia.ap.args);
885-
if (res < 0)
885+
if (res < 0) {
886+
if (res == -EAGAIN)
887+
res = AOP_TRUNCATED_PAGE;
886888
return res;
889+
}
887890
/*
888891
* Short read means EOF. If file size is larger, truncate it
889892
*/
@@ -2506,6 +2509,35 @@ static void fuse_vma_close(struct vm_area_struct *vma)
25062509
mapping_set_error(vma->vm_file->f_mapping, err);
25072510
}
25082511

2512+
static int fuse_send_page_mkwrite(struct file *file, loff_t pos, size_t len)
2513+
{
2514+
struct inode *inode = file_inode(file);
2515+
struct fuse_mount *fm = get_fuse_mount(inode);
2516+
struct fuse_file *ff = file->private_data;
2517+
struct fuse_page_mkwrite_in inarg = {
2518+
.fh = ff->fh,
2519+
.off = pos,
2520+
.len = len
2521+
};
2522+
FUSE_ARGS(args);
2523+
int err = 0;
2524+
2525+
if (fm->fc->no_mkwrite)
2526+
return err;
2527+
2528+
args.opcode = FUSE_PAGE_MKWRITE;
2529+
args.nodeid = ff->nodeid;
2530+
args.in_numargs = 1;
2531+
args.in_args[0].size = sizeof(inarg);
2532+
args.in_args[0].value = &inarg;
2533+
2534+
err = fuse_simple_request(fm, &args);
2535+
if (err == -ENOSYS) {
2536+
fm->fc->no_mkwrite = 1;
2537+
err = 0;
2538+
}
2539+
return err;
2540+
}
25092541
/*
25102542
* Wait for writeback against this page to complete before allowing it
25112543
* to be marked dirty again, and hence written back again, possibly
@@ -2525,6 +2557,12 @@ static vm_fault_t fuse_page_mkwrite(struct vm_fault *vmf)
25252557
{
25262558
struct page *page = vmf->page;
25272559
struct inode *inode = file_inode(vmf->vma->vm_file);
2560+
int err;
2561+
2562+
err = fuse_send_page_mkwrite(vmf->vma->vm_file, vmf->pgoff << PAGE_SHIFT, PAGE_SIZE);
2563+
if (err < 0) {
2564+
return vmf_error(err);
2565+
}
25282566

25292567
file_update_time(vmf->vma->vm_file);
25302568
lock_page(page);

fs/fuse/fuse_i.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,9 @@ struct fuse_conn {
860860
/* do we have support for dlm in the fs? */
861861
unsigned int dlm:1;
862862

863+
/* Is mkwrite not implemented by fs? */
864+
unsigned int no_mkwrite:1;
865+
863866
/* Use io_uring for communication */
864867
unsigned int io_uring;
865868

fs/fuse/fuse_trace.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
EM( FUSE_TMPFILE, "FUSE_TMPFILE") \
6060
EM( FUSE_STATX, "FUSE_STATX") \
6161
EM( FUSE_DLM_WB_LOCK, "FUSE_DLM_WB_LOCK") \
62+
EM( FUSE_PAGE_MKWRITE, "FUSE_PAGE_MKWRITE") \
6263
EMe(CUSE_INIT, "CUSE_INIT")
6364

6465
/*

include/uapi/linux/fuse.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,7 @@ enum fuse_opcode {
639639
FUSE_TMPFILE = 51,
640640
FUSE_STATX = 52,
641641
FUSE_DLM_WB_LOCK = 53,
642+
FUSE_PAGE_MKWRITE = 54,
642643

643644
/* CUSE specific operations */
644645
CUSE_INIT = 4096,
@@ -902,6 +903,12 @@ struct fuse_init_out {
902903

903904
#define CUSE_INIT_INFO_MAX 4096
904905

906+
struct fuse_page_mkwrite_in {
907+
uint64_t fh;
908+
uint64_t off;
909+
uint64_t len;
910+
};
911+
905912
struct cuse_init_in {
906913
uint32_t major;
907914
uint32_t minor;

0 commit comments

Comments
 (0)