]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd/cache/pwl/ssd/WriteLog: don't crash on split log entries 41093/head
authorIlya Dryomov <idryomov@gmail.com>
Thu, 29 Apr 2021 13:03:46 +0000 (15:03 +0200)
committerIlya Dryomov <idryomov@gmail.com>
Mon, 3 May 2021 12:05:58 +0000 (14:05 +0200)
write_log_entries() will split a log entry at the end of the log, the
remainder is written to the beginning at DATA_RING_BUFFER_OFFSET.  On
the read side aio_read_data_block() doesn't handle this case and just
crashes.  Unless the workload in use is <= 4K, the image is rendered
unusable sooner or later.

Fixes: https://tracker.ceph.com/issues/50589
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
src/librbd/cache/pwl/ssd/WriteLog.cc
src/librbd/cache/pwl/ssd/WriteLog.h

index 14b813abedbac7319d83970a47c53f7e68c1619f..864c8f6653dbcc24ada87b59cb4eb301affecc90 100644 (file)
@@ -954,18 +954,6 @@ int WriteLog<I>::update_pool_root_sync(
   return bdev->write(0, bl, false);
 }
 
-template <typename I>
-void WriteLog<I>::pre_io_check(WriteLogCacheEntry *log_entry,
-                               uint64_t &length) {
-  assert(log_entry->is_write() || log_entry->is_writesame());
-  ceph_assert(log_entry->write_data_pos <= pool_size);
-
-  length = log_entry->is_write() ? log_entry->write_bytes :
-                                   log_entry->ws_datalen;
-  length = round_up_to(length, MIN_WRITE_ALLOC_SSD_SIZE);
-  ceph_assert(length != 0 && log_entry->write_data_pos + length <= pool_size);
-}
-
 template <typename I>
 void WriteLog<I>::aio_read_data_block(WriteLogCacheEntry *log_entry,
                                       bufferlist *bl, Context *ctx) {
@@ -999,12 +987,32 @@ void WriteLog<I>::aio_read_data_block(
   for (unsigned int i = 0; i < log_entries.size(); i++) {
     auto log_entry = log_entries[i];
 
-    uint64_t length;
-    pre_io_check(log_entry, length);
-    ldout(cct, 20) << "Read at " << log_entry->write_data_pos
-                   << ", length " << length << dendl;
-
-    bdev->aio_read(log_entry->write_data_pos, length, bls[i], &aio->ioc);
+    ceph_assert(log_entry->is_write() || log_entry->is_writesame());
+    uint64_t len = log_entry->is_write() ? log_entry->write_bytes :
+                                           log_entry->ws_datalen;
+    uint64_t align_len = round_up_to(len, MIN_WRITE_ALLOC_SSD_SIZE);
+
+    ldout(cct, 20) << "entry i=" << i << " " << log_entry->write_data_pos
+                   << "~" << len << dendl;
+    ceph_assert(log_entry->write_data_pos <= pool_root.pool_size);
+    ceph_assert(align_len != 0);
+    if (log_entry->write_data_pos + align_len > pool_root.pool_size) {
+      // spans boundary, need to split
+      uint64_t len1 = pool_root.pool_size - log_entry->write_data_pos;
+      uint64_t len2 = align_len - len1;
+
+      ldout(cct, 20) << "read " << log_entry->write_data_pos << "~"
+                     << align_len << " spans boundary, split into "
+                     << log_entry->write_data_pos << "~" << len1
+                     << " and " << DATA_RING_BUFFER_OFFSET << "~"
+                     << len2 << dendl;
+      bdev->aio_read(log_entry->write_data_pos, len1, bls[i], &aio->ioc);
+      bdev->aio_read(DATA_RING_BUFFER_OFFSET, len2, bls[i], &aio->ioc);
+    } else {
+      ldout(cct, 20) << "read " << log_entry->write_data_pos << "~"
+                     << align_len << dendl;
+      bdev->aio_read(log_entry->write_data_pos, align_len, bls[i], &aio->ioc);
+    }
   }
   bdev->aio_submit(&aio->ioc);
 }
index df45164f7826c763987ffe9d20350382b7fc5bf1..ca3b90c0b3680f0b0f7059c63a60b6b8c9dd8453 100644 (file)
@@ -134,7 +134,6 @@ private:
   int update_pool_root_sync(std::shared_ptr<pwl::WriteLogPoolRoot> root);
   void update_pool_root(std::shared_ptr<WriteLogPoolRoot> root,
                                           AioTransContext *aio);
-  void pre_io_check(WriteLogCacheEntry *log_entry, uint64_t &length);
   void aio_read_data_block(WriteLogCacheEntry *log_entry, bufferlist *bl,
                            Context *ctx);
   void aio_read_data_block(std::vector<WriteLogCacheEntry*> &log_entries,