Commit graph

8667 commits

Author SHA1 Message Date
Pavel Emelyanov
f2f5fd68dd page-xfer: Sanitize xfer core routine
Make it call .write_pagemap once and decide whether or not to
call .write_pages based on the flags caluculated in one place
as well.

Acked-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-17 03:27:02 +03:00
Pavel Emelyanov
daf8b4f75c page-xfer: Move lazy bool on xfer
Same thing for the boolean value saying whether or not to send
lazy pagemaps alone or follow them with the respective pages.
This value is non-true in the single place, so let's simplify
the API and keep this bool on xfer object.

Acked-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-17 03:27:02 +03:00
Pavel Emelyanov
121f07a79f page-xfer: Move iov offset on xfer
The offset in question is used by shmem dumping code to dump
memory segments relative to shmem segment start, no to task
mapping start. The offset value is now the part of the xfer
callback and is typically 0 :) Let's keep this on xfer object
to simplify the xfer API.

Acked-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-17 03:27:02 +03:00
Pavel Emelyanov
efbf59ddf6 page-xfer: Use send_psi everywhere
There are two places left that send ps_iov by hands into
socket. Switch it to use common helper.

Acked-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-17 03:27:02 +03:00
Pavel Emelyanov
f83ba3fe31 page-xfer: Rework send_psi to use send (and flags)
There are cases when we need to specify flags with which
to send the ps_iov, so tune-up the send_psi for that and
use where needed.

Acked-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-17 03:27:02 +03:00
Pavel Emelyanov
4fd66c9d9e page-xfer: Tune up send_psi to accept less args
The only thing it does is puts 4 values on the on-stack ps_iov,
let's avoid double stack copying and put the values on ps_iov
in callers.

Acked-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-17 03:27:02 +03:00
Pavel Emelyanov
3c62260789 page-xfer: Fixup page server protocol for lazy pages
Introduce the PS_IOV_ADD_F command that is to add pages with
flags. We already use the similar notation on page-xfer -- the
single write callback with pagemap and flags. For page-server
let's use the same. Legacy _HOLE and _PAGE handling is kept.

Changed commands numbers are OK, as the commands in question
are still in criu-dev branch.

Acked-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-17 03:27:02 +03:00
Pavel Emelyanov
f9510f67e9 pagemap: Remove seek_pagemap_page
The page_read.seek_pagemap already tunes the pages offset,
so the separate call for skip_pagemap_pages in the routine
in question is always no-op.

Acked-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-17 03:27:00 +03:00
Mike Rapoport
a33b747f7d lazy-pages: fix off-by-one in remap_lazy_iovs
When the remap 'from' parameter matches an IOV end we try to split that IOV
exactly at its end and effectively create an IOV with zero length.
With the off-by-one fix we will skip the IOV in such case as expected.

Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:30:22 +03:00
Mike Rapoport
b1aca099cc test: add test that verifies proper intraction between lazy-pages and THP
Acked-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:30:22 +03:00
Mike Rapoport
9d45bb3987 lazy-pages: fix memory corruption when combining pre-dump with lazy pages
When we combine pre-dump with lazy pages, we populate a part of a memory
region with data that was saved during the pre-dump. Afterwards, the
region is registered with userfaultfd and we expect to get page faults for
the parts of the region that were not yet populated. However, khugepaged
collapses the pages and the page faults we would expect do not occur.

To mitigate this problem we temporarily disable THP for the restored
process, up to the point when we register all the memory regions with
userfaultfd.

https://lists.openvz.org/pipermail/criu/2017-May/037728.html

