2#include "advisory-lock-table.h"
4namespace PosixAdvisory {
6bool sameOwner(
const Grant& a,
const Grant& b) {
7 return a.owner == b.owner && a.kind == b.kind;
10bool sameSet(
const Grant& a,
const Grant& b) {
11 return a.inode == b.inode && a.name == b.name;
14bool overlaps(
const Range& a,
const Range& b) {
15 return a.first <= b.last && b.first <= a.last;
18bool conflicts(
const Grant& a,
const Grant& b) {
19 return a.type != Type::Unlock && b.type != Type::Unlock && sameSet(a, b) && !sameOwner(a, b) &&
20 overlaps(a.range, b.range) && (a.type == Type::Write || b.type == Type::Write);
24RangeResult normalise(
int whence, int64_t start, int64_t length, uint64_t position,
25 uint64_t fileSize, Range& result) {
29 }
else if (whence == 2) {
31 }
else if (whence != 0) {
32 return RangeResult::Invalid;
35 if (base >
static_cast<uint64_t
>(LastOffset) ||
36 __builtin_add_overflow(
static_cast<int64_t
>(base), start, &first)) {
37 return RangeResult::Overflow;
40 return RangeResult::Invalid;
42 int64_t last = LastOffset;
44 if (__builtin_add_overflow(first, length - 1, &last)) {
45 return RangeResult::Overflow;
47 }
else if (length < 0) {
51 return RangeResult::Invalid;
54 result = {first, last};
55 return RangeResult::Success;
58Table::Table(Grant* current, Grant* scratch,
size_t capacity)
59 : m_Current(current), m_Scratch(scratch), m_Capacity(capacity) {}
61bool Table::conflict(
const Grant& request, Grant& result)
const {
63 for (
size_t i = 0; i < m_Count; ++i) {
64 const Grant& grant = m_Current[i];
65 if (conflicts(request, grant) && (!found || grant.range.first < result.range.first)) {
73bool Table::query(
const Grant& request, Grant& result)
const {
74 if (request.type != Type::Unlock)
75 return conflict(request, result);
78 if (request.kind != OwnerKind::OpenDescription || request.name != Namespace::Record)
81 for (
size_t i = 0; i < m_Count; ++i) {
82 const Grant& grant = m_Current[i];
83 if (sameSet(request, grant) && sameOwner(request, grant) &&
84 overlaps(request.range, grant.range) &&
85 (!found || grant.range.first < result.range.first)) {
93bool Table::append(
const Grant& grant,
size_t& count) {
94 if (count == m_Capacity)
96 m_Scratch[count++] = grant;
100Result Table::apply(
const Grant& request) {
102 if (conflict(request, blocked))
103 return Result::Conflict;
104 Grant replacement = request;
105 if (replacement.type != Type::Unlock) {
108 for (
size_t i = 0; i < m_Count;) {
109 const Grant& old = m_Current[i];
110 const bool touching =
111 overlaps(replacement.range, old.range) ||
112 (replacement.range.last != LastOffset && replacement.range.last + 1 == old.range.first) ||
113 (old.range.last != LastOffset && old.range.last + 1 == replacement.range.first);
114 if (sameSet(old, replacement) && sameOwner(old, replacement) &&
115 old.type == replacement.type && touching &&
116 (old.range.first < replacement.range.first || old.range.last > replacement.range.last)) {
117 if (old.range.first < replacement.range.first)
118 replacement.range.first = old.range.first;
119 if (old.range.last > replacement.range.last)
120 replacement.range.last = old.range.last;
128 if (replacement.type != Type::Unlock && !append(replacement, staged))
130 for (
size_t i = 0; i < m_Count; ++i) {
131 const Grant& old = m_Current[i];
132 if (!sameSet(old, replacement) || !sameOwner(old, replacement) ||
133 !overlaps(old.range, replacement.range)) {
134 if (!append(old, staged))
138 if (old.range.first < replacement.range.first) {
140 left.range.last = replacement.range.first - 1;
141 if (!append(left, staged))
144 if (old.range.last > replacement.range.last) {
146 right.range.first = replacement.range.last + 1;
147 if (!append(right, staged))
151 Grant* previous = m_Current;
152 m_Current = m_Scratch;
153 m_Scratch = previous;
155 return Result::Success;
158bool Table::removeOwner(uint64_t owner, uintptr_t inode) {
160 for (
size_t i = 0; i < m_Count; ++i) {
161 const Grant& grant = m_Current[i];
162 if (grant.owner != owner || (inode && grant.inode != inode)) {
163 m_Current[kept++] = grant;
166 const bool changed = kept != m_Count;
171bool Table::wouldDeadlock(
const Grant& request,
const Grant*
const* waiters,
172 size_t waiterCount)
const {
173 if (request.kind != OwnerKind::Process || request.name != Namespace::Record ||
174 request.type == Type::Unlock || waiterCount > MaximumWaiters)
177 uint64_t reachable[MaximumWaiters + 1] = {request.owner};
179 for (
size_t node = 0; node < reached; ++node) {
180 for (
size_t w = 0; w <= waiterCount; ++w) {
181 const Grant* waiting = w == waiterCount ? &request : waiters[w];
182 if (!waiting || waiting->owner != reachable[node] || waiting->kind != OwnerKind::Process ||
183 waiting->name != Namespace::Record)
185 for (
size_t g = 0; g < m_Count; ++g) {
186 const Grant& blocker = m_Current[g];
187 if (blocker.kind != OwnerKind::Process || !conflicts(*waiting, blocker))
189 if (blocker.owner == request.owner)
192 bool hasWait =
false;
193 for (
size_t i = 0; i < waiterCount; ++i) {
194 if (waiters[i] && waiters[i]->owner == blocker.owner &&
195 waiters[i]->kind == OwnerKind::Process && waiters[i]->name == Namespace::Record) {
203 for (
size_t i = 0; i < reached; ++i)
204 seen |= reachable[i] == blocker.owner;
205 if (!seen && reached < MaximumWaiters + 1)
206 reachable[reached++] = blocker.owner;