aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorGravatar Anatol Pomozov <anatol.pomozov@gmail.com>2012-04-22 18:49:35 -0700
committerGravatar Miklos Szeredi <mszeredi@suse.cz>2012-06-18 13:32:43 +0200
commit96ac0e5d76db3714b7c8d37956f6e6b1d804a01a (patch)
tree4cd918bccb54e30edca0dadbe2b44a43b7ef1c91 /lib
parent46b9c3326d50aebe52c33d63885b83a47a2e74ea (diff)
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.
Diffstat (limited to 'lib')
-rw-r--r--lib/fuse.c36
-rw-r--r--lib/fuse_lowlevel.c15
-rw-r--r--lib/fuse_versionscript7
3 files changed, 57 insertions, 1 deletions
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;