]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
client: clamp I/O sizes to INT_MAX when we can't return larger values
authorJeff Layton <jlayton@redhat.com>
Fri, 9 Feb 2018 12:39:56 +0000 (07:39 -0500)
committerJeff Layton <jlayton@redhat.com>
Mon, 12 Feb 2018 12:17:56 +0000 (07:17 -0500)
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 <jlayton@redhat.com>
src/client/Client.cc
src/client/Client.h

index a121a894487e04b53cc8ce7f754e2fa15336f80d..91b3808e9a29c28373437b177dd0ccd6912198a5 100644 (file)
@@ -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)
index c936a90d35f54735febc0504528145d1a773bffd..919848ab3fbdd5192531d583c8dbee7c004a5935 100644 (file)
@@ -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);