]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
os/bluestore: fix large (>2GB) writes when bluefs_buffered_io = true 35404/head
authorIgor Fedotov <ifedotov@suse.com>
Wed, 29 Apr 2020 16:59:03 +0000 (19:59 +0300)
committerNathan Cutler <ncutler@suse.com>
Thu, 4 Jun 2020 14:50:16 +0000 (16:50 +0200)
Fixes: https://tracker.ceph.com/issues/45337
Signed-off-by: Igor Fedotov <ifedotov@suse.com>
(cherry picked from commit d9b0250e215b4755f38b57dbaabecef1063db8d6)

src/os/bluestore/KernelDevice.cc

index 8481d67a474469110e3ed56a6e43a4bb125860fe..0fe58822525b64a5623160a94f9920dc962b926c 100644 (file)
@@ -773,18 +773,42 @@ int KernelDevice::_sync_write(uint64_t off, bufferlist &bl, bool buffered, int w
   }
   vector<iovec> iov;
   bl.prepare_iov(&iov);
-  int r = ::pwritev(choose_fd(buffered, write_hint),
-                   &iov[0], iov.size(), off);
 
-  if (r < 0) {
-    r = -errno;
-    derr << __func__ << " pwritev error: " << cpp_strerror(r) << dendl;
-    return r;
-  }
+  auto left = len;
+  auto o = off;
+  size_t idx = 0;
+  do {
+    auto r = ::pwritev(choose_fd(buffered, write_hint),
+      &iov[idx], iov.size() - idx, o);
+
+    if (r < 0) {
+      r = -errno;
+      derr << __func__ << " pwritev error: " << cpp_strerror(r) << dendl;
+      return r;
+    }
+    o += r;
+    left -= r;
+    if (left) {
+      // skip fully processed IOVs
+      while (idx < iov.size() && (size_t)r >= iov[idx].iov_len) {
+        r -= iov[idx++].iov_len;
+      }
+      // update partially processed one if any
+      if (r) {
+        ceph_assert(idx < iov.size());
+        ceph_assert((size_t)r < iov[idx].iov_len);
+        iov[idx].iov_base = static_cast<char*>(iov[idx].iov_base) + r;
+        iov[idx].iov_len -= r;
+        r = 0;
+      }
+      ceph_assert(r == 0);
+    }
+  } while (left);
+
 #ifdef HAVE_SYNC_FILE_RANGE
   if (buffered) {
     // initiate IO and wait till it completes
-    r = ::sync_file_range(fd_buffereds[WRITE_LIFE_NOT_SET], off, len, SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER|SYNC_FILE_RANGE_WAIT_BEFORE);
+    auto r = ::sync_file_range(fd_buffereds[WRITE_LIFE_NOT_SET], off, len, SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER|SYNC_FILE_RANGE_WAIT_BEFORE);
     if (r < 0) {
       r = -errno;
       derr << __func__ << " sync_file_range error: " << cpp_strerror(r) << dendl;