Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: "Michał Górny" <mgorny@g.o>, gentoo-portage-dev@l.g.o
Cc: Zac Medico <zmedico@g.o>
Subject: Re: [gentoo-portage-dev] [PATCH] movefile: support in-kernel file copying on Linux (bug 607868)
Date: Fri, 03 Mar 2017 17:16:49
Message-Id: 2330239c-62ec-4f6c-be87-9e7faea9c0ba@gentoo.org
In Reply to: Re: [gentoo-portage-dev] [PATCH] movefile: support in-kernel file copying on Linux (bug 607868) by "Michał Górny"
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