diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | configure.in | 1 | ||||
-rw-r--r-- | example/fusexmp.c | 26 | ||||
-rw-r--r-- | example/fusexmp_fh.c | 16 | ||||
-rw-r--r-- | include/fuse.h | 15 | ||||
-rw-r--r-- | include/fuse_kernel.h | 14 | ||||
-rw-r--r-- | include/fuse_lowlevel.h | 20 | ||||
-rw-r--r-- | lib/fuse.c | 36 | ||||
-rw-r--r-- | lib/fuse_lowlevel.c | 15 | ||||
-rw-r--r-- | lib/fuse_versionscript | 7 |
10 files changed, 152 insertions, 2 deletions
@@ -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); }; /** @@ -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; |