aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;