Add more constraints for block cloning.
- We cannot clone into files with smaller block size if there is more than one block, since we can not grow the block size. - Block size must be power-of-2 if destination offset != 0, since there can be no multiple blocks of non-power-of-2 size. The first should handle the case when destination file has several blocks but still is not bigger than one block of the source file. The second fixes panic in dmu_buf_hold_array_by_dnode() on attempt to concatenate files with equal but non-power-of-2 block sizes. While there, assert that error is reported if we made no progress. Reviewed-by: Pawel Jakub Dawidek <pawel@dawidek.net> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Rob Norris <rob.norris@klarasystems.com> Reviewed-by: Kay Pedersen <mail@mkwg.de> Reviewed-by: Umer Saleem <usaleem@ixsystems.com> Signed-off-by: Alexander Motin <mav@FreeBSD.org> Sponsored by: iXsystems, Inc. Closes #15251
This commit is contained in:
parent
12ce45f260
commit
5cc1876f14
|
@ -1172,9 +1172,20 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp,
|
|||
inblksz = inzp->z_blksz;
|
||||
|
||||
/*
|
||||
* We cannot clone into files with different block size.
|
||||
* We cannot clone into files with different block size if we can't
|
||||
* grow it (block size is already bigger or more than one block).
|
||||
*/
|
||||
if (inblksz != outzp->z_blksz && outzp->z_size > inblksz) {
|
||||
if (inblksz != outzp->z_blksz && (outzp->z_size > outzp->z_blksz ||
|
||||
outzp->z_size > inblksz)) {
|
||||
error = SET_ERROR(EINVAL);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Block size must be power-of-2 if destination offset != 0.
|
||||
* There can be no multiple blocks of non-power-of-2 size.
|
||||
*/
|
||||
if (outoff != 0 && !ISP2(inblksz)) {
|
||||
error = SET_ERROR(EINVAL);
|
||||
goto unlock;
|
||||
}
|
||||
|
@ -1358,6 +1369,12 @@ unlock:
|
|||
*inoffp += done;
|
||||
*outoffp += done;
|
||||
*lenp = done;
|
||||
} else {
|
||||
/*
|
||||
* If we made no progress, there must be a good reason.
|
||||
* EOF is handled explicitly above, before the loop.
|
||||
*/
|
||||
ASSERT3S(error, !=, 0);
|
||||
}
|
||||
|
||||
zfs_exit_two(inzfsvfs, outzfsvfs, FTAG);
|
||||
|
|
Loading…
Reference in New Issue