Lines 3096-3108
vn_generic_copy_file_range(struct vnode *invp, off_t *
Link Here
|
3096 |
struct vnode *outvp, off_t *outoffp, size_t *lenp, unsigned int flags, |
3096 |
struct vnode *outvp, off_t *outoffp, size_t *lenp, unsigned int flags, |
3097 |
struct ucred *incred, struct ucred *outcred, struct thread *fsize_td) |
3097 |
struct ucred *incred, struct ucred *outcred, struct thread *fsize_td) |
3098 |
{ |
3098 |
{ |
3099 |
struct vattr va; |
3099 |
struct vattr va, inva; |
3100 |
struct mount *mp; |
3100 |
struct mount *mp; |
3101 |
struct uio io; |
3101 |
struct uio io; |
3102 |
off_t startoff, endoff, xfer, xfer2; |
3102 |
off_t startoff, endoff, xfer, xfer2; |
3103 |
u_long blksize; |
3103 |
u_long blksize; |
3104 |
int error, interrupted; |
3104 |
int error, interrupted; |
3105 |
bool cantseek, readzeros, eof, lastblock; |
3105 |
bool cantseek, readzeros, eof, lastblock, holetoeof; |
3106 |
ssize_t aresid; |
3106 |
ssize_t aresid; |
3107 |
size_t copylen, len, rem, savlen; |
3107 |
size_t copylen, len, rem, savlen; |
3108 |
char *dat; |
3108 |
char *dat; |
Lines 3115-3120
vn_generic_copy_file_range(struct vnode *invp, off_t *
Link Here
|
3115 |
dat = NULL; |
3115 |
dat = NULL; |
3116 |
|
3116 |
|
3117 |
error = vn_lock(invp, LK_SHARED); |
3117 |
error = vn_lock(invp, LK_SHARED); |
|
|
3118 |
if (error == 0) |
3119 |
error = VOP_GETATTR(invp, &inva, incred); |
3118 |
if (error != 0) |
3120 |
if (error != 0) |
3119 |
goto out; |
3121 |
goto out; |
3120 |
if (VOP_PATHCONF(invp, _PC_MIN_HOLE_SIZE, &holein) != 0) |
3122 |
if (VOP_PATHCONF(invp, _PC_MIN_HOLE_SIZE, &holein) != 0) |
Lines 3209-3216
vn_generic_copy_file_range(struct vnode *invp, off_t *
Link Here
|
3209 |
|
3211 |
|
3210 |
/* |
3212 |
/* |
3211 |
* Find the next data area. If there is just a hole to EOF, |
3213 |
* Find the next data area. If there is just a hole to EOF, |
3212 |
* FIOSEEKDATA should fail and then we drop down into the |
3214 |
* FIOSEEKDATA should fail with ENXIO. |
3213 |
* inner loop and create the hole on the outvp file. |
|
|
3214 |
* (I do not know if any file system will report a hole to |
3215 |
* (I do not know if any file system will report a hole to |
3215 |
* EOF via FIOSEEKHOLE, but I am pretty sure FIOSEEKDATA |
3216 |
* EOF via FIOSEEKHOLE, but I am pretty sure FIOSEEKDATA |
3216 |
* will fail for those file systems.) |
3217 |
* will fail for those file systems.) |
Lines 3219-3231
vn_generic_copy_file_range(struct vnode *invp, off_t *
Link Here
|
3219 |
* the code just falls through to the inner copy loop. |
3220 |
* the code just falls through to the inner copy loop. |
3220 |
*/ |
3221 |
*/ |
3221 |
error = EINVAL; |
3222 |
error = EINVAL; |
3222 |
if (holein > 0) |
3223 |
holetoeof = false; |
|
|
3224 |
if (holein > 0) { |
3223 |
error = VOP_IOCTL(invp, FIOSEEKDATA, &startoff, 0, |
3225 |
error = VOP_IOCTL(invp, FIOSEEKDATA, &startoff, 0, |
3224 |
incred, curthread); |
3226 |
incred, curthread); |
3225 |
if (error == 0) { |
3227 |
printf("seekdata soff=%ld err=%d\n", startoff, error); |
|
|
3228 |
if (error == ENXIO) { |
3229 |
startoff = endoff = inva.va_size; |
3230 |
eof = holetoeof = true; |
3231 |
printf("holeeof\n"); |
3232 |
error = 0; |
3233 |
} |
3234 |
} |
3235 |
if (error == 0 && !holetoeof) { |
3226 |
endoff = startoff; |
3236 |
endoff = startoff; |
3227 |
error = VOP_IOCTL(invp, FIOSEEKHOLE, &endoff, 0, |
3237 |
error = VOP_IOCTL(invp, FIOSEEKHOLE, &endoff, 0, |
3228 |
incred, curthread); |
3238 |
incred, curthread); |
|
|
3239 |
printf("seekhole eoff=%ld err=%d\n", endoff, error); |
3229 |
/* |
3240 |
/* |
3230 |
* Since invp is unlocked, it may be possible for |
3241 |
* Since invp is unlocked, it may be possible for |
3231 |
* another thread to do a truncate(), lseek(), write() |
3242 |
* another thread to do a truncate(), lseek(), write() |
Lines 3240-3248
vn_generic_copy_file_range(struct vnode *invp, off_t *
Link Here
|
3240 |
} |
3251 |
} |
3241 |
if (error == 0) { |
3252 |
if (error == 0) { |
3242 |
if (startoff > *inoffp) { |
3253 |
if (startoff > *inoffp) { |
|
|
3254 |
printf("hole at startoff\n"); |
3243 |
/* Found hole before data block. */ |
3255 |
/* Found hole before data block. */ |
3244 |
xfer = MIN(startoff - *inoffp, len); |
3256 |
xfer = MIN(startoff - *inoffp, len); |
|
|
3257 |
printf("xfer=%ld len=%ld\n", xfer, len); |
3245 |
if (*outoffp < va.va_size) { |
3258 |
if (*outoffp < va.va_size) { |
|
|
3259 |
printf("punching hole\n"); |
3246 |
/* Must write 0s to punch hole. */ |
3260 |
/* Must write 0s to punch hole. */ |
3247 |
xfer2 = MIN(va.va_size - *outoffp, |
3261 |
xfer2 = MIN(va.va_size - *outoffp, |
3248 |
xfer); |
3262 |
xfer); |
Lines 3253-3267
vn_generic_copy_file_range(struct vnode *invp, off_t *
Link Here
|
3253 |
} |
3267 |
} |
3254 |
|
3268 |
|
3255 |
if (error == 0 && *outoffp + xfer > |
3269 |
if (error == 0 && *outoffp + xfer > |
3256 |
va.va_size && xfer == len) |
3270 |
va.va_size && (xfer == len || holetoeof)) { |
3257 |
/* Grow last block. */ |
3271 |
/* Grow output file (hole at end). */ |
3258 |
error = vn_write_outvp(outvp, dat, |
3272 |
error = vn_write_outvp(outvp, dat, |
3259 |
*outoffp, xfer, blksize, true, |
3273 |
*outoffp, xfer, blksize, true, |
3260 |
false, outcred); |
3274 |
false, outcred); |
|
|
3275 |
printf("grow at end=%d\n", error); |
3276 |
} |
3261 |
if (error == 0) { |
3277 |
if (error == 0) { |
3262 |
*inoffp += xfer; |
3278 |
*inoffp += xfer; |
3263 |
*outoffp += xfer; |
3279 |
*outoffp += xfer; |
3264 |
len -= xfer; |
3280 |
len -= xfer; |
|
|
3281 |
printf("inoff=%ld outoff=%ld xfer=%ld len=%ld\n", *inoffp, *outoffp, xfer, len); |
3265 |
if (len < savlen) |
3282 |
if (len < savlen) |
3266 |
interrupted = sig_intr(); |
3283 |
interrupted = sig_intr(); |
3267 |
} |
3284 |
} |
Lines 3286-3291
vn_generic_copy_file_range(struct vnode *invp, off_t *
Link Here
|
3286 |
} |
3303 |
} |
3287 |
/* Loop copying the data block. */ |
3304 |
/* Loop copying the data block. */ |
3288 |
while (copylen > 0 && error == 0 && !eof && interrupted == 0) { |
3305 |
while (copylen > 0 && error == 0 && !eof && interrupted == 0) { |
|
|
3306 |
printf("in copyloop copylen=%ld xfer=%ld\n", copylen, xfer); |
3289 |
if (copylen < xfer) |
3307 |
if (copylen < xfer) |
3290 |
xfer = copylen; |
3308 |
xfer = copylen; |
3291 |
error = vn_lock(invp, LK_SHARED); |
3309 |
error = vn_lock(invp, LK_SHARED); |