mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-12-18 11:00:25 +00:00
rbd: write max 1gb per WriteSame() operation
It seems that writing more than 1 GiB per WriteSame() operation causes an EINVAL (22) "Invalid argument" error. Splitting the writes in blocks of maximum 1 GiB should prevent that from happening. Not all volumes are of a size that is the multiple of the stripe-size. WriteSame() needs to write full blocks of data, so in case there is a small left-over, it will be filled with WriteAt(). Signed-off-by: Niels de Vos <ndevos@redhat.com>
This commit is contained in:
parent
06d5d8f23a
commit
fe0f169875
@ -333,15 +333,52 @@ func (rv *rbdVolume) allocate(offset uint64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// zeroBlock is the stripe-period: size of the object-size multiplied
|
// blockSize is the stripe-period: size of the object-size multiplied
|
||||||
// by the stripe-count
|
// by the stripe-count
|
||||||
zeroBlock := make([]byte, sc*(1<<st.Order))
|
blockSize := sc * (1 << st.Order)
|
||||||
|
zeroBlock := make([]byte, blockSize)
|
||||||
|
|
||||||
// the actual size of the image as available in the pool, can be
|
// the actual size of the image as available in the pool, can be
|
||||||
// marginally different from the requested image size
|
// marginally different from the requested image size
|
||||||
_, err = image.WriteSame(offset, st.Size-offset, zeroBlock, rados.OpFlagNone)
|
size := st.Size - offset
|
||||||
|
|
||||||
return err
|
// In case the remaining space on the volume is smaller than blockSize,
|
||||||
|
// write a partial block with WriteAt() after this loop.
|
||||||
|
for size > blockSize {
|
||||||
|
writeSize := size
|
||||||
|
// write a maximum of 1GB per WriteSame() call
|
||||||
|
if size > helpers.GiB {
|
||||||
|
writeSize = helpers.GiB
|
||||||
|
}
|
||||||
|
|
||||||
|
// round down to the size of a zeroBlock
|
||||||
|
if (writeSize % blockSize) != 0 {
|
||||||
|
writeSize = (writeSize / blockSize) * blockSize
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = image.WriteSame(offset, writeSize, zeroBlock,
|
||||||
|
rados.OpFlagNone)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to allocate %d/%d bytes at "+
|
||||||
|
"offset %d: %w", writeSize, blockSize, offset, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// write succeeded
|
||||||
|
size -= writeSize
|
||||||
|
offset += writeSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the last remaining bytes, in case the image size can not be
|
||||||
|
// written with the optimal blockSize
|
||||||
|
if size != 0 {
|
||||||
|
_, err = image.WriteAt(zeroBlock[:size], int64(offset))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to allocate %d bytes at "+
|
||||||
|
"offset %d: %w", size, offset, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// isInUse checks if there is a watcher on the image. It returns true if there
|
// isInUse checks if there is a watcher on the image. It returns true if there
|
||||||
|
Loading…
Reference in New Issue
Block a user