From 4143c6e9720b81bd928ee7f0d8055445cec4951b Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 9 Feb 2018 07:39:56 -0500 Subject: [PATCH] client: clamp I/O sizes to INT_MAX when we can't return larger values We have several API functions that allow the caller to request I/Os larger than INT_MAX bytes, but that return an int. Ensure that we don't try to do more I/O than we can represent in the return value. Tracker: http://tracker.ceph.com/issues/22948 Signed-off-by: Jeff Layton --- src/client/Client.cc | 28 +++++++++++++++++++++++----- src/client/Client.h | 3 ++- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/client/Client.cc b/src/client/Client.cc index a121a894487e0..91b3808e9a29c 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -8691,6 +8691,8 @@ int Client::read(int fd, char *buf, loff_t size, loff_t offset) return -EBADF; #endif bufferlist bl; + /* We can't return bytes written larger than INT_MAX, clamp size to that */ + size = std::min(size, (loff_t)INT_MAX); int r = _read(f, offset, size, &bl); ldout(cct, 3) << "read(" << fd << ", " << (void*)buf << ", " << size << ", " << offset << ") = " << r << dendl; if (r >= 0) { @@ -9010,7 +9012,9 @@ 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, NULL, 0); + /* We can't return bytes written larger than INT_MAX, clamp size to that */ + size = std::min(size, (loff_t)INT_MAX); + int r = _write(fh, offset, size, buf, NULL, false); ldout(cct, 3) << "write(" << fd << ", \"...\", " << size << ", " << offset << ") = " << r << dendl; return r; } @@ -9023,7 +9027,8 @@ int Client::pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) } int64_t Client::_preadv_pwritev_locked(Fh *fh, const struct iovec *iov, - unsigned iovcnt, int64_t offset, bool write) + unsigned iovcnt, int64_t offset, bool write, + bool clamp_to_int) { #if defined(__linux__) && defined(O_PATH) if (fh->flags & O_PATH) @@ -9033,6 +9038,15 @@ int64_t Client::_preadv_pwritev_locked(Fh *fh, const struct iovec *iov, for (unsigned i = 0; i < iovcnt; i++) { totallen += iov[i].iov_len; } + + /* + * Some of the API functions take 64-bit size values, but only return + * 32-bit signed integers. Clamp the I/O sizes in those functions so that + * we don't do I/Os larger than the values we can return. + */ + if (clamp_to_int) { + totallen = std::min(totallen, (loff_t)INT_MAX); + } if (write) { int64_t w = _write(fh, offset, totallen, NULL, iov, iovcnt); ldout(cct, 3) << "pwritev(" << fh << ", \"...\", " << totallen << ", " << offset << ") = " << w << dendl; @@ -9075,7 +9089,7 @@ int Client::_preadv_pwritev(int fd, const struct iovec *iov, unsigned iovcnt, in Fh *fh = get_filehandle(fd); if (!fh) return -EBADF; - return _preadv_pwritev_locked(fh, iov, iovcnt, offset, write); + return _preadv_pwritev_locked(fh, iov, iovcnt, offset, write, true); } int64_t Client::_write(Fh *f, int64_t offset, uint64_t size, const char *buf, @@ -12645,6 +12659,8 @@ int Client::ll_read(Fh *fh, loff_t off, loff_t len, bufferlist *bl) if (unmounting) return -ENOTCONN; + /* We can't return bytes written larger than INT_MAX, clamp len to that */ + len = std::min(len, (loff_t)INT_MAX); return _read(fh, off, len, bl); } @@ -12785,6 +12801,8 @@ int Client::ll_write(Fh *fh, loff_t off, loff_t len, const char *data) if (unmounting) return -ENOTCONN; + /* We can't return bytes written larger than INT_MAX, clamp len to that */ + len = std::min(len, (loff_t)INT_MAX); int r = _write(fh, off, len, data, NULL, 0); ldout(cct, 3) << "ll_write " << fh << " " << off << "~" << len << " = " << r << dendl; @@ -12796,7 +12814,7 @@ int64_t Client::ll_writev(struct Fh *fh, const struct iovec *iov, int iovcnt, in Mutex::Locker lock(client_lock); if (unmounting) return -ENOTCONN; - return _preadv_pwritev_locked(fh, iov, iovcnt, off, true); + return _preadv_pwritev_locked(fh, iov, iovcnt, off, true, false); } int64_t Client::ll_readv(struct Fh *fh, const struct iovec *iov, int iovcnt, int64_t off) @@ -12804,7 +12822,7 @@ int64_t Client::ll_readv(struct Fh *fh, const struct iovec *iov, int iovcnt, int Mutex::Locker lock(client_lock); if (unmounting) return -ENOTCONN; - return _preadv_pwritev_locked(fh, iov, iovcnt, off, false); + return _preadv_pwritev_locked(fh, iov, iovcnt, off, false, false); } int Client::ll_flush(Fh *fh) diff --git a/src/client/Client.h b/src/client/Client.h index c936a90d35f54..919848ab3fbdd 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -835,7 +835,8 @@ private: int64_t _read(Fh *fh, int64_t offset, uint64_t size, bufferlist *bl); int64_t _write(Fh *fh, int64_t offset, uint64_t size, const char *buf, const struct iovec *iov, int iovcnt); - int64_t _preadv_pwritev_locked(Fh *f, const struct iovec *iov, unsigned iovcnt, int64_t offset, bool write); + int64_t _preadv_pwritev_locked(Fh *f, const struct iovec *iov, + unsigned iovcnt, int64_t offset, bool write, bool clamp_to_int); int _preadv_pwritev(int fd, const struct iovec *iov, unsigned iovcnt, int64_t offset, bool write); int _flush(Fh *fh); int _fsync(Fh *fh, bool syncdataonly); -- 2.39.5