Skip to content
This repository has been archived by the owner on May 21, 2024. It is now read-only.

Implement ostree pause/resume #1007

Merged
merged 3 commits into from
Nov 27, 2018
Merged

Implement ostree pause/resume #1007

merged 3 commits into from
Nov 27, 2018

Conversation

patriotyk
Copy link
Contributor

No description provided.

@patriotyk patriotyk force-pushed the ostree_pause branch 3 times, most recently from 02814f8 to c63165a Compare November 15, 2018 08:08
@codecov-io
Copy link

codecov-io commented Nov 15, 2018

Codecov Report

Merging #1007 into master will increase coverage by 0.15%.
The diff coverage is 95.45%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1007      +/-   ##
==========================================
+ Coverage   82.03%   82.19%   +0.15%     
==========================================
  Files         188      188              
  Lines       13229    13241      +12     
==========================================
+ Hits        10853    10884      +31     
+ Misses       2376     2357      -19
Impacted Files Coverage Δ
src/libaktualizr/utilities/utils.cc 86% <ø> (ø) ⬆️
src/libaktualizr/uptane/fetcher.h 85.71% <100%> (+1.09%) ⬆️
src/libaktualizr/uptane/fetcher_test.cc 95.91% <100%> (+0.04%) ⬆️
src/libaktualizr/package_manager/ostreemanager.h 85.71% <100%> (+5.71%) ⬆️
src/libaktualizr/uptane/fetcher.cc 97.97% <100%> (+4.1%) ⬆️
src/libaktualizr/package_manager/ostreemanager.cc 61.77% <71.42%> (+7.89%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 19adf3c...e6d74dc. Read the comment docs.

@patriotyk patriotyk force-pushed the ostree_pause branch 3 times, most recently from b5ea82a to 54e52f6 Compare November 15, 2018 15:52
@@ -86,7 +86,7 @@ TEST(fetcher, fetch_with_pause) {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
EXPECT_EQ(f.setPause(true), PauseResult::kPaused);
EXPECT_EQ(f.setPause(true), PauseResult::kAlreadyPaused);
std::this_thread::sleep_for(std::chrono::seconds(2));
std::this_thread::sleep_for(std::chrono::seconds(15));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does it need to sleep so long?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tried to understand who blocks the thread, I have already found it, but havn't restored previouse values

@patriotyk
Copy link
Contributor Author

patriotyk commented Nov 16, 2018

We have several issues here.
I have added tests that tests ostree pull, we have newer tested reall ostree pull functionality before. As result we got several memmory issues under valgrind.
First one it is definitely lost memory leak which happens only on CI because in the new ostree version(which is installed on my laptop) it is already fixed - ostreedev/ostree#1521
Second one it is following issue:

23: ==14500== Syscall param ioctl(generic) points to unaddressable byte(s)
23: ==14500==    at 0x71BF5D7: ioctl (syscall-template.S:78)
23: ==14500==    by 0x59D433E: ??? (in /usr/lib/x86_64-linux-gnu/libostree-1.so.1.0.0)
23: ==14500==    by 0x59D5F35: ??? (in /usr/lib/x86_64-linux-gnu/libostree-1.so.1.0.0)
23: ==14500==    by 0x59D8B0E: ostree_repo_write_content (in /usr/lib/x86_64-linux-gnu/libostree-1.so.1.0.0)
23: ==14500==    by 0x59D8B90: ??? (in /usr/lib/x86_64-linux-gnu/libostree-1.so.1.0.0)
23: ==14500==    by 0x5CC1FC3: ??? (in /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.5600.2)
23: ==14500==    by 0x5CAD225: ??? (in /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.5600.2)
23: ==14500==    by 0x5CD4C95: ??? (in /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.5600.2)
23: ==14500==    by 0x62AE84F: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.5600.2)
23: ==14500==    by 0x62ADE84: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.5600.2)
23: ==14500==    by 0x4E436DA: start_thread (pthread_create.c:463)
23: ==14500==    by 0x71CA88E: clone (clone.S:95)
23: ==14500==  Address 0xf is not stack'd, malloc'd or (recently) free'd

But I can't figure out what is going here.

@lbonn
Copy link
Contributor

lbonn commented Nov 16, 2018

Wow, not running test with pull was quite an overlook! Good that we are making progress.

