diff options
Diffstat (limited to 'api/src')
| -rw-r--r-- | api/src/Makefile.am | 2 | ||||
| -rw-r--r-- | api/src/gfapi.aliases | 1 | ||||
| -rw-r--r-- | api/src/gfapi.map | 1 | ||||
| -rw-r--r-- | api/src/glfs-fops.c | 155 | ||||
| -rw-r--r-- | api/src/glfs.h | 39 | 
5 files changed, 197 insertions, 1 deletions
diff --git a/api/src/Makefile.am b/api/src/Makefile.am index 6ed30bc99f6..7f9a7d17b35 100644 --- a/api/src/Makefile.am +++ b/api/src/Makefile.am @@ -19,7 +19,7 @@ libgfapi_la_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \          -I$(top_srcdir)/rpc/xdr/src \          -I$(top_builddir)/rpc/xdr/src \          -DDATADIR=\"$(localstatedir)\" \ -        -D__USE_FILE_OFFSET64 +        -D__USE_FILE_OFFSET64 -D__USE_LARGEFILE64  AM_CFLAGS = -Wall $(GF_CFLAGS) diff --git a/api/src/gfapi.aliases b/api/src/gfapi.aliases index a71422c8577..0e52c38d346 100644 --- a/api/src/gfapi.aliases +++ b/api/src/gfapi.aliases @@ -188,3 +188,4 @@ _pub_glfs_ftruncate _glfs_ftruncate$GFAPI_future  _pub_glfs_ftruncate_async _glfs_ftruncate_async$GFAPI_future  _pub_glfs_discard_async _glfs_discard_async$GFAPI_future  _pub_glfs_zerofill_async _glfs_zerofill_async$GFAPI_future +_pub_glfs_copy_file_range _glfs_copy_file_range$GFAPI_future
\ No newline at end of file diff --git a/api/src/gfapi.map b/api/src/gfapi.map index c47323781fb..1be2953ce9a 100644 --- a/api/src/gfapi.map +++ b/api/src/gfapi.map @@ -255,5 +255,6 @@ GFAPI_future {  		glfs_ftruncate_async;  		glfs_discard_async;  		glfs_zerofill_async; +		glfs_copy_file_range;  } GFAPI_4.1.6; diff --git a/api/src/glfs-fops.c b/api/src/glfs-fops.c index 2a1cc73ccee..f59990aed1f 100644 --- a/api/src/glfs-fops.c +++ b/api/src/glfs-fops.c @@ -1333,6 +1333,161 @@ invalid_fs:  }  ssize_t +pub_glfs_copy_file_range(struct glfs_fd *glfd_in, off64_t *off_in, +                         struct glfs_fd *glfd_out, off64_t *off_out, size_t len, +                         unsigned int flags, struct stat *statbuf, +                         struct stat *prestat, struct stat *poststat) +{ +    xlator_t *subvol = NULL; +    int ret = -1; +    fd_t *fd_in = NULL; +    fd_t *fd_out = NULL; +    struct iatt preiatt = +                    { +                        0, +                    }, +                iattbuf = +                    { +                        0, +                    }, +                postiatt = { +                    0, +                }; +    dict_t *fop_attr = NULL; +    off64_t pos_in; +    off64_t pos_out; + +    DECLARE_OLD_THIS; +    __GLFS_ENTRY_VALIDATE_FD(glfd_in, invalid_fs); +    __GLFS_ENTRY_VALIDATE_FD(glfd_out, invalid_fs); + +    GF_REF_GET(glfd_in); +    GF_REF_GET(glfd_out); + +    if (glfd_in->fs != glfd_out->fs) { +        ret = -1; +        errno = EXDEV; +        goto out; +    } + +    subvol = glfs_active_subvol(glfd_in->fs); +    if (!subvol) { +        ret = -1; +        errno = EIO; +        goto out; +    } + +    fd_in = glfs_resolve_fd(glfd_in->fs, subvol, glfd_in); +    if (!fd_in) { +        ret = -1; +        errno = EBADFD; +        goto out; +    } + +    fd_out = glfs_resolve_fd(glfd_out->fs, subvol, glfd_out); +    if (!fd_out) { +        ret = -1; +        errno = EBADFD; +        goto out; +    } + +    /* +     * This is based on how the vfs layer in the kernel handles +     * copy_file_range call. Upon receiving it follows the +     * below method to consider the offset. +     * if (off_in != NULL) +     *    use the value off_in to perform the op +     * else if off_in == NULL +     *    use the current file offset position to perform the op +     * +     * For gfapi, glfd->offset is used. For a freshly opened +     * fd, the offset is set to 0. +     */ +    if (off_in) +        pos_in = *off_in; +    else +        pos_in = glfd_in->offset; + +    if (off_out) +        pos_out = *off_out; +    else +        pos_out = glfd_out->offset; + +    ret = get_fop_attr_thrd_key(&fop_attr); +    if (ret) +        gf_msg_debug("gfapi", 0, "Getting leaseid from thread failed"); + +    ret = syncop_copy_file_range(subvol, fd_in, pos_in, fd_out, pos_out, len, +                                 flags, &iattbuf, &preiatt, &postiatt, fop_attr, +                                 NULL); +    DECODE_SYNCOP_ERR(ret); + +    if (ret >= 0) { +        pos_in += ret; +        pos_out += ret; + +        if (off_in) +            *off_in = pos_in; +        if (off_out) +            *off_out = pos_out; + +        if (statbuf) +            glfs_iatt_to_stat(glfd_in->fs, &iattbuf, statbuf); +        if (prestat) +            glfs_iatt_to_stat(glfd_in->fs, &preiatt, prestat); +        if (poststat) +            glfs_iatt_to_stat(glfd_in->fs, &postiatt, poststat); +    } + +    if (ret <= 0) +        goto out; + +    /* +     * If *off_in is NULL, then there is no offset info that can +     * obtained from the input argument. Hence follow below method. +     *  If *off_in is NULL, then +     *     glfd->offset = offset + ret; +     * else +     *     do nothing. +     * +     * According to the man page of copy_file_range, if off_in is +     * NULL, then the offset of the source file is advanced by +     * the return value of the fop. The same applies to off_out as +     * well. Otherwise, if *off_in is not NULL, then the offset +     * is not advanced by the filesystem. The entity which sends +     * the copy_file_range call is supposed to advance the offset +     * value in its buffer (pointed to by *off_in or *off_out) +     * by the return value of copy_file_range. +     */ +    if (!off_in) +        glfd_in->offset += ret; + +    if (!off_out) +        glfd_out->offset += ret; + +out: +    if (fd_in) +        fd_unref(fd_in); +    if (fd_out) +        fd_unref(fd_out); +    if (glfd_in) +        GF_REF_PUT(glfd_in); +    if (glfd_out) +        GF_REF_PUT(glfd_out); +    if (fop_attr) +        dict_unref(fop_attr); + +    glfs_subvol_done(glfd_in->fs, subvol); + +    __GLFS_EXIT_FS; + +invalid_fs: +    return ret; +} + +GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_copy_file_range, future); + +ssize_t  pub_glfs_pwritev(struct glfs_fd *glfd, const struct iovec *iovec, int iovcnt,                   off_t offset, int flags)  { diff --git a/api/src/glfs.h b/api/src/glfs.h index cd642a5ea20..160a784222f 100644 --- a/api/src/glfs.h +++ b/api/src/glfs.h @@ -42,6 +42,38 @@  #include <sys/statvfs.h>  #include <inttypes.h> +/* + * For off64_t to be defined, we need both + * __USE_LARGEFILE64 to be true and __off64_t_defnined to be + * false. But, making __USE_LARGEFILE64 true causes other issues + * such as redinition of stat and fstat to stat64 and fstat64 + * respectively which again causes compilation issues. + * Without off64_t being defined, this will not compile as + * copy_file_range uses off64_t. Hence define it here. First + * check whether __off64_t_defined is true or not. <unistd.h> + * sets that flag when it defines off64_t. If __off64_t_defined + * is false and __USE_FILE_OFFSET64 is true, then go on to define + * off64_t using __off64_t. + */ +#ifndef GF_BSD_HOST_OS +#if defined(__USE_FILE_OFFSET64) && !defined(__off64_t_defined) +typedef __off64_t off64_t; +#endif /* defined(__USE_FILE_OFFSET64) && !defined(__off64_t_defined) */ +#else +#include <stdio.h> +#ifndef _OFF64_T_DECLARED +/* + * Including <stdio.h> (done above) should actually define + * _OFF64_T_DECLARED with off64_t data type being available + * for consumption. But, off64_t data type is not recognizable + * for FreeBSD versions less than 11. Hence, int64_t is typedefed + * to off64_t. + */ +#define _OFF64_T_DECLARED +typedef int64_t off64_t; +#endif /* _OFF64_T_DECLARED */ +#endif /* GF_BSD_HOST_OS */ +  #if defined(HAVE_SYS_ACL_H) || (defined(USE_POSIX_ACLS) && USE_POSIX_ACLS)  #include <sys/acl.h>  #else @@ -594,6 +626,13 @@ off_t  glfs_lseek(glfs_fd_t *fd, off_t offset, int whence) __THROW      GFAPI_PUBLIC(glfs_lseek, 3.4.0); +ssize_t +glfs_copy_file_range(struct glfs_fd *glfd_in, off64_t *off_in, +                     struct glfs_fd *glfd_out, off64_t *off_out, size_t len, +                     unsigned int flags, struct stat *statbuf, +                     struct stat *prestat, struct stat *poststat) __THROW +    GFAPI_PUBLIC(glfs_copy_file_range, future); +  int  glfs_truncate(glfs_t *fs, const char *path, off_t length) __THROW      GFAPI_PUBLIC(glfs_truncate, 3.7.15);  | 
