From: Jevon Qiao Date: Mon, 15 Jun 2015 02:15:45 +0000 (+0800) Subject: libcephfs: add ceph_p{read,write}v X-Git-Tag: v9.0.3~161^2~2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=f6bf6c2a969b3d79179d1f14375ed9dfa3fd49ea;p=ceph.git libcephfs: add ceph_p{read,write}v Add interfaces in libcephfs to enable users to read/write data via iovec structure. Signed-off-by: Jevon Qiao --- diff --git a/src/client/Client.cc b/src/client/Client.cc index a027528eb7cd..02ea319bbfe8 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -22,6 +22,7 @@ #include #include #include +#include #if defined(__linux__) #include @@ -239,11 +240,6 @@ Client::~Client() delete logger; } - - - - - void Client::tear_down_cache() { // fd's @@ -7133,6 +7129,11 @@ int Client::read(int fd, char *buf, loff_t size, loff_t offset) return r; } +int Client::preadv(int fd, const struct iovec *iov, int iovcnt, loff_t offset) +{ + return _preadv_pwritev(fd, iov, iovcnt, offset, false); +} + int Client::_read(Fh *f, int64_t offset, uint64_t size, bufferlist *bl) { const md_config_t *conf = cct->_conf; @@ -7450,13 +7451,63 @@ int Client::write(int fd, const char *buf, loff_t size, loff_t offset) if (fh->flags & O_PATH) return -EBADF; #endif - int r = _write(fh, offset, size, buf); + int r = _write(fh, offset, size, buf, NULL, 0); ldout(cct, 3) << "write(" << fd << ", \"...\", " << size << ", " << offset << ") = " << r << dendl; return r; } +int Client::pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) +{ + return _preadv_pwritev(fd, iov, iovcnt, offset, true); +} + +int Client::_preadv_pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset, bool write) +{ + Mutex::Locker lock(client_lock); + tout(cct) << fd << std::endl; + tout(cct) << offset << std::endl; + + Fh *fh = get_filehandle(fd); + if (!fh) + return -EBADF; +#if defined(__linux__) && defined(O_PATH) + if (fh->flags & O_PATH) + return -EBADF; +#endif + loff_t totallen = 0; + for (int i = 0; i < iovcnt; i++) { + totallen += iov[i].iov_len; + } + if (write) { + int w = _write(fh, offset, totallen, NULL, iov, iovcnt); + ldout(cct, 3) << "write(" << fd << ", \"...\", " << totallen << ", " << offset << ") = " << w << dendl; + return w; + } else { + bufferlist bl; + int r = _read(fh, offset, totallen, &bl); + ldout(cct, 3) << "read(" << fd << ", " << offset << ") = " << r << dendl; + int bufoff = 0; + uint32_t rlen = 0; + for (int j = 0, tmplen = r; j < iovcnt && tmplen > 0; j++) { + /* + * This piece of code aims to handle the case that bufferlist does no have enough data + * to fill in the iov + */ + if (tmplen < iov[j].iov_len) { + bl.copy(bufoff, tmplen, (char *)iov[j].iov_base); + break; + } else { + bl.copy(bufoff, iov[j].iov_len, (char *)iov[j].iov_base); + } + tmplen -= iov[j].iov_len; + bufoff += iov[j].iov_len; + } + return r; + } +} -int Client::_write(Fh *f, int64_t offset, uint64_t size, const char *buf) +int Client::_write(Fh *f, int64_t offset, uint64_t size, const char *buf, + const struct iovec *iov, int iovcnt) { if ((uint64_t)(offset+size) > mdsmap->get_max_filesize()) //too large! return -EFBIG; @@ -7508,10 +7559,20 @@ int Client::_write(Fh *f, int64_t offset, uint64_t size, const char *buf) } // copy into fresh buffer (since our write may be resub, async) - bufferptr bp; - if (size > 0) bp = buffer::copy(buf, size); bufferlist bl; - bl.push_back( bp ); + bufferptr *bparr; + if (buf) { + bufferptr bp; + if (size > 0) bp = buffer::copy(buf, size); + bl.push_back( bp ); + } else if (iov){ + //iov case + bparr = new bufferptr[iovcnt]; + for (int i = 0; i < iovcnt; i++) { + if (iov[i].iov_len > 0) bparr[i] = buffer::copy((char*)iov[i].iov_base, iov[i].iov_len); + bl.push_back( bparr[i] ); + } + } utime_t lat; uint64_t totalwritten; @@ -7659,6 +7720,9 @@ done: } put_cap_ref(in, CEPH_CAP_FILE_WR); + if (buf == NULL && iov != NULL) { + delete[] bparr; + } return r; } @@ -10205,7 +10269,7 @@ int Client::ll_write(Fh *fh, loff_t off, loff_t len, const char *data) tout(cct) << off << std::endl; tout(cct) << len << std::endl; - int r = _write(fh, off, len, data); + int r = _write(fh, off, len, data, NULL, 0); ldout(cct, 3) << "ll_write " << fh << " " << off << "~" << len << " = " << r << dendl; return r; diff --git a/src/client/Client.h b/src/client/Client.h index 4f1b77c77531..a1ad18c417cd 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -678,7 +678,9 @@ private: bool *created = NULL, int uid=-1, int gid=-1); loff_t _lseek(Fh *fh, loff_t offset, int whence); int _read(Fh *fh, int64_t offset, uint64_t size, bufferlist *bl); - int _write(Fh *fh, int64_t offset, uint64_t size, const char *buf); + int _write(Fh *fh, int64_t offset, uint64_t size, const char *buf, + const struct iovec *iov, int iovcnt); + int _preadv_pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset, bool write); int _flush(Fh *fh); int _fsync(Fh *fh, bool syncdataonly); int _sync_fs(); @@ -846,7 +848,9 @@ public: int close(int fd); loff_t lseek(int fd, loff_t offset, int whence); int read(int fd, char *buf, loff_t size, loff_t offset=-1); + int preadv(int fd, const struct iovec *iov, int iovcnt, loff_t offset=-1); int write(int fd, const char *buf, loff_t size, loff_t offset=-1); + int pwritev(int fd, const struct iovec *iov, int iovcnt, loff_t offset=-1); int fake_write_size(int fd, loff_t size); int ftruncate(int fd, loff_t size); int fsync(int fd, bool syncdataonly); diff --git a/src/include/cephfs/libcephfs.h b/src/include/cephfs/libcephfs.h index 26e09a288e77..45585f494be7 100644 --- a/src/include/cephfs/libcephfs.h +++ b/src/include/cephfs/libcephfs.h @@ -799,6 +799,19 @@ int64_t ceph_lseek(struct ceph_mount_info *cmount, int fd, int64_t offset, int w */ int ceph_read(struct ceph_mount_info *cmount, int fd, char *buf, int64_t size, int64_t offset); +/** + * Read data from the file. + * @param cmount the ceph mount handle to use for performing the read. + * @param fd the file descriptor of the open file to read from. + * @param iov the iov structure to read data into + * @param iovcnt the number of items that iov includes + * @param offset the offset in the file to read from. If this value is negative, the + * function reads from the current offset of the file descriptor. + * @returns the number of bytes read into buf, or a negative error code on failure. + */ +int ceph_preadv(struct ceph_mount_info *cmount, int fd, const struct iovec *iov, int iovcnt, + int64_t offset); + /** * Write data to a file. * @@ -813,6 +826,20 @@ int ceph_read(struct ceph_mount_info *cmount, int fd, char *buf, int64_t size, i int ceph_write(struct ceph_mount_info *cmount, int fd, const char *buf, int64_t size, int64_t offset); +/** + * Write data to a file. + * + * @param cmount the ceph mount handle to use for performing the write. + * @param fd the file descriptor of the open file to write to + * @param iov the iov structure to read data into + * @param iovcnt the number of items that iov includes + * @param offset the offset of the file write into. If this value is negative, the + * function writes to the current offset of the file descriptor. + * @returns the number of bytes written, or a negative error code + */ +int ceph_pwritev(struct ceph_mount_info *cmount, int fd, const struct iovec *iov, int iovcnt, + int64_t offset); + /** * Truncate a file to the given size. * diff --git a/src/libcephfs.cc b/src/libcephfs.cc index aa387ffd6948..13d85c7e2814 100644 --- a/src/libcephfs.cc +++ b/src/libcephfs.cc @@ -812,6 +812,14 @@ extern "C" int ceph_read(struct ceph_mount_info *cmount, int fd, char *buf, return cmount->get_client()->read(fd, buf, size, offset); } +extern "C" int ceph_preadv(struct ceph_mount_info *cmount, int fd, + const struct iovec *iov, int iovcnt, int64_t offset) +{ + if (!cmount->is_mounted()) + return -ENOTCONN; + return cmount->get_client()->preadv(fd, iov, iovcnt, offset); +} + extern "C" int ceph_write(struct ceph_mount_info *cmount, int fd, const char *buf, int64_t size, int64_t offset) { @@ -820,6 +828,14 @@ extern "C" int ceph_write(struct ceph_mount_info *cmount, int fd, const char *bu return cmount->get_client()->write(fd, buf, size, offset); } +extern "C" int ceph_pwritev(struct ceph_mount_info *cmount, int fd, + const struct iovec *iov, int iovcnt, int64_t offset) +{ + if (!cmount->is_mounted()) + return -ENOTCONN; + return cmount->get_client()->pwritev(fd, iov, iovcnt, offset); +} + extern "C" int ceph_ftruncate(struct ceph_mount_info *cmount, int fd, int64_t size) { if (!cmount->is_mounted())