Reported-by: Adrian Reber <areber@redhat.com>
Acked-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:30:22 +03:00
Mike Rapoport
bbbd597b41 mem: add dump state of THP_DISABLED prctl
Acked-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:30:22 +03:00
Mike Rapoport
5480a2a406 kerndat: add test for availability of PR_SET_THP_DISABLE prctl
The PR_SET_THP_DISABLE prctl allows control of transparent huge pages on
per-process basis. It is available since Linux 3.15, but until recently it
set VM_NOHUGEPAGE for all VMAs created after prctl() call, which prevents
proper restore for combination of pre- and post-copy. A recent change to
prctl(PR_SET_THP_DISABLE) behavior eliminates the use of per-VMA flags and
we can use the new version of the prctl() to disable THP.

Acked-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:30:22 +03:00
Mike Rapoport
9f61de8776 proc_parse: make smaps parsing helpers globally available
The is_vma_range_fmt and parse_vmflags will be required for detection of
availability of PR_SET_THP_DISABLE prctl

Acked-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:30:22 +03:00
Pavel Emelyanov
c8717da44c page-server: Make sync-read re-use the async reading code
Now we have two separate recv-calling routines, that receive
header and pages from page-server. These two can finally be
unified.

After this the sync-read code looks like -- start async one
and wait for it to finish right at once.

Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:30:22 +03:00
Pavel Emelyanov
b31a5d67b3 page-server: Split the code doing async page-read (v2)
This is prerequisite for the next patch.

v2: spellchecks, code reshuffle

Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
Acked-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:30:22 +03:00
Pavel Emelyanov
2cc7e90d5b page-server: Merge async and sync read API calls
Now these two look exactly the same and we can have
only one call with additional sync/async (flags) arg.

Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
Acked-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:30:22 +03:00
Pavel Emelyanov
832f3844f6 page-server: Unify async/sync calls
The newly introduced sync-read call may look exactly
the same as its async pair by using the respective
complete callback.

Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
Acked-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:30:22 +03:00
Pavel Emelyanov
b801cd68d9 page-server: Introduce page_server_start_sync_read
There's no need in two API calls to read xfer header
and pages themselves, so merge them into one single
call.

Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:30:22 +03:00
Mike Rapoport
47b9438628 test/travis: update lazy-pages testing
* drop --keep-going etc from --lazy-pages pass
* add --remote-lazy-pages pass

Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:30:20 +03:00
Mike Rapoport
0ebf7b81fa test/jenkins: update lazy-pages testing
* select excluded tests based on the kernel version
* test local and remote lazy-pages with and withour pre-dump

Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:29:57 +03:00
Mike Rapoport
77c115f3bf test: enable fork* tests for --remote-lazy-pages
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:29:55 +03:00
Mike Rapoport
5306cd0fe8 lazy-pages: don't close page-read for child processes
The page-read for child process is a shallow copy of the parent process
page-read. They share the open file descriptors and the pagemap.
The lpi_fini of the child processes should not release any resources, they
all will be released during lpi_fini of the parent process.

