mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-11-17 20:00:23 +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
|
||||
}
|
||||
|
||||
// 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
|
||||
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
|
||||
// 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
|
||||
|
Loading…
Reference in New Issue
Block a user