Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions fs/fuse/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -1464,6 +1464,50 @@ static void fuse_dio_unlock(struct kiocb *iocb, bool exclusive)
}
}


/*
* With writeback caching the request size seen by the server depends on
* how many contiguous dirty pages the flusher finds, which is bounded by
* dirty throttling: with BDI_CAP_STRICTLIMIT the dirty window can degrade
* to a single page under streaming writes, turning large application
* writes into page-sized requests.
*
* Writes that already match the server's preferred alignment gain
* nothing from accumulating in the page cache, so send them through
* fuse_perform_write() instead, which packs requests up to max_write.
* They create no dirty pages, hence no DLM write lock needs to be cached
* for them. Unaligned writes keep using the writeback cache, where they
* can merge with neighbouring data.
*/
static bool fuse_use_writeback_cache(struct fuse_conn *fc, struct kiocb *iocb,
struct iov_iter *from)
{
size_t count = iov_iter_count(from);
u64 align;
bool ret;

if (!fc->big_writes) {
printk("%s: wbc=1 no big_writes pos=%lld count=%zu\n",
Comment thread
hbirth marked this conversation as resolved.
__func__, iocb->ki_pos, count);
return true;
}

/* these rely on the semantics of their current paths */
if (iocb->ki_flags & (IOCB_DIRECT | IOCB_APPEND | IOCB_NOWAIT)) {
printk("%s: wbc=1 ki_flags=0x%x pos=%lld count=%zu\n",
__func__, iocb->ki_flags, iocb->ki_pos, count);
return true;
}

align = fc->alignment_pages ?
(u64)fc->alignment_pages << PAGE_SHIFT : PAGE_SIZE;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why enforcing alignment on page size if fc->alignment_pages is not set?


ret = !IS_ALIGNED(iocb->ki_pos | (u64)count, align);
Comment thread
hbirth marked this conversation as resolved.
printk("%s: wbc=%d pos=%lld count=%zu align=%llu alignment_pages=%u\n",
__func__, ret, iocb->ki_pos, count, align, fc->alignment_pages);
return ret;
}

static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
struct file *file = iocb->ki_filp;
Expand All @@ -1486,6 +1530,9 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
goto writethrough;
}

if (!fuse_use_writeback_cache(fc, iocb, from))
goto writethrough;

/* if we have dlm support acquire the lock for the area
* we are writing into */
if (fc->dlm) {
Expand Down
2 changes: 1 addition & 1 deletion fs/fuse/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1745,7 +1745,7 @@ static int fuse_bdi_init(struct fuse_conn *fc, struct super_block *sb)

/* fuse does it's own writeback accounting */
sb->s_bdi->capabilities &= ~BDI_CAP_WRITEBACK_ACCT;
sb->s_bdi->capabilities |= BDI_CAP_STRICTLIMIT;
sb->s_bdi->capabilities &= ~BDI_CAP_STRICTLIMIT;

/*
* For a single fuse filesystem use max 1% of dirty +
Expand Down
7 changes: 4 additions & 3 deletions include/uapi/linux/fuse.h
Original file line number Diff line number Diff line change
Expand Up @@ -429,8 +429,8 @@ struct fuse_file_lock {
* FUSE_OVER_IO_URING: Indicate that client supports io-uring
* FUSE_INVAL_INODE_ENTRY: invalidate inode aliases when doing inode invalidation
* FUSE_EXPIRE_INODE_ENTRY: expire inode aliases when doing inode invalidation
* FUSE_ALIGN_PG_ORDER: page order (power of 2 exponent for number of pages) for
* optimal io-size alignment
* FUSE_ALIGN_PG_ORDER: alignment order (power of 2 exponent of the IO size
* in bytes) for optimal io-size alignment
* FUSE_URING_REDUCED_Q: Client (kernel) supports less queues - Server is free
* to register between 1 and nr-core io-uring queues
*/
Expand Down Expand Up @@ -926,7 +926,8 @@ struct fuse_init_in {
#define FUSE_COMPAT_22_INIT_OUT_SIZE 24

/*
* align_page_order: Number of pages for optimal IO, or a multiple of that
* align_page_order: log2 of the optimal IO size in bytes; IO is optimal
* when sized and aligned to (1 << align_page_order) or a multiple of it
*/
struct fuse_init_out {
uint32_t major;
Expand Down