diff --git a/fs/fuse/file.c b/fs/fuse/file.c index c721bd4fa3dd07c1e771c5a81d7926b7f3b97dd4..087cce1b149bb4c81e5bbe58093b0b40bb180e54 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -2183,6 +2183,10 @@ static bool fuse_writepage_need_send(struct fuse_conn *fc, struct page *page, if (ap->num_pages == data->max_pages && !fuse_pages_realloc(data)) return true; + /* Reached alignment boundary */ + if (fc->write_alignment && !(page->index % fc->write_align_pages)) + return true; + return false; } diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index bff009c733ec7277c41471ee206afa5e10678061..32bc49ac8f618acb33387593a76d217e1b4a994a 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -621,6 +621,9 @@ struct fuse_conn { /** Maximum write size */ unsigned max_write; + /* Maxmum number of pages that write request should be aligned with */ + unsigned int write_align_pages; + /** Maxmum number of pages that can be used in a single request */ unsigned int max_pages; @@ -864,6 +867,9 @@ struct fuse_conn { /* Is rescue_uid specified? */ unsigned int rescue_uid_present:1; + /* write reques is aligned on max_write boundary */ + unsigned int write_alignment:1; + /** The number of requests waiting for completion */ atomic_t num_waiting; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index e9a08b64ecdfc35dfc315ba6bf93753e282a0dcc..a4c8b889ad89c0dcfe80fb3807c8f3a34ecf3909 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -1225,6 +1225,8 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args, pr_info("server recovery enabled for tag %s\n", fc->tag); } } + if (flags & FUSE_WRITE_ALIGNMENT) + fc->write_alignment = 1; } else { ra_pages = fc->max_read / PAGE_SIZE; fc->no_lock = 1; @@ -1236,6 +1238,12 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args, fc->minor = arg->minor; fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; fc->max_write = max_t(unsigned, 4096, fc->max_write); + if (fc->write_alignment) { + if (fc->max_write % PAGE_SIZE) + ok = false; + else + fc->write_align_pages = fc->max_write >> PAGE_SHIFT; + } fc->conn_init = 1; } kfree(ia); @@ -1271,7 +1279,8 @@ static void fuse_prepare_send_init(struct fuse_mount *fm, FUSE_INVAL_CACHE_INFAIL | FUSE_CLOSE_TO_OPEN | FUSE_INVALDIR_ALLENTRY | FUSE_DELETE_STALE | FUSE_DIRECT_IO_ALLOW_MMAP | FUSE_NO_EXPORT_SUPPORT | - FUSE_HAS_RESEND | FUSE_SEPARATE_BACKGROUND | FUSE_HAS_RECOVERY; + FUSE_HAS_RESEND | FUSE_SEPARATE_BACKGROUND | FUSE_HAS_RECOVERY | + FUSE_WRITE_ALIGNMENT; #ifdef CONFIG_FUSE_DAX if (fm->fc->dax) flags |= FUSE_MAP_ALIGNMENT; diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index e67709c9a5a0942c0d6101e9ddc543a2c8741c16..f3f3631389a0dcede417de6acc212dfd22d5ead8 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -352,6 +352,7 @@ struct fuse_file_lock { * FUSE_SEPARATE_BACKGROUND: separate background queue for WRITE requests and * the others * FUSE_HAS_RECOVERY: recovery mechanism for fuse server + * FUSE_WRITE_ALIGNMENT: write request is aligned on max_write boundary */ #define FUSE_ASYNC_READ (1 << 0) #define FUSE_POSIX_LOCKS (1 << 1) @@ -389,6 +390,7 @@ struct fuse_file_lock { #define FUSE_DIRECT_IO_ALLOW_MMAP (1ULL << 36) #define FUSE_NO_EXPORT_SUPPORT (1ULL << 38) #define FUSE_HAS_RESEND (1ULL << 39) +#define FUSE_WRITE_ALIGNMENT (1ULL << 55) #define FUSE_SEPARATE_BACKGROUND (1ULL << 56) #define FUSE_HAS_RECOVERY (1ULL << 57) #define FUSE_DELETE_STALE (1ULL << 58)