For reference, which version of ostree are you using on your laptop? I'll try the last release 2018.9.

@patriotyk
Copy link
Contributor Author

2018.8

@lbonn
Copy link
Contributor

lbonn commented Nov 16, 2018

Here is your error with a better stacktrace:

[ RUN      ] fetcher.test_pause_ostree
created: /tmp/aktualizr-7a85-b932-e1ae-b3af/667f-d9d7-dir
No download in progress, can't pause.
Download is already paused.
Download is not paused, can't resume.
ostree-pull: Receiving metadata objects: 1 outstanding: 1
==1052== Thread 2 pool:
==1052== Syscall param ioctl(generic) points to unaddressable byte(s)
==1052==    at 0x71F15D7: ioctl (syscall-template.S:78)
==1052==    by 0x59DEE68: _check_support_reflink (ostree-repo-commit.c:650)
==1052==    by 0x59DFAF7: write_content_object (ostree-repo-commit.c:878)
==1052==    by 0x59E3D5D: ostree_repo_write_content (ostree-repo-commit.c:2597)
==1052==    by 0x59E3F22: write_content_thread (ostree-repo-commit.c:2635)
==1052==    by 0x5CF3FC3: ??? (in /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.5600.2)
==1052==    by 0x5CDF225: ??? (in /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.5600.2)
==1052==    by 0x5D06C95: ??? (in /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.5600.2)
==1052==    by 0x62E084F: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.5600.2)
==1052==    by 0x62DFE84: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.5600.2)
==1052==    by 0x4E436DA: start_thread (pthread_create.c:463)
==1052==    by 0x71FC88E: clone (clone.S:95)
==1052==  Address 0xf is not stack'd, malloc'd or (recently) free'd
==1052==
ostree-pull: 5 metadata, 1 content objects fetched; 195 B transferred in 18 seconds
[       OK ] fetcher.test_pause_ostree (20009 ms)
[ RUN      ] fetcher.fetch_restore_binary

I used the bionic docker with ostree 2018.9, compiled with -g.

I also got these leaks:

