diff --git a/src/librbd/AioRequest.cc b/src/librbd/AioRequest.cc index 63424e397fc..b9a76e48e0a 100644 --- a/src/librbd/AioRequest.cc +++ b/src/librbd/AioRequest.cc @@ -157,15 +157,47 @@ namespace librbd { ldout(m_ictx->cct, 20) << "WRITE_CHECK_GUARD" << dendl; if (r == -ENOENT) { + Mutex::Locker l(m_ictx->snap_lock); Mutex::Locker l2(m_ictx->parent_lock); - // copyup the entire object up to the overlap point - ldout(m_ictx->cct, 20) << "reading from parent " << m_object_image_extents << dendl; - assert(m_object_image_extents.size()); + /* + * Parent may have disappeared; if so, recover by using + * send_copyup() to send the original write req (the copyup + * operation itself will be a no-op, since someone must have + * populated the child object while we weren't looking). + * Move to WRITE_FLAT state as we'll be done with the + * operation once the null copyup completes. + */ - m_state = LIBRBD_AIO_WRITE_COPYUP; - read_from_parent(m_object_image_extents); + if (m_ictx->parent == NULL) { + ldout(m_ictx->cct, 20) << "parent is gone; do null copyup " << dendl; + m_state = LIBRBD_AIO_WRITE_FLAT; + send_copyup(); + finished = false; + break; + } + + // If parent still exists, overlap might also have changed. + uint64_t newlen = m_ictx->prune_parent_extents( + m_object_image_extents, m_ictx->parent_md.overlap); + + // copyup the entire object up to the overlap point, if any + if (newlen != 0) { + ldout(m_ictx->cct, 20) << "should_complete(" << this << ") overlap " + << m_ictx->parent_md.overlap << " newlen " + << newlen << " image_extents" + << m_object_image_extents << dendl; + + m_state = LIBRBD_AIO_WRITE_COPYUP; + read_from_parent(m_object_image_extents); + } else { + ldout(m_ictx->cct, 20) << "should_complete(" << this + << "): parent overlap now 0" << dendl; + m_object_image_extents.clear(); + m_state = LIBRBD_AIO_WRITE_FLAT; + send_copyup(); + } finished = false; break; }