1 |
On 03/02/2017 08:24 AM, Michał Górny wrote: |
2 |
> W dniu 01.03.2017, śro o godzinie 19∶03 -0800, użytkownik Zac Medico |
3 |
> napisał: |
4 |
>> +def _test_optimized_copyfile(): |
5 |
>> + """ |
6 |
>> + Test if _optimized_copyfile works. It will fail for Linux versions |
7 |
>> + from 2.6.0 to 2.6.32, because sendfile does not support writing |
8 |
>> + to regular files. It will also fail for Linux versions less than |
9 |
>> + 3.1 if portage was compiled 3.1 or later, due to missing support |
10 |
>> + for lseek SEEK_DATA/SEEK_HOLE. |
11 |
> |
12 |
> I don't really like the idea of relying on one-time attempt to determine |
13 |
> whether a complex mechanism lacking proper fallback will work. But I |
14 |
> guess you're only aiming at catching corner cases here. |
15 |
|
16 |
In v2, there's a complete fallback mechanism in the native code, and the |
17 |
_test_optimized_copyfile function has been eliminated. |
18 |
|
19 |
>> + /* Revert SEEK_HOLE offset change, since we're going |
20 |
>> + * to copy the data that comes before the hole. |
21 |
>> + */ |
22 |
>> + if (lseek(fd_in, offset_out, SEEK_SET) < 0) { |
23 |
>> + error = 1; |
24 |
>> + break; |
25 |
>> + } |
26 |
>> + |
27 |
>> + copyfunc_ret = copyfunc(fd_out, |
28 |
>> + fd_in, |
29 |
>> + &offset_out, |
30 |
>> + offset_hole - offset_data); |
31 |
>> + |
32 |
>> + if (copyfunc_ret < 0) { |
33 |
>> + if ((errno == EXDEV || errno == ENOSYS) && |
34 |
>> + copyfunc == cfr_wrapper) { |
35 |
>> + /* Use sendfile instead of copy_file_range for |
36 |
>> + * cross-device copies, or when the copy_file_range |
37 |
>> + * syscall is not available (less than Linux 4.5). |
38 |
>> + */ |
39 |
>> + copyfunc = sendfile; |
40 |
>> + copyfunc_ret = copyfunc(fd_out, |
41 |
>> + fd_in, |
42 |
>> + &offset_out, |
43 |
>> + offset_hole - offset_data); |
44 |
>> + |
45 |
>> + if (copyfunc_ret < 0) { |
46 |
> |
47 |
> I think you still should have a proper fallback for sendfile() refusing |
48 |
> to do its job. |
49 |
|
50 |
In the lseek loop, sendfile should always work if lseek SEEK_DATA works, |
51 |
so there should be no need to fallback for sendfile failure here. In v2, |
52 |
I've added a comment about this. |
53 |
|
54 |
>> + while (eintr_retry) { |
55 |
>> + |
56 |
>> + error = 0; |
57 |
>> + |
58 |
>> + Py_BEGIN_ALLOW_THREADS |
59 |
>> + |
60 |
>> + if (!stat_acquired && fstat(fd_in, &sb) < 0) { |
61 |
>> + error = 1; |
62 |
>> + } |
63 |
>> + else { |
64 |
>> + stat_acquired = 1; |
65 |
>> + while (offset_out < sb.st_size) { |
66 |
>> + copyfunc_ret = sendfile(fd_out, |
67 |
>> + fd_in, |
68 |
>> + &offset_out, |
69 |
>> + sb.st_size - offset_out); |
70 |
>> + |
71 |
>> + if (copyfunc_ret < 0) { |
72 |
> |
73 |
> Likewise, especially that old kernels may refuse file-to-file copy here. |
74 |
|
75 |
In v2, it will fallback to a plain read/write loop. |
76 |
-- |
77 |
Thanks, |
78 |
Zac |