aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnatol Pomozov <anatol.pomozov@gmail.com>2012-04-22 18:49:35 -0700
committerMiklos Szeredi <mszeredi@suse.cz>2012-06-18 13:32:43 +0200
commit96ac0e5d76db3714b7c8d37956f6e6b1d804a01a (patch)
tree4cd918bccb54e30edca0dadbe2b44a43b7ef1c91
parent46b9c3326d50aebe52c33d63885b83a47a2e74ea (diff)
downloadandroid_external_fuse-96ac0e5d76db3714b7c8d37956f6e6b1d804a01a.tar.gz
android_external_fuse-96ac0e5d76db3714b7c8d37956f6e6b1d804a01a.tar.bz2
android_external_fuse-96ac0e5d76db3714b7c8d37956f6e6b1d804a01a.zip
Add FALLOCATE operation
fallocate filesystem operation preallocates media space for the given file. If fallocate returns success then any subsequent write to the given range never fails with 'not enough space' error.
-rw-r--r--ChangeLog4
-rw-r--r--configure.in1
-rw-r--r--example/fusexmp.c26
-rw-r--r--example/fusexmp_fh.c16
-rw-r--r--include/fuse.h15
-rw-r--r--include/fuse_kernel.h14
-rw-r--r--include/fuse_lowlevel.h20
-rw-r--r--lib/fuse.c36
-rw-r--r--lib/fuse_lowlevel.c15
-rw-r--r--lib/fuse_versionscript7
10 files changed, 152 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index a60ac12..d465b3c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2012-04-24 Miklos Szeredi <miklos@szeredi.hu>
+
+ * Add fallocate operation. Patch by Anatol Pomozov
+
2012-05-16 Miklos Szeredi <miklos@szeredi.hu>
* Linking to a library that uses threads requires the application
diff --git a/configure.in b/configure.in
index e9ce79b..a7448df 100644
--- a/configure.in
+++ b/configure.in
@@ -57,6 +57,7 @@ if test "$enable_mtab" = "no"; then
fi
AC_CHECK_FUNCS([fork setxattr fdatasync splice vmsplice utimensat])
+AC_CHECK_FUNCS([posix_fallocate])
AC_CHECK_MEMBERS([struct stat.st_atim])
AC_CHECK_MEMBERS([struct stat.st_atimespec])
diff --git a/example/fusexmp.c b/example/fusexmp.c
index 20a7116..dca8a46 100644
--- a/example/fusexmp.c
+++ b/example/fusexmp.c
@@ -310,6 +310,29 @@ static int xmp_fsync(const char *path, int isdatasync,
return 0;
}
+#ifdef HAVE_POSIX_FALLOCATE
+static int xmp_fallocate(const char *path, int mode,
+ off_t offset, off_t length, struct fuse_file_info *fi)
+{
+ int fd;
+ int res;
+
+ (void) fi;
+
+ if (mode)
+ return -EOPNOTSUPP;
+
+ fd = open(path, O_WRONLY);
+ if (fd == -1)
+ return -errno;
+
+ res = -posix_fallocate(fd, offset, length);
+
+ close(fd);
+ return res;
+}
+#endif
+
#ifdef HAVE_SETXATTR
/* xattr operations are optional and can safely be left unimplemented */
static int xmp_setxattr(const char *path, const char *name, const char *value,
@@ -371,6 +394,9 @@ static struct fuse_operations xmp_oper = {
.statfs = xmp_statfs,
.release = xmp_release,
.fsync = xmp_fsync,
+#ifdef HAVE_POSIX_FALLOCATE
+ .fallocate = xmp_fallocate,
+#endif
#ifdef HAVE_SETXATTR
.setxattr = xmp_setxattr,
.getxattr = xmp_getxattr,
diff --git a/example/fusexmp_fh.c b/example/fusexmp_fh.c
index d79ff37..1ba9dbc 100644
--- a/example/fusexmp_fh.c
+++ b/example/fusexmp_fh.c
@@ -439,6 +439,19 @@ static int xmp_fsync(const char *path, int isdatasync,
return 0;
}
+#ifdef HAVE_POSIX_FALLOCATE
+static int xmp_fallocate(const char *path, int mode,
+ off_t offset, off_t length, struct fuse_file_info *fi)
+{
+ (void) path;
+
+ if (mode)
+ return -EOPNOTSUPP;
+
+ return -posix_fallocate(fi->fh, offset, length);
+}
+#endif
+
#ifdef HAVE_SETXATTR
/* xattr operations are optional and can safely be left unimplemented */
static int xmp_setxattr(const char *path, const char *name, const char *value,
@@ -529,6 +542,9 @@ static struct fuse_operations xmp_oper = {
.flush = xmp_flush,
.release = xmp_release,
.fsync = xmp_fsync,
+#ifdef HAVE_POSIX_FALLOCATE
+ .fallocate = xmp_fallocate,
+#endif
#ifdef HAVE_SETXATTR
.setxattr = xmp_setxattr,
.getxattr = xmp_getxattr,
diff --git a/include/fuse.h b/include/fuse.h
index 36b168c..c657e67 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -575,6 +575,19 @@ struct fuse_operations {
* Introduced in version 2.9
*/
int (*flock) (const char *, struct fuse_file_info *, int op);
+
+ /**
+ * Allocates space for an open file
+ *
+ * This function ensures that required space is allocated for specified
+ * file. If this function returns success then any subsequent write
+ * request to specified range is guaranteed not to fail because of lack
+ * of space on the file system media.
+ *
+ * Introduced in version 2.9.1
+ */
+ int (*fallocate) (const char *, int, off_t, off_t,
+ struct fuse_file_info *);
};
/** Extra context that may be needed by some filesystems
@@ -870,6 +883,8 @@ int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, int cmd, void *arg,
int fuse_fs_poll(struct fuse_fs *fs, const char *path,
struct fuse_file_info *fi, struct fuse_pollhandle *ph,
unsigned *reventsp);
+int fuse_fs_fallocate(struct fuse_fs *fs, const char *path, int mode,
+ off_t offset, off_t length, struct fuse_file_info *fi);
void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn);
void fuse_fs_destroy(struct fuse_fs *fs);
diff --git a/include/fuse_kernel.h b/include/fuse_kernel.h
index 1ce072c..c632b58 100644
--- a/include/fuse_kernel.h
+++ b/include/fuse_kernel.h
@@ -80,6 +80,9 @@
* 7.18
* - add FUSE_IOCTL_DIR flag
* - add FUSE_NOTIFY_DELETE
+ *
+ * 7.19
+ * - add FUSE_FALLOCATE
*/
#ifndef _LINUX_FUSE_H
@@ -116,7 +119,7 @@
#define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 18
+#define FUSE_KERNEL_MINOR_VERSION 19
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
@@ -309,6 +312,7 @@ enum fuse_opcode {
FUSE_POLL = 40,
FUSE_NOTIFY_REPLY = 41,
FUSE_BATCH_FORGET = 42,
+ FUSE_FALLOCATE = 43,
/* CUSE specific operations */
CUSE_INIT = 4096,
@@ -602,6 +606,14 @@ struct fuse_notify_poll_wakeup_out {
__u64 kh;
};
+struct fuse_fallocate_in {
+ __u64 fh;
+ __u64 offset;
+ __u64 length;
+ __u32 mode;
+ __u32 padding;
+};
+
struct fuse_in_header {
__u32 len;
__u32 opcode;
diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h
index 3ecc46e..2036717 100644
--- a/include/fuse_lowlevel.h
+++ b/include/fuse_lowlevel.h
@@ -996,6 +996,26 @@ struct fuse_lowlevel_ops {
*/
void (*flock) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi, int op);
+
+ /**
+ * Allocate requested space. If this function returns success then
+ * subsequent writes to the specified range shall not fail due to the lack
+ * of free space on the file system storage media.
+ *
+ * Introduced in version 2.9
+ *
+ * Valid replies:
+ * fuse_reply_err
+ *
+ * @param req request handle
+ * @param ino the inode number
+ * @param offset starting point for allocated region
+ * @param length size of allocated region
+ * @param mode determines the operation to be performed on the given range,
+ * see fallocate(2)
+ */
+ void (*fallocate) (fuse_req_t req, fuse_ino_t ino, int mode,
+ off_t offset, off_t length, struct fuse_file_info *fi);
};
/**
diff --git a/lib/fuse.c b/lib/fuse.c
index 4922361..644878b 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -2281,6 +2281,23 @@ int fuse_fs_poll(struct fuse_fs *fs, const char *path,
return -ENOSYS;
}
+int fuse_fs_fallocate(struct fuse_fs *fs, const char *path, int mode,
+ off_t offset, off_t length, struct fuse_file_info *fi)
+{
+ fuse_get_context()->private_data = fs->user_data;
+ if (fs->op.fallocate) {
+ if (fs->debug)
+ fprintf(stderr, "fallocate %s mode %x, offset: %llu, length: %llu\n",
+ path,
+ mode,
+ (unsigned long long) offset,
+ (unsigned long long) length);
+
+ return fs->op.fallocate(path, mode, offset, length, fi);
+ } else
+ return -ENOSYS;
+}
+
static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
{
struct node *node;
@@ -3990,6 +4007,24 @@ static void fuse_lib_poll(fuse_req_t req, fuse_ino_t ino,
reply_err(req, err);
}
+static void fuse_lib_fallocate(fuse_req_t req, fuse_ino_t ino, int mode,
+ off_t offset, off_t length, struct fuse_file_info *fi)
+{
+ struct fuse *f = req_fuse_prepare(req);
+ struct fuse_intr_data d;
+ char *path;
+ int err;
+
+ err = get_path_nullok(f, ino, &path);
+ if (!err) {
+ fuse_prepare_interrupt(f, req, &d);
+ err = fuse_fs_fallocate(f->fs, path, mode, offset, length, fi);
+ fuse_finish_interrupt(f, req, &d);
+ free_path(f, ino, path);
+ }
+ reply_err(req, err);
+}
+
static int clean_delay(struct fuse *f)
{
/*
@@ -4084,6 +4119,7 @@ static struct fuse_lowlevel_ops fuse_path_ops = {
.bmap = fuse_lib_bmap,
.ioctl = fuse_lib_ioctl,
.poll = fuse_lib_poll,
+ .fallocate = fuse_lib_fallocate,
};
int fuse_notify_poll(struct fuse_pollhandle *ph)
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index 2282ccf..305bbbf 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -1717,6 +1717,20 @@ static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
}
}
+static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+ struct fuse_fallocate_in *arg = (struct fuse_fallocate_in *) inarg;
+ struct fuse_file_info fi;
+
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
+
+ if (req->f->op.fallocate)
+ req->f->op.fallocate(req, nodeid, arg->mode, arg->offset, arg->length, &fi);
+ else
+ fuse_reply_err(req, ENOSYS);
+}
+
static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
@@ -2267,6 +2281,7 @@ static struct {
[FUSE_BMAP] = { do_bmap, "BMAP" },
[FUSE_IOCTL] = { do_ioctl, "IOCTL" },
[FUSE_POLL] = { do_poll, "POLL" },
+ [FUSE_FALLOCATE] = { do_fallocate, "FALLOCATE" },
[FUSE_DESTROY] = { do_destroy, "DESTROY" },
[FUSE_NOTIFY_REPLY] = { (void *) 1, "NOTIFY_REPLY" },
[FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" },
diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript
index 2d110fb..8d91887 100644
--- a/lib/fuse_versionscript
+++ b/lib/fuse_versionscript
@@ -196,7 +196,12 @@ FUSE_2.9 {
fuse_clean_cache;
fuse_lowlevel_notify_delete;
fuse_fs_flock;
+} FUSE_2.8;
+
+FUSE_2.9.1 {
+ global:
+ fuse_fs_fallocate;
local:
*;
-} FUSE_2.8;
+} FUSE_2.9;