diff --git a/include/fuse-lite/fuse_common.h b/include/fuse-lite/fuse_common.h index 819bb8d7..7139b9b1 100644 --- a/include/fuse-lite/fuse_common.h +++ b/include/fuse-lite/fuse_common.h @@ -43,6 +43,8 @@ extern "C" { #define FUSE_CAP_DONT_MASK (1 << 6) #endif +#define FUSE_CAP_BIG_WRITES (1 << 5) + /** * Information about open files * @@ -116,19 +118,12 @@ struct fuse_conn_info { */ unsigned max_readahead; -#ifdef POSIXACLS unsigned capable; unsigned want; /** * For future use. */ unsigned reserved[25]; -#else - /** - * For future use. - */ - unsigned reserved[27]; -#endif }; struct fuse_session; diff --git a/include/fuse-lite/fuse_kernel.h b/include/fuse-lite/fuse_kernel.h index 59c72b8d..69641b65 100644 --- a/include/fuse-lite/fuse_kernel.h +++ b/include/fuse-lite/fuse_kernel.h @@ -130,10 +130,12 @@ struct fuse_file_lock { /** * INIT request/reply flags + * FUSE_BIG_WRITES: allow big writes to be issued to the file system * FUSE_DONT_MASK: don't apply umask to file mode on create operations */ #define FUSE_ASYNC_READ (1 << 0) #define FUSE_POSIX_LOCKS (1 << 1) +#define FUSE_BIG_WRITES (1 << 5) #define FUSE_DONT_MASK (1 << 6) /** diff --git a/include/ntfs-3g/param.h b/include/ntfs-3g/param.h index 985fdb75..4480eea8 100644 --- a/include/ntfs-3g/param.h +++ b/include/ntfs-3g/param.h @@ -50,6 +50,19 @@ enum { /* maximum cluster size for allowing compression for new files */ #define MAX_COMPRESSION_CLUSTER_SIZE 4096 +/* + * Use of big write buffers + * + * With small volumes, the cluster allocator may fail to allocate + * enough clusters when the volume is nearly full. At most a run + * can be allocated per bitmap chunk. So, there is a danger when the + * number of chunks (capacity/(32768*clsiz)) is less than the number + * of clusters in the biggest write buffer (131072/clsiz). Hence + * a safe minimal capacity is 4GB + */ + +#define SAFE_CAPACITY_FOR_BIG_WRITES 0x100000000LL + /* * Parameters for runlists */ diff --git a/libfuse-lite/fuse_lowlevel.c b/libfuse-lite/fuse_lowlevel.c index fdd18152..492b8d87 100644 --- a/libfuse-lite/fuse_lowlevel.c +++ b/libfuse-lite/fuse_lowlevel.c @@ -1043,6 +1043,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) if (arg->flags & FUSE_DONT_MASK) f->conn.capable |= FUSE_CAP_DONT_MASK; #endif + if (arg->flags & FUSE_BIG_WRITES) + f->conn.capable |= FUSE_CAP_BIG_WRITES; } else { f->conn.async_read = 0; f->conn.max_readahead = 0; @@ -1087,6 +1089,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) if (f->conn.want & FUSE_CAP_DONT_MASK) outarg.flags |= FUSE_DONT_MASK; #endif + if (f->conn.want & FUSE_CAP_BIG_WRITES) + outarg.flags |= FUSE_BIG_WRITES; outarg.max_readahead = f->conn.max_readahead; outarg.max_write = f->conn.max_write; diff --git a/src/lowntfs-3g.c b/src/lowntfs-3g.c index 9fa177f3..578aac49 100644 --- a/src/lowntfs-3g.c +++ b/src/lowntfs-3g.c @@ -557,7 +557,8 @@ int ntfs_macfuse_setchgtime(const char *path, const struct timespec *tv) } #endif /* defined(__APPLE__) || defined(__DARWIN__) */ -#if defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__)) +#if defined(FUSE_CAP_DONT_MASK) || defined(FUSE_CAP_BIG_WRITES) \ + || (defined(__APPLE__) || defined(__DARWIN__)) static void ntfs_init(void *userdata __attribute__((unused)), struct fuse_conn_info *conn) { @@ -568,6 +569,12 @@ static void ntfs_init(void *userdata __attribute__((unused)), /* request umask not to be enforced by fuse */ conn->want |= FUSE_CAP_DONT_MASK; #endif /* defined FUSE_CAP_DONT_MASK */ +#ifdef FUSE_CAP_BIG_WRITES + if (ctx->big_writes + && ((ctx->vol->nr_clusters << ctx->vol->cluster_size_bits) + >= SAFE_CAPACITY_FOR_BIG_WRITES)) + conn->want |= FUSE_CAP_BIG_WRITES; +#endif } #endif /* defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__)) */ @@ -3364,7 +3371,8 @@ static struct fuse_lowlevel_ops ntfs_3g_ops = { .setbkuptime = ntfs_macfuse_setbkuptime, .setchgtime = ntfs_macfuse_setchgtime, #endif /* defined(__APPLE__) || defined(__DARWIN__) */ -#if defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__)) +#if defined(FUSE_CAP_DONT_MASK) || defined(FUSE_CAP_BIG_WRITES) \ + || (defined(__APPLE__) || defined(__DARWIN__)) .init = ntfs_init #endif }; diff --git a/src/ntfs-3g.8.in b/src/ntfs-3g.8.in index 562aa297..01f9e123 100644 --- a/src/ntfs-3g.8.in +++ b/src/ntfs-3g.8.in @@ -284,6 +284,11 @@ This option disables creating new transparently compressed files in directories marked for compression. Existing compressed files can still be read and updated. Currently this is the default option. .TP +.B big_writes +This option prevents fuse from splitting write buffers into 4K chunks, +enabling big write buffers to be transferred from the application in a +single step (up to some system limit, generally 128K bytes). +.TP .B debug Makes ntfs-3g to print a lot of debug output from libntfs-3g and FUSE. .TP diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index 956f04d7..c1497b95 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -635,7 +635,8 @@ int ntfs_macfuse_setchgtime(const char *path, const struct timespec *tv) } #endif /* defined(__APPLE__) || defined(__DARWIN__) */ -#if defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__)) +#if defined(FUSE_CAP_DONT_MASK) || defined(FUSE_CAP_BIG_WRITES) \ + || (defined(__APPLE__) || defined(__DARWIN__)) static void *ntfs_init(struct fuse_conn_info *conn) { #if defined(__APPLE__) || defined(__DARWIN__) @@ -645,6 +646,12 @@ static void *ntfs_init(struct fuse_conn_info *conn) /* request umask not to be enforced by fuse */ conn->want |= FUSE_CAP_DONT_MASK; #endif /* defined FUSE_CAP_DONT_MASK */ +#ifdef FUSE_CAP_BIG_WRITES + if (ctx->big_writes + && ((ctx->vol->nr_clusters << ctx->vol->cluster_size_bits) + >= SAFE_CAPACITY_FOR_BIG_WRITES)) + conn->want |= FUSE_CAP_BIG_WRITES; +#endif return NULL; } #endif /* defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__)) */ @@ -3283,7 +3290,8 @@ static struct fuse_operations ntfs_3g_ops = { .setbkuptime = ntfs_macfuse_setbkuptime, .setchgtime = ntfs_macfuse_setchgtime, #endif /* defined(__APPLE__) || defined(__DARWIN__) */ -#if defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__)) +#if defined(FUSE_CAP_DONT_MASK) || defined(FUSE_CAP_BIG_WRITES) \ + || (defined(__APPLE__) || defined(__DARWIN__)) .init = ntfs_init #endif }; diff --git a/src/ntfs-3g_common.c b/src/ntfs-3g_common.c index e696f65a..85d267d6 100644 --- a/src/ntfs-3g_common.c +++ b/src/ntfs-3g_common.c @@ -99,6 +99,7 @@ const struct DEFOPTION optionlist[] = { { "norecover", OPT_NORECOVER, FLGOPT_BOGUS }, { "remove_hiberfile", OPT_REMOVE_HIBERFILE, FLGOPT_BOGUS }, { "sync", OPT_SYNC, FLGOPT_BOGUS | FLGOPT_APPEND }, + { "big_writes", OPT_BIG_WRITES, FLGOPT_BOGUS }, { "locale", OPT_LOCALE, FLGOPT_STRING }, { "nfconv", OPT_NFCONV, FLGOPT_BOGUS }, { "nonfconv", OPT_NONFCONV, FLGOPT_BOGUS }, @@ -314,6 +315,11 @@ char *parse_mount_options(ntfs_fuse_context_t *ctx, case OPT_SYNC : ctx->sync = TRUE; break; +#ifdef FUSE_CAP_BIG_WRITES + case OPT_BIG_WRITES : + ctx->big_writes = TRUE; + break; +#endif case OPT_LOCALE : ntfs_set_char_encoding(val); break; diff --git a/src/ntfs-3g_common.h b/src/ntfs-3g_common.h index 978569da..f1ac1e5a 100644 --- a/src/ntfs-3g_common.h +++ b/src/ntfs-3g_common.h @@ -73,6 +73,7 @@ enum { OPT_NORECOVER, OPT_REMOVE_HIBERFILE, OPT_SYNC, + OPT_BIG_WRITES, OPT_LOCALE, OPT_NFCONV, OPT_NONFCONV, @@ -127,6 +128,7 @@ typedef struct { BOOL recover; BOOL hiberfile; BOOL sync; + BOOL big_writes; BOOL debug; BOOL no_detach; BOOL blkdev;