]>
git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/src/core/fsnotify.cc
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.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
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
19 * Copyright 2020 ScyllaDB Ltd.
22 #include <seastar/core/internal/pollable_fd.hh>
23 #include <seastar/core/posix.hh>
24 #include <seastar/core/reactor.hh>
25 #include <seastar/core/fsnotify.hh>
27 namespace seastar::experimental
{
29 class fsnotifier::impl
: public enable_shared_from_this
<impl
> {
30 class my_poll_fd
: public pollable_fd
{
32 using pollable_fd::pollable_fd
;
33 using pollable_fd::get_fd
;
35 operator int() const {
40 watch_token _close_dummy
= -1;
43 : _fd(file_desc::inotify_init(IN_NONBLOCK
| IN_CLOEXEC
))
45 void remove_watch(watch_token
);
46 future
<watch_token
> create_watch(const sstring
& path
, flags events
);
47 future
<std::vector
<event
>> wait();
54 void fsnotifier::impl::remove_watch(watch_token token
) {
56 auto res
= ::inotify_rm_watch(_fd
, token
);
57 // throw if any other error than EINVAL.
58 throw_system_error_on(res
== -1 && errno
!= EINVAL
, "could not remove inotify watch");
62 future
<fsnotifier::watch_token
> fsnotifier::impl::create_watch(const sstring
& path
, flags events
) {
64 throw std::runtime_error("attempting to use closed notifier");
66 return engine().inotify_add_watch(_fd
, path
, uint32_t(events
));
69 future
<std::vector
<fsnotifier::event
>> fsnotifier::impl::wait() {
70 // be paranoid about buffer alignment
71 auto buf
= temporary_buffer
<char>::aligned(std::max(alignof(::inotify_event
), alignof(int64_t)), 4096);
72 auto f
= _fd
.read_some(buf
.get_write(), buf
.size());
73 return f
.then([me
= shared_from_this(), buf
= std::move(buf
)](size_t n
) {
75 auto e
= buf
.get() + n
;
77 std::vector
<event
> events
;
80 auto ev
= reinterpret_cast<const ::inotify_event
*>(p
);
81 if (ev
->wd
== me
->_close_dummy
&& me
->_close_dummy
!= -1) {
84 events
.emplace_back(event
{
85 ev
->wd
, flags(ev
->mask
), ev
->cookie
,
86 ev
->len
!= 0 ? sstring(ev
->name
) : sstring
{}
89 p
+= sizeof(::inotify_event
) + ev
->len
;
96 void fsnotifier::impl::shutdown() {
97 // reactor does not yet have
98 // any means of "shutting down" a non-socket read,
99 // so we work around this by creating a watch for something ubiquitous,
100 // then removing the watch while adding a mark.
101 // This will cause any event waiter to wake up, but ignore the event for our
103 (void)create_watch("/", flags::delete_self
).then([me
= shared_from_this()](watch_token t
) {
104 me
->_close_dummy
= t
;
109 fsnotifier::watch::~watch() {
111 _impl
->remove_watch(_token
);
115 fsnotifier::watch::watch(watch
&&) noexcept
= default;
116 fsnotifier::watch
& fsnotifier::watch::operator=(watch
&&) noexcept
= default;
118 fsnotifier::watch_token
fsnotifier::watch::release() {
123 fsnotifier::watch::watch(shared_ptr
<impl
> impl
, watch_token token
)
125 , _impl(std::move(impl
))
128 fsnotifier::fsnotifier()
129 : _impl(make_shared
<impl
>())
132 fsnotifier::~fsnotifier() = default;
134 fsnotifier::fsnotifier(fsnotifier
&&) = default;
135 fsnotifier
& fsnotifier::operator=(fsnotifier
&&) = default;
137 future
<fsnotifier::watch
> fsnotifier::create_watch(const sstring
& path
, flags events
) {
138 return _impl
->create_watch(path
, events
).then([this](watch_token token
) {
139 return watch(_impl
, token
);
143 future
<std::vector
<fsnotifier::event
>> fsnotifier::wait() const {
144 return _impl
->wait();
147 void fsnotifier::shutdown() {
151 bool fsnotifier::active() const {
152 return _impl
->active();