]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/src/core/fsnotify.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / seastar / src / core / fsnotify.cc
CommitLineData
f67539c2
TL
1/*
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18/*
19 * Copyright 2020 ScyllaDB Ltd.
20 */
21
22#include <seastar/core/internal/pollable_fd.hh>
23#include <seastar/core/posix.hh>
24#include <seastar/core/reactor.hh>
25#include "fsnotify.hh"
26
27class seastar::fsnotifier::impl : public enable_shared_from_this<impl> {
28 class my_poll_fd : public pollable_fd {
29 public:
30 using pollable_fd::pollable_fd;
31 using pollable_fd::get_fd;
32
33 operator int() const {
34 return get_fd();
35 }
36 };
37 my_poll_fd _fd;
38 watch_token _close_dummy = -1;
39public:
40 impl()
41 : _fd(file_desc::inotify_init(IN_NONBLOCK | IN_CLOEXEC))
42 {}
43 void remove_watch(watch_token);
44 future<watch_token> create_watch(const sstring& path, flags events);
45 future<std::vector<event>> wait();
46 void shutdown();
47 bool active() const {
48 return bool(_fd);
49 }
50};
51
52void seastar::fsnotifier::impl::remove_watch(watch_token token) {
53 if (active()) {
54 auto res = ::inotify_rm_watch(_fd, token);
55 // throw if any other error than EINVAL.
56 throw_system_error_on(res == -1 && errno != EINVAL, "could not remove inotify watch");
57 }
58}
59
60seastar::future<seastar::fsnotifier::watch_token> seastar::fsnotifier::impl::create_watch(const sstring& path, flags events) {
61 if (!active()) {
62 throw std::runtime_error("attempting to use closed notifier");
63 }
64 return engine().inotify_add_watch(_fd, path, uint32_t(events));
65}
66
67seastar::future<std::vector<seastar::fsnotifier::event>> seastar::fsnotifier::impl::wait() {
68 // be paranoid about buffer alignment
69 auto buf = temporary_buffer<char>::aligned(std::max(alignof(::inotify_event), alignof(int64_t)), 4096);
70 auto f = _fd.read_some(buf.get_write(), buf.size());
71 return f.then([me = shared_from_this(), buf = std::move(buf)](size_t n) {
72 auto p = buf.get();
73 auto e = buf.get() + n;
74
75 std::vector<event> events;
76
77 while (p < e) {
78 auto ev = reinterpret_cast<const ::inotify_event*>(p);
79 if (ev->wd == me->_close_dummy && me->_close_dummy != -1) {
80 me->_fd.close();
81 } else {
82 events.emplace_back(event {
83 ev->wd, flags(ev->mask), ev->cookie,
84 ev->len != 0 ? sstring(ev->name) : sstring{}
85 });
86 }
87 p += sizeof(::inotify_event) + ev->len;
88 }
89
90 return events;
91 });
92}
93
94void seastar::fsnotifier::impl::shutdown() {
95 // reactor does not yet have
96 // any means of "shutting down" a non-socket read,
97 // so we work around this by creating a watch for something ubiquitous,
98 // then removing the watch while adding a mark.
99 // This will cause any event waiter to wake up, but ignore the event for our
100 // dummy.
101 (void)create_watch("/", flags::delete_self).then([me = shared_from_this()](watch_token t) {
102 me->_close_dummy = t;
103 me->remove_watch(t);
104 });
105}
106
107seastar::fsnotifier::watch::~watch() {
108 if (_impl) {
109 _impl->remove_watch(_token);
110 }
111}
112
113seastar::fsnotifier::watch::watch(watch&&) noexcept = default;
114seastar::fsnotifier::watch& seastar::fsnotifier::watch::operator=(watch&&) noexcept = default;
115
116seastar::fsnotifier::watch_token seastar::fsnotifier::watch::release() {
117 _impl = {};
118 return _token;
119}
120
121seastar::fsnotifier::watch::watch(shared_ptr<impl> impl, watch_token token)
122 : _token(token)
123 , _impl(std::move(impl))
124{}
125
126seastar::fsnotifier::fsnotifier()
127 : _impl(make_shared<impl>())
128{}
129
130seastar::fsnotifier::~fsnotifier() = default;
131
132seastar::fsnotifier::fsnotifier(fsnotifier&&) = default;
133seastar::fsnotifier& seastar::fsnotifier::operator=(fsnotifier&&) = default;
134
135seastar::future<seastar::fsnotifier::watch> seastar::fsnotifier::create_watch(const sstring& path, flags events) {
136 return _impl->create_watch(path, events).then([this](watch_token token) {
137 return watch(_impl, token);
138 });
139}
140
141seastar::future<std::vector<seastar::fsnotifier::event>> seastar::fsnotifier::wait() const {
142 return _impl->wait();
143}
144
145void seastar::fsnotifier::shutdown() {
146 _impl->shutdown();
147}
148
149bool seastar::fsnotifier::active() const {
150 return _impl->active();
151}