vfs_vnops.c: Fix blksize for ZFS
Since ZFS reports _PC_MIN_HOLE_SIZE as 512 (although it appears that an unwritten region must be at least f_iosize to remain unallocated), vn_generic_copy_file_range() uses 4096 for the copy blksize for ZFS, reulting in slow copies. For most other file systems, _PC_MIN_HOLE_SIZE and f_iosize are the same value, so this patch modifies the code to use f_iosize for most cases. It also documents in comments why the blksize is being set a certain way, so that the code does not appear to be doing "magic math". Reported by: allanjude Reviewed by: allanjude, asomers MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D37076
This commit is contained in:
parent
5d42ef55de
commit
4ee16246f9
@ -3266,7 +3266,7 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp,
|
|||||||
int error, interrupted;
|
int error, interrupted;
|
||||||
bool cantseek, readzeros, eof, lastblock, holetoeof;
|
bool cantseek, readzeros, eof, lastblock, holetoeof;
|
||||||
ssize_t aresid, r = 0;
|
ssize_t aresid, r = 0;
|
||||||
size_t copylen, len, rem, savlen;
|
size_t copylen, len, savlen;
|
||||||
char *dat;
|
char *dat;
|
||||||
long holein, holeout;
|
long holein, holeout;
|
||||||
struct timespec curts, endts;
|
struct timespec curts, endts;
|
||||||
@ -3338,31 +3338,38 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp,
|
|||||||
if (error != 0)
|
if (error != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/*
|
if (holein == 0 && holeout > 0) {
|
||||||
* Set the blksize to the larger of the hole sizes for invp and outvp.
|
/*
|
||||||
* If hole sizes aren't available, set the blksize to the larger
|
* For this special case, the input data will be scanned
|
||||||
* f_iosize of invp and outvp.
|
* for blocks of all 0 bytes. For these blocks, the
|
||||||
* This code expects the hole sizes and f_iosizes to be powers of 2.
|
* write can be skipped for the output file to create
|
||||||
* This value is clipped at 4Kbytes and 1Mbyte.
|
* an unallocated region.
|
||||||
*/
|
* Therefore, use the appropriate size for the output file.
|
||||||
blksize = MAX(holein, holeout);
|
*/
|
||||||
|
blksize = holeout;
|
||||||
/* Clip len to end at an exact multiple of hole size. */
|
if (blksize <= 512) {
|
||||||
if (blksize > 1) {
|
/*
|
||||||
rem = *inoffp % blksize;
|
* Use f_iosize, since ZFS reports a _PC_MIN_HOLE_SIZE
|
||||||
if (rem > 0)
|
* of 512, although it actually only creates
|
||||||
rem = blksize - rem;
|
* unallocated regions for blocks >= f_iosize.
|
||||||
if (len > rem && len - rem > blksize)
|
*/
|
||||||
len = savlen = rounddown(len - rem, blksize) + rem;
|
blksize = outvp->v_mount->mnt_stat.f_iosize;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
if (blksize <= 1)
|
/*
|
||||||
|
* Use the larger of the two f_iosize values. If they are
|
||||||
|
* not the same size, one will normally be an exact multiple of
|
||||||
|
* the other, since they are both likely to be a power of 2.
|
||||||
|
*/
|
||||||
blksize = MAX(invp->v_mount->mnt_stat.f_iosize,
|
blksize = MAX(invp->v_mount->mnt_stat.f_iosize,
|
||||||
outvp->v_mount->mnt_stat.f_iosize);
|
outvp->v_mount->mnt_stat.f_iosize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clip to sane limits. */
|
||||||
if (blksize < 4096)
|
if (blksize < 4096)
|
||||||
blksize = 4096;
|
blksize = 4096;
|
||||||
else if (blksize > 1024 * 1024)
|
else if (blksize > maxphys)
|
||||||
blksize = 1024 * 1024;
|
blksize = maxphys;
|
||||||
dat = malloc(blksize, M_TEMP, M_WAITOK);
|
dat = malloc(blksize, M_TEMP, M_WAITOK);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user