Skip to content

Commit

Permalink
Enable parallel direct writes on the same file.
Browse files Browse the repository at this point in the history
Right now fuse kernel serializes direct writes on the
same file. This serialization is good for such FUSE
implementations which rely on the inode lock to
avoid any data inconsistency issues but it hurts badly
such FUSE implementations which have their own mechanism
of dealing with cache/data integrity and can handle
parallel direct writes on the same file.

This patch allows parallel direct writes on the same file to be
enabled with the help of a flag FOPEN_PARALLEL_DIRECT_WRITES.
FUSE implementations which want to use this feature can
set this flag during fuse init. Default behaviour remains
same i.e no parallel direct writes on the same file.

Corresponding fuse kernel patch(Merged).
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?h=v6.2&id=153524053bbb0d27bb2e0be36d1b46862e9ce74c
  • Loading branch information
d-hans authored and Nikratio committed Mar 3, 2023
1 parent 4f8aae7 commit a5eb7f2
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 4 deletions.
14 changes: 14 additions & 0 deletions include/fuse.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,20 @@ struct fuse_config {
* fuse_file_info argument is NULL.
*/
int nullpath_ok;
/**
* Allow parallel direct-io writes to operate on the same file.
*
* FUSE implementations which do not handle parallel writes on
* same file/region should NOT enable this option at all as it
* might lead to data inconsistencies.
*
* For the FUSE implementations which have their own mechanism
* of cache/data integrity are beneficiaries of this setting as
* it now open doors to parallel writes on the same file (without
* enabling this setting, all direct writes on the same file are
* serialized, resulting in huge data bandwidth loss).
*/
int parallel_direct_writes;

/**
* The remaining options are used by libfuse internally and
Expand Down
8 changes: 6 additions & 2 deletions include/fuse_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ struct fuse_file_info {
requests if write caching had been disabled. */
unsigned int writepage : 1;

/** Can be filled in by open, to use direct I/O on this file. */
/** Can be filled in by open/create, to use direct I/O on this file. */
unsigned int direct_io : 1;

/** Can be filled in by open and opendir. It signals the kernel that any
Expand All @@ -68,6 +68,10 @@ struct fuse_file_info {
the file/directory is closed. */
unsigned int keep_cache : 1;

/** Can be filled by open/create, to allow parallel direct writes on this
* file */
unsigned int parallel_direct_writes : 1;

/** Indicates a flush operation. Set in flush operation, also
maybe set in highlevel lock operation and lowlevel release
operation. */
Expand All @@ -93,7 +97,7 @@ struct fuse_file_info {
unsigned int noflush : 1;

/** Padding. Reserved for future use*/
unsigned int padding : 24;
unsigned int padding : 23;
unsigned int padding2 : 32;

/** File handle id. May be filled in by filesystem in create,
Expand Down
3 changes: 2 additions & 1 deletion include/fuse_kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,14 +307,15 @@ struct fuse_file_lock {
* FOPEN_CACHE_DIR: allow caching this directory
* FOPEN_STREAM: the file is stream-like (no file position at all)
* FOPEN_NOFLUSH: don't flush data cache on close (unless FUSE_WRITEBACK_CACHE)
* FOPEN_PARALLEL_DIRECT_WRITES: allow parallel direct writes on the same file
*/
#define FOPEN_DIRECT_IO (1 << 0)
#define FOPEN_KEEP_CACHE (1 << 1)
#define FOPEN_NONSEEKABLE (1 << 2)
#define FOPEN_CACHE_DIR (1 << 3)
#define FOPEN_STREAM (1 << 4)
#define FOPEN_NOFLUSH (1 << 5)

#define FOPEN_PARALLEL_DIRECT_WRITES (1 << 6)
/**
* INIT request/reply flags
*
Expand Down
9 changes: 8 additions & 1 deletion lib/fuse.c
Original file line number Diff line number Diff line change
Expand Up @@ -3145,7 +3145,9 @@ static void fuse_lib_create(fuse_req_t req, fuse_ino_t parent,
fi->direct_io = 1;
if (f->conf.kernel_cache)
fi->keep_cache = 1;

if (fi->direct_io &&
f->conf.parallel_direct_writes)
fi->parallel_direct_writes = 1;
}
}
fuse_finish_interrupt(f, req, &d);
Expand Down Expand Up @@ -3229,6 +3231,10 @@ static void fuse_lib_open(fuse_req_t req, fuse_ino_t ino,
if (f->conf.no_rofd_flush &&
(fi->flags & O_ACCMODE) == O_RDONLY)
fi->noflush = 1;

if (fi->direct_io && f->conf.parallel_direct_writes)
fi->parallel_direct_writes = 1;

}
fuse_finish_interrupt(f, req, &d);
}
Expand Down Expand Up @@ -4653,6 +4659,7 @@ static const struct fuse_opt fuse_lib_opts[] = {
FUSE_LIB_OPT("noforget", remember, -1),
FUSE_LIB_OPT("remember=%u", remember, 0),
FUSE_LIB_OPT("modules=%s", modules, 0),
FUSE_LIB_OPT("parallel_direct_write=%d", parallel_direct_writes, 0),
FUSE_OPT_END
};

Expand Down
2 changes: 2 additions & 0 deletions lib/fuse_lowlevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,8 @@ static void fill_open(struct fuse_open_out *arg,
arg->open_flags |= FOPEN_NONSEEKABLE;
if (f->noflush)
arg->open_flags |= FOPEN_NOFLUSH;
if (f->parallel_direct_writes)
arg->open_flags |= FOPEN_PARALLEL_DIRECT_WRITES;
}

int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
Expand Down

0 comments on commit a5eb7f2

Please sign in to comment.