Fixes: #325

Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:29:43 +03:00
Mike Rapoport
1ad1400c8b lazy-pages: use random read from page-pipe instead of splitting it
For the remote lazy pages case, to access pages in the middle of a pipe we
are splitting the page_pipe_buffers and iovecs and use splice() to move the
data between the underlying pipes. After the splits we get page_pipe_buffer
with single iovec that can be used to splice() the data further into the
socket.
This patch replaces the splitting and splicing with use of a helper pipe
and tee(). We tee() the pages from beginning of the pipe up to the last
requested page into a helper pipe, sink the unneeded head part into
/dev/null and we get the requested pages ready for splice() into the
socket.
This allows lazy-pages daemon to request the same page several time, which
is required to properly support fork() after the restore.
As added bonus we simplify the code and reduce amount of pipes that live in
the system.

Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Acked-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:29:43 +03:00
Mike Rapoport
a364f05bf9 lazy-pages: handle_remaining_pages: enable asynchronous reads
Until now once we've started to fetch an iovec we've been waiting until
it's completely copied before returning to event processing loop. Now we
can have several request for the remote pages in flight.

Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Acked-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:29:43 +03:00
Mike Rapoport
7c108b8b8d lazy-pages: make the check for outstanding request more strict
There could be several outstaning requests for the same page, either from
page fault handler or from handle_remaining_pages. Verifying that the
faulting address is already requested is not enough. We need to check if
there any request in flight that covers the faulting address.

Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Acked-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:29:43 +03:00
Pavel Emelyanov
9354582fd2 kdat: Relax uffd checks (v2)
v2: When uffd is present, the reported features may still be 0,
    so we need one more bool for uffd syscall itself.

Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:29:43 +03:00
Mike Rapoport
459b833a8e zdtm: enable fork tests with --lazy-pages
They still will fail with --remote-lazy-pages, so mark them as
'noremotelazy'

Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:29:43 +03:00
Mike Rapoport
eb261b579d zdtm: introduce 'noremotelazy' flag
This allows skipping tests that are not yet run with --remote-lazy-pages,
but can be run with --lazy-pages

Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:29:43 +03:00
Mike Rapoport
a9ea60f8b3 zdtm: check lazy-pages and page-server exit status after test is gone
When running with --lazy-pages or --remote-lazy-pages, the daemons should
run in the background, rather than complete before t.stop() is called.
Many tests try to verify things are ok after test_waitsig() and that's
exactly the place where they access memory and cause page faults.

Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:29:43 +03:00
Mike Rapoport
516b779551 travis-test: select tests skipped by lazy-pages pass more carefully
Most of zdtm test should pass with --lazy-pages with kernels newer than
4.11.
Some test excluded for older kernels surprisingly pass even now, mainly
becuase they do not actually stress userfaultfd, which will be fixed in the
upcoming commits :)
The cmdlinenv00 fails even with kernel 4.11 because of a race between uffd
and gup in the case external process reads /proc/<pid>/cmdline before
memory containing the command line is populated.

Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 12:29:43 +03:00
Mike Rapoport
bd39d5edc5 travis: add lazy-pages run
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 11:47:03 +03:00
Mike Rapoport
583a399732 Update criu/include/linux/userfaultfd.h
This is the version from v4.11-rc5. Apparently, that would be the userfault
ABI for the next few month.

Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 11:47:03 +03:00
Mike Rapoport
27662f2547 lazy-pages: handle exit() based on uffdio_copy return value
The UFFDIO_EVENT_EXIT didn't make it upstream because of possible races in
exit() syscall [1].
The only way to detect that the monitored process is exited is checking for
ENOSPC errno value set by uffdio_copy.

[1] http://www.spinics.net/lists/linux-mm/msg122467.html

Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 11:47:03 +03:00
Mike Rapoport
4c0d56f4e7 lazy-pages: make epollfd part of global daemon state
We only use one epoll instance to manage lazy-pages related I/O. Making
epollfd file-visible will allow cleaner implementation of the restored
process exit() calls tracking.

Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 11:47:03 +03:00
Mike Rapoport
6b1dbb1e63 lazy-pages: drop unneeded forward declaration
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 11:47:03 +03:00
Mike Rapoport
985d154ea6 lazy-pages: add comments about different addresses in lazy_iov and lp_req
Both lazy_iov and lp_req have two fields for address/start: the run-time
address that tracks remaps, and the "dump time" address, which is required
for pagemap accesses.

Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Acked-by: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
2017-09-16 11:47:03 +03:00
Mike Rapoport
8eae2ee844 test: add basic test for uffd events
The lazy-pages daemon have to properly track changes to virtual memory
layout of the restored process. The test verifies that lazy-pages daemon
properly reacts to fork(), exit(), madvise(MADV_DONTNEED) and mremap()
events.
Currently, no zdtm tests would generate UFFD_EVENT_{REMAP,REMOVE}.

Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
2017-09-16 11:47:03 +03:00
Mike Rapoport
de01e0d3dc lazy-pages: request userfaultfd events during API handshake
travis-ci: success for lazy-pages: add non-#PF events handling (rev2)
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
2017-09-16 11:47:03 +03:00
Mike Rapoport
371947c174 lazy-pages: add handling of UFFD_EVENT_FORK
travis-ci: success for lazy-pages: add non-#PF events handling (rev2)
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
2017-09-16 11:47:03 +03:00
Mike Rapoport
d7c0b1f1a2 lazy-pages: handle UFFD_EVENT_EXIT
travis-ci: success for lazy-pages: add non-#PF events handling (rev2)
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
2017-09-16 11:47:03 +03:00
Mike Rapoport
f10b348e96 util: introduce epoll_del_rfd
travis-ci: success for lazy-pages: add non-#PF events handling (rev2)
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
2017-09-16 11:47:03 +03:00
Mike Rapoport
fb90982db5 page-read: introduce dup_page_read
The dup_page_read performs a shallow copy of a page_read object. It is
required for implementation of fork event in lazy-pages daemon.
When a restored process fork()'s a child, the lazy-pages daemon will handle
page faults of the child process, and it will use the parent process memory
dump for that.

