File: pagemap.cc

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (117 lines) | stat: -rw-r--r-- 3,394 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "chromeos/ash/components/memory/pagemap.h"

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string>

#include "base/logging.h"
#include "base/memory/page_size.h"
#include "base/posix/eintr_wrapper.h"
#include "base/strings/stringprintf.h"
#include "base/threading/scoped_blocking_call.h"
#include "chromeos/ash/components/memory/aligned_memory.h"

namespace ash {
namespace memory {

namespace {
constexpr char kPagemapFileFormat[] = "/proc/%d/pagemap";
}

Pagemap::~Pagemap() = default;

Pagemap::Pagemap(pid_t pid) {
  if (pid) {
    std::string pagemap_file = base::StringPrintf(kPagemapFileFormat, pid);
    fd_.reset(HANDLE_EINTR(open(pagemap_file.c_str(), O_RDONLY)));
  }
}

bool Pagemap::IsValid() const {
  return fd_.is_valid();
}

bool Pagemap::GetEntries(uint64_t address,
                         uint64_t length,
                         std::vector<PagemapEntry>* entries) const {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::WILL_BLOCK);
  DCHECK(IsValid());
  DCHECK(entries);

  const size_t kPageSize = base::GetPageSize();
  DCHECK(IsPageAligned(address));
  DCHECK(IsPageAligned(length));

  // The size of each pagemap entry to calculate our offset in the file.
  uint64_t num_pages = length / kPageSize;

  if (entries->size() != num_pages) {
    // Shrink or grow entries to the correct length if it was not already.
    entries->resize(num_pages);
    entries->shrink_to_fit();  // If we made it smaller shrink capacity.
  }

  uint64_t pagemap_offset = (address / kPageSize) * sizeof(PagemapEntry);
  uint64_t pagemap_len = num_pages * sizeof(PagemapEntry);

  memset(entries->data(), 0, pagemap_len);

  // The caller was expected to provide a buffer large enough for the number of
  // pages in the region.
  uint64_t total_read = 0;
  while (total_read < pagemap_len) {
    ssize_t bytes_read = HANDLE_EINTR(
        pread(fd_.get(), reinterpret_cast<char*>(entries->data()) + total_read,
              pagemap_len - total_read, pagemap_offset + total_read));

    if (bytes_read <= 0) {
      return false;
    }
    total_read += bytes_read;
  }

  return true;
}

bool Pagemap::GetNumberOfPagesPresent(uint64_t address,
                                      uint64_t length,
                                      uint64_t* pages_present) const {
  DCHECK(pages_present);
  *pages_present = 0;

  std::vector<Pagemap::PagemapEntry> entries(length / base::GetPageSize());
  if (!GetEntries(address, length, &entries)) {
    return false;
  }

  for (const Pagemap::PagemapEntry& entry : entries) {
    if (entry.page_present)
      (*pages_present)++;
  }

  return true;
}

bool Pagemap::IsFullyPresent(uint64_t address, uint64_t length) const {
  const size_t kPageSize = base::GetPageSize();
  uint64_t pages_present = 0;
  if (!GetNumberOfPagesPresent(address, length, &pages_present)) {
    LOG(WARNING) << "Unable to get pagemap entry";
    return false;
  }
  return (length / kPageSize) == pages_present;
}

}  // namespace memory
}  // namespace ash