==1052== HEAP SUMMARY:
==1052==     in use at exit: 93,812 bytes in 1,080 blocks
==1052==   total heap usage: 32,733 allocs, 31,653 frees, 11,974,052 bytes allocated
==1052==
==1052== Thread 1:
==1052== 416 bytes in 1 blocks are possibly lost in loss record 1,038 of 1,057
==1052==    at 0x4C31B25: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==1052==    by 0x40134A6: allocate_dtv (dl-tls.c:286)
==1052==    by 0x40134A6: _dl_allocate_tls (dl-tls.c:530)
==1052==    by 0x4E44227: allocate_stack (allocatestack.c:627)
==1052==    by 0x4E44227: pthread_create@@GLIBC_2.2.5 (pthread_create.c:644)
==1052==    by 0x6BF7834: std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==1052==    by 0x1310F1: thread<test_pause(const Uptane::Target&)::<lambda()> > (thread:126)
==1052==    by 0x1310F1: test_pause(Uptane::Target const&) (fetcher_test.cc:85)
==1052==    by 0x131BE1: fetcher_test_pause_ostree_Test::TestBody() (fetcher_test.cc:116)
==1052==    by 0x2859A1: HandleSehExceptionsInMethodIfSupported<testing::Test, void> (gtest.cc:2417)
==1052==    by 0x2859A1: void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (gtest.cc:2453)
==1052==    by 0x27C22F: testing::Test::Run() (gtest.cc:2491)
==1052==    by 0x27C354: testing::TestInfo::Run() (gtest.cc:2667)
==1052==    by 0x27C42A: testing::TestCase::Run() (gtest.cc:2785)
==1052==    by 0x27C61A: testing::internal::UnitTestImpl::RunAllTests() (gtest.cc:5042)
==1052==    by 0x285E8D: HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool> (gtest.cc:2417)
==1052==    by 0x285E8D: bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) (gtest.cc:2453)
==1052==    by 0x27C9B0: testing::UnitTest::Run() (gtest.cc:4658)
==1052==    by 0x12E938: RUN_ALL_TESTS (gtest.h:2314)
==1052==    by 0x12E938: main (fetcher_test.cc:172)
==1052==
==1052== 416 bytes in 1 blocks are possibly lost in loss record 1,039 of 1,057
==1052==    at 0x4C31B25: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==1052==    by 0x40134A6: allocate_dtv (dl-tls.c:286)
==1052==    by 0x40134A6: _dl_allocate_tls (dl-tls.c:530)
==1052==    by 0x4E44227: allocate_stack (allocatestack.c:627)
==1052==    by 0x4E44227: pthread_create@@GLIBC_2.2.5 (pthread_create.c:644)
==1052==    by 0x62FDB5F: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.5600.2)
==1052==    by 0x62E018E: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.5600.2)
==1052==    by 0x62E0237: g_thread_new (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.5600.2)
==1052==    by 0x62B9343: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.5600.2)
==1052==    by 0x5D06426: g_task_get_type (in /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.5600.2)
==1052==    by 0x5D064A8: g_task_new (in /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.5600.2)
==1052==    by 0x5A3B733: _ostree_fetcher_request_async (ostree-fetcher-curl.c:864)
==1052==    by 0x5A3B9A7: _ostree_fetcher_request_to_membuf (ostree-fetcher-curl.c:924)
==1052==    by 0x5A36FCA: _ostree_fetcher_mirrored_request_to_membuf_once (ostree-fetcher-util.c:81)
==1052==    by 0x5A37165: _ostree_fetcher_mirrored_request_to_membuf (ostree-fetcher-util.c:128)
==1052==    by 0x59EA019: fetch_mirrored_uri_contents_utf8_sync (ostree-repo-pull.c:575)
==1052==    by 0x59EEA66: load_remote_repo_config (ostree-repo-pull.c:2219)
==1052==    by 0x59F4107: ostree_repo_pull_with_options (ostree-repo-pull.c:3891)
==1052==    by 0x1C46EF: OstreeManager::pull(boost::filesystem::path const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, KeyManager const&, Uptane::Target const&, std::shared_ptr<std::mutex> const&, std::shared_ptr<boost::signals2::signal<void (std::shared_ptr<event::BaseEvent>), boost::signals2::optional_last_value<void>, int, std::less<int>, boost::function<void (std::shared_ptr<event::BaseEvent>)>, boost::function<void (boost::signals2::connection const&, std::shared_ptr<event::BaseEvent>)>, boost::signals2::mutex> > const&) (ostreemanager.cc:121)
==1052==    by 0x19D77E: Uptane::Fetcher::fetchVerifyTarget(Uptane::Target const&) (fetcher.cc:150)
==1052==    by 0x131153: test_pause(Uptane::Target const&) (fetcher_test.cc:97)
==1052==    by 0x131BE1: fetcher_test_pause_ostree_Test::TestBody() (fetcher_test.cc:116)
==1052==    by 0x2859A1: HandleSehExceptionsInMethodIfSupported<testing::Test, void> (gtest.cc:2417)
==1052==    by 0x2859A1: void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (gtest.cc:2453)
==1052==    by 0x27C22F: testing::Test::Run() (gtest.cc:2491)
==1052==    by 0x27C354: testing::TestInfo::Run() (gtest.cc:2667)
==1052==    by 0x27C42A: testing::TestCase::Run() (gtest.cc:2785)
==1052==    by 0x27C61A: testing::internal::UnitTestImpl::RunAllTests() (gtest.cc:5042)
==1052==
==1052== LEAK SUMMARY:
==1052==    definitely lost: 0 bytes in 0 blocks
==1052==    indirectly lost: 0 bytes in 0 blocks
==1052==      possibly lost: 832 bytes in 2 blocks
==1052==    still reachable: 48,546 bytes in 464 blocks
==1052==                       of which reachable via heuristic:
==1052==                         length64           : 984 bytes in 21 blocks
==1052==                         newarray           : 1,744 bytes in 29 blocks
==1052==         suppressed: 42,154 bytes in 595 blocks

Are they new?

@lbonn
Copy link
Contributor

lbonn commented Nov 16, 2018

The ioctl stuff seems to be a valgrind bug (to confirm): https://bugs.kde.org/show_bug.cgi?id=397605

@patriotyk
Copy link
Contributor Author

Possibly lost leaks doesn't cause tests to FAIL. And yes I have also those issues on my laptop, but we don't know is it new or not because we didn't test such functionality before.