travis-ci: success for lazy-pages: add non-#PF events handling (rev2)
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
2017-09-16 11:47:03 +03:00
Mike Rapoport
00436b7c2b page-read: add PID for some debug printouts
Replace "pr<id>" with "pr<pid>-<id>" when printing information about a
particular page-read.

travis-ci: success for lazy-pages: add non-#PF events handling (rev2)
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
2017-09-16 11:47:03 +03:00
Mike Rapoport
2c5e635e74 lazy-pages: add handling of UFFD_EVENT_REMAP
When the restored process calls mremap(), we will see #PF's on the new
addresses and we have to create a correspondence between the addresses
found in the dump and the actual addresses the process uses. For this
purpose we distinguish "live" address and "image" address in the lazy IOVs
and outstanding requests. The "live" address is used to find the
appropriate IOV and in uffd_copy and the "image" address is used to request
pages from the page-read.

If the mremap() call causes the mapping to grow, the additional part will
receive zero pages, as expected.

For the shrinking remaps, we will get UFFD_EVENT_UNMAP for the dropped part
of the mapping.

travis-ci: success for lazy-pages: add non-#PF events handling (rev2)
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
2017-09-16 11:47:03 +03:00
Mike Rapoport
064917442d lazy-pages: introduce split_iov
travis-ci: success for lazy-pages: add non-#PF events handling (rev2)
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
2017-09-16 11:47:03 +03:00
Mike Rapoport
b2ba8493a8 lazy-pages: add handling of UFFD_EVENT_UNMAP
The UNMAP event is generated by userfaultfd when a VMA (or a part of it) is
unmapped from the process address space. We won't receive #PF's at the
unmapped range, but we need to make sure we are not trying to fill that
range at handle_remaining_pages.
Note, that the VMA is gone, so there is no sense to unregister uffd from
it.

travis-ci: success for lazy-pages: add non-#PF events handling (rev2)
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
2017-09-16 11:47:03 +03:00
Mike Rapoport
ba3d099b74 lazy-pages: add handling of UFFD_EVENT_REMOVE
When the restored process calls madvise(MADV_DONTNEED) or
madvise(MADV_REMOVE) the memory range specified by the madvise() call
should be remapped to zero pfn and we should stop monitoring this range in
order to avoid its pollution with data the process does not expect.
All we need to do here, is to unregister the memory range from userfaultfd
and the kernel will take care of the rest.

travis-ci: success for lazy-pages: add non-#PF events handling (rev2)
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
2017-09-16 11:47:03 +03:00
Mike Rapoport
7df4f14be6 cr-check: lazy-pages: detect availability of UNMAP and EXIT events
travis-ci: success for lazy-pages: add non-#PF events handling (rev2)
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
2017-09-16 11:47:03 +03:00
Mike Rapoport
2f2f11ad87 Update criu/include/linux/userfaultfd.h
This is the version from linux-next at the moment.

travis-ci: success for lazy-pages: add non-#PF events handling (rev2)
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
2017-09-16 11:47:03 +03:00