@lbonn
Copy link
Contributor

lbonn commented Nov 16, 2018

Ok fair enough.

I would update the dockerfiles to use the same version as meta-updater (2018.7) if it doesn't have the other leak and add the ioctl error to our suppression list.

@patriotyk
Copy link
Contributor Author

I knew that our code is the best, and issues are somewhere else )))))))

Copy link
Collaborator

@pattivacek pattivacek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I get it so far, but I still need to actually test and verify.

has_been_paused = true;
} else {
mt->pause_mutex->unlock();
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I entirely understand this logic. So if the mutex is already locked, we want to acquire it again? I assume that is just to wait until it is freed/unpaused. But then why wait until the end of this function before unlocking it again?

Whatever the intention, a comment would be helpful here. This logic is tricky enough that it is worth stating the goals explicitly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated with comments

sleep(3);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You will need to rebase; we've improved this logic so that now we can wait for the server to be ready automatically instead of mandating 3 seconds.

target_json["length"] = 0;
Uptane::Target target("pause", target_json);
test_pause(target);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also have test_pause_binary, which would basically be the same as how this used to be, but now reusing the test_pause function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, strange. I made this function exactly to use in both tests.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured that was your intention, and it makes perfect sense to me!

@@ -31,6 +32,8 @@ def do_GET(self):
break
self.wfile.write(data)
else:
if path.endswith("ef2f2629dc9263fdf3c0f032563a2d757623bbc11cf99df25c3c3f258dccbe.commitmeta"):
time.sleep(1.5)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this sleep necessary? Might be worth a comment with a reference to the appropriate test case since it is not obvious.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because ostree calls progress callback every N miliseconds. To be sure our callback will be called we need to have this sleep.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, that makes sense. A comment in the code is still a good idea, though. Thanks!

@patriotyk patriotyk force-pushed the ostree_pause branch 4 times, most recently from 45d8bd5 to 79df4a3 Compare November 19, 2018 15:00
@patriotyk
Copy link
Contributor Author

I have updated PR and now there is only ostree memory leaks which has been fixed in new version. Should I supress those leaks too? Or we will use newer version of ostree?

@patriotyk patriotyk force-pushed the ostree_pause branch 3 times, most recently from 2dd7a63 to a0067ed Compare November 20, 2018 15:57
@pattivacek
Copy link
Collaborator

The failure on Jenkins:

[ RUN      ] fetcher.test_pause_ostree
created: /tmp/aktualizr-6bb5-daac-7d92-bc71/d2bd-1ae9-dir
No download in progress, can't pause.
Download is already paused.
Download is not paused, can't resume.
ostree-pull: Receiving metadata objects: 1 outstanding: 1
ostree-pull: Receiving metadata objects: 2 outstanding: 1
Error of pulling image: Writing content object: fchown: Operation not permitted
/home/laurent/jenkins-slave/jenkins-home/workspace/aktualizr_PR-1007-NGATZZPT5YMGPNEXMNCFKUOQSHRZXVBDAGI3P4B4S6L4N4Q22OPA@3/src/libaktualizr/uptane/fetcher_test.cc:105: Failure
Value of: result
  Actual: false
Expected: true
[  FAILED  ] fetcher.test_pause_ostree (16124 ms)
[ RUN      ] fetcher.test_pause_binary
created: /tmp/aktualizr-6bb5-daac-7d92-bc71/e2db-8eaa-dir
No download in progress, can't pause.
No file 'large_interrupted' with matched hash in the database
Download is already paused.
Download is not paused, can't resume.
Error while downloading a target: The target's calculated hash did not match the hash in the metadata.
/home/laurent/jenkins-slave/jenkins-home/workspace/aktualizr_PR-1007-NGATZZPT5YMGPNEXMNCFKUOQSHRZXVBDAGI3P4B4S6L4N4Q22OPA@3/src/libaktualizr/uptane/fetcher_test.cc:105: Failure
Value of: result
  Actual: false
Expected: true
[  FAILED  ] fetcher.test_pause_binary (7996 ms)

@patriotyk
Copy link
Contributor Author

Looks like it is permissions problem. Do we run under root? ostree librarry can't change owner of fetched files.

@lbonn
Copy link
Contributor

lbonn commented Nov 21, 2018

To answer your question: no we do not run under root and it would be nice to keep it that way if possible.

@patriotyk
Copy link
Contributor Author

But I can't do here anything, we should be able to change owner of files in our temporary directory. It is issue of jenkins configuration.

@lbonn
Copy link
Contributor

lbonn commented Nov 21, 2018

Did not work... That's annoying.

edit: also noticed the opcua build failure, I'll fix it in #1012.

@lbonn
Copy link
Contributor

lbonn commented Nov 22, 2018

As #1012 has been merged, rebasing should fix the Travis failure.

As for the fchown permission, I've just tried using ./scripts/run_docker_test.sh from the jenkins user on the CI machine and it indeed fails the same way (it does work if I try it on my machine from my local user).

It indicates that it is more likely to be system/docker related and not from jenkins' configuration.

Signed-off-by: Serhiy Stetskovych <patriotyk@gmail.com>
@patriotyk
Copy link
Contributor Author

How it resolves this issue?

@patriotyk
Copy link
Contributor Author

patriotyk commented Nov 23, 2018

I found the root of problem and solution.

The problem is in ostree code. I created fchown call wrapper and loaded it with LD_PRELOAD. It showed me, that ostree tries to change owner of deleted file. On some systems it works, but on some doesn't. I think it depends on filesystem type. Also I have found that ostree doesn't call fchown on 'bare-user' repo type. So if i change repo from 'bare' to 'bare-user' the problem goes away.
I have prepared one line fix, but for now I just waiting for CI finish, to check if embeding submodule to our source tree resolves the issue.

Also I removed '--previleged' commit because it is no needed.

@lbonn
Copy link
Contributor

lbonn commented Nov 23, 2018

Great work @patriotyk! For what it's worth I run btrfs on my machine, where the test works and I think ostree has some custom code to take advantage of the CoW mechanism there. So maybe it breaks on non-btrfs?

If we have easy reproduction steps, it could be worth it to report it upstream.

Signed-off-by: Serhiy Stetskovych <patriotyk@gmail.com>
@patriotyk
Copy link
Contributor Author

patriotyk commented Nov 23, 2018

I use ext4 and it works too. What the filesystem is on Jenkins machine?

@lbonn
Copy link
Contributor

lbonn commented Nov 23, 2018

It seems to have failed the same way on both Jenkins machines. One is using ext4, the other btrfs...


TemporaryDirectory temp_dir;
int r = system((std::string("cp -r ") + argv[1] + std::string(" ") + temp_dir.PathString()).c_str());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use Utils::copyDir?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried but it doesn't work. Looks like 'Utils::copyDir' has problems with symlink copying.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok that should be fine for now then. Could you add a comment to document that?

@pattivacek
Copy link
Collaborator

It seems to have failed the same way on both Jenkins machines. One is using ext4, the other btrfs...

@lbonn Did you restart the CI jobs, or how did this pass?

@patriotyk Really good catch, by the way!

@lbonn
Copy link
Contributor

lbonn commented Nov 23, 2018

@patrickvacek the fix is to use bare-user, it seems to work in all case (see last commit)

The question was: what makes it fail in bare mode. Apparently it works on my machine (btrfs), serhiy's (ext4) but not on the CI machines (btrfs and ext4).

But it shouldn't hold the PR, this was for the sake of understanding.

@pattivacek
Copy link
Collaborator

@patriotyk Also, do you mind "checking" the boxes in actions.md for Download an OSTree package and Verify an OSTree package if you believe those items are properly covered by your new test. Please add "fetcher_test.cc" on those lines as well, and ideally add the same strings ("Download an OSTree package" etc.) to the test case itself so it is easy to grep for.

@pattivacek
Copy link
Collaborator

@lbonn Ah, okay, thanks, I misunderstood your previous comment. I was concerned there was still something going wrong.

Signed-off-by: Serhiy Stetskovych <patriotyk@gmail.com>
@lbonn lbonn merged commit b98aa42 into master Nov 27, 2018
@lbonn lbonn deleted the ostree_pause branch November 27, 2018 08:47
@pattivacek
Copy link
Collaborator

I'm testing this now with qemu and pausing does not seem to have an effect. It continues to download despite claiming to be paused. @patriotyk Can you reproduce?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants