blob: 0eec6f2507fe02e080222a89b23c0f4205354642 [file] [log] [blame]
Patrick Ventureef3aead2018-09-12 08:53:29 -07001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Patrick Venturecd8dab42019-01-15 19:57:38 -080017#include "manager.hpp"
18
Patrick Venturee50d4e42018-10-23 09:50:27 -070019#include <algorithm>
Kun Yib61a88b2019-11-12 22:50:34 -080020#include <iostream>
Patrick Ventureb3e07e22018-09-27 15:11:57 -070021#include <memory>
Patrick Ventureef3aead2018-09-12 08:53:29 -070022#include <string>
23#include <vector>
24
25namespace blobs
26{
27
Kun Yib61a88b2019-11-12 22:50:34 -080028void BlobManager::eraseSession(GenericBlobInterface* handler, uint16_t session)
29{
30 sessions.erase(session);
31 /* Ok for openSessions[handler] to be an empty set */
32 openSessions[handler].erase(session);
Kun Yi9ce83482019-11-14 13:08:39 -080033
34 auto path = getPath(session);
35 openFiles[path]--;
36 if (openFiles[path] == 0)
37 {
38 openFiles.erase(path);
39 }
Kun Yib61a88b2019-11-12 22:50:34 -080040}
41
42void BlobManager::cleanUpStaleSessions(GenericBlobInterface* handler)
43{
44 if (openSessions.count(handler) == 0)
45 {
46 return;
47 }
48
49 auto timeNow = std::chrono::steady_clock::now();
50 std::set<uint16_t> expiredSet;
51
52 for (auto sessionId : openSessions[handler])
53 {
54 if (timeNow - sessions[sessionId].lastActionTime >= sessionTimeout)
55 {
56 expiredSet.insert(sessionId);
57 }
58 }
59
60 for (auto sessionId : expiredSet)
61 {
62 std::cerr << "phosphor-ipmi-blobs: expiring stale session " << sessionId
63 << std::endl;
64
65 /* We do a best case recovery by issuing an expire call. If it fails
66 * don't erase sessions since the handler side might be still tracking
67 * it as open. */
68 if (handler->expire(sessionId))
69 {
70 eraseSession(handler, sessionId);
71 }
72 else
73 {
74 std::cerr << "phosphor-ipmi-blobs: failed to expire session "
75 << sessionId << std::endl;
76 }
77 }
78}
79
Patrick Ventureef3aead2018-09-12 08:53:29 -070080bool BlobManager::registerHandler(std::unique_ptr<GenericBlobInterface> handler)
81{
82 if (!handler)
83 {
84 return false;
85 }
86
87 handlers.push_back(std::move(handler));
88 return true;
89}
90
91uint32_t BlobManager::buildBlobList()
92{
93 /* Clear out the current list (IPMI handler is presently single-threaded).
94 */
95 ids.clear();
96
97 /* Grab the list of blobs and extend the local list */
Patrick Venturea6e21a02018-10-23 09:45:04 -070098 for (const auto& h : handlers)
Patrick Ventureef3aead2018-09-12 08:53:29 -070099 {
100 std::vector<std::string> blobs = h->getBlobIds();
101 ids.insert(ids.end(), blobs.begin(), blobs.end());
102 }
103
104 return ids.size();
105}
106
107std::string BlobManager::getBlobId(uint32_t index)
108{
109 /* Range check. */
110 if (index >= ids.size())
111 {
112 return "";
113 }
114
115 return ids[index];
116}
117
118bool BlobManager::open(uint16_t flags, const std::string& path,
119 uint16_t* session)
120{
121 GenericBlobInterface* handler = getHandler(path);
122
123 /* No handler found. */
124 if (!handler)
125 {
126 return false;
127 }
128
Patrick Venture2f581512019-01-10 09:30:36 -0800129 /* No sessions available... */
Patrick Ventureef3aead2018-09-12 08:53:29 -0700130 if (!getSession(session))
131 {
132 return false;
133 }
134
135 /* Verify flags - must be at least read or write */
136 if (!(flags & (OpenFlags::read | OpenFlags::write)))
137 {
138 /* Neither read not write set, which means calls to Read/Write will
139 * reject. */
140 return false;
141 }
142
Kun Yib61a88b2019-11-12 22:50:34 -0800143 /* Try to clean up anything that's falling out of cleanup timeout for this
144 * handler */
145 cleanUpStaleSessions(handler);
146
Patrick Ventureef3aead2018-09-12 08:53:29 -0700147 if (!handler->open(*session, flags, path))
148 {
149 return false;
150 }
151
152 /* Associate session with handler */
153 sessions[*session] = SessionInfo(path, handler, flags);
Kun Yib61a88b2019-11-12 22:50:34 -0800154 openSessions[handler].insert(*session);
Kun Yi9ce83482019-11-14 13:08:39 -0800155 openFiles[path]++;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700156 return true;
157}
158
159GenericBlobInterface* BlobManager::getHandler(const std::string& path)
160{
161 /* Find a handler. */
Patrick Venturee50d4e42018-10-23 09:50:27 -0700162 auto h = std::find_if(
163 handlers.begin(), handlers.end(),
164 [&path](const auto& iter) { return (iter->canHandleBlob(path)); });
165 if (h != handlers.end())
Patrick Ventureef3aead2018-09-12 08:53:29 -0700166 {
Patrick Venturee50d4e42018-10-23 09:50:27 -0700167 return h->get();
Patrick Ventureef3aead2018-09-12 08:53:29 -0700168 }
169
Patrick Venturee50d4e42018-10-23 09:50:27 -0700170 return nullptr;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700171}
172
Kun Yifea1d812019-11-14 11:38:44 -0800173GenericBlobInterface* BlobManager::getActionHandle(uint16_t session,
174 uint16_t requiredFlags)
175{
176 if (auto item = sessions.find(session);
177 item != sessions.end() && (item->second.flags & requiredFlags))
178 {
179 item->second.lastActionTime = std::chrono::steady_clock::now();
180 return item->second.handler;
181 }
182 return nullptr;
183}
184
Patrick Ventureef3aead2018-09-12 08:53:29 -0700185std::string BlobManager::getPath(uint16_t session) const
186{
Kun Yifea1d812019-11-14 11:38:44 -0800187 if (auto item = sessions.find(session); item != sessions.end())
Patrick Ventureef3aead2018-09-12 08:53:29 -0700188 {
Kun Yifea1d812019-11-14 11:38:44 -0800189 return item->second.blobId;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700190 }
191
Kun Yifea1d812019-11-14 11:38:44 -0800192 return "";
Patrick Ventureef3aead2018-09-12 08:53:29 -0700193}
194
Patrick Venture8bc11772019-06-04 07:20:24 -0700195bool BlobManager::stat(const std::string& path, BlobMeta* meta)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700196{
197 /* meta should never be NULL. */
198 GenericBlobInterface* handler = getHandler(path);
199
200 /* No handler found. */
201 if (!handler)
202 {
203 return false;
204 }
205
206 return handler->stat(path, meta);
207}
208
Patrick Venture8bc11772019-06-04 07:20:24 -0700209bool BlobManager::stat(uint16_t session, BlobMeta* meta)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700210{
Kun Yic892f4a2019-11-19 13:42:46 -0800211 if (auto handler = getActionHandle(session))
Patrick Ventureef3aead2018-09-12 08:53:29 -0700212 {
Kun Yic892f4a2019-11-19 13:42:46 -0800213 return handler->stat(session, meta);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700214 }
Kun Yic892f4a2019-11-19 13:42:46 -0800215 return false;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700216}
217
218bool BlobManager::commit(uint16_t session, const std::vector<uint8_t>& data)
219{
Kun Yic892f4a2019-11-19 13:42:46 -0800220 if (auto handler = getActionHandle(session))
Patrick Ventureef3aead2018-09-12 08:53:29 -0700221 {
Kun Yic892f4a2019-11-19 13:42:46 -0800222 return handler->commit(session, data);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700223 }
Kun Yic892f4a2019-11-19 13:42:46 -0800224 return false;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700225}
226
227bool BlobManager::close(uint16_t session)
228{
Kun Yic892f4a2019-11-19 13:42:46 -0800229 if (auto handler = getActionHandle(session))
Patrick Ventureef3aead2018-09-12 08:53:29 -0700230 {
Kun Yic892f4a2019-11-19 13:42:46 -0800231 if (!handler->close(session))
232 {
233 return false;
234 }
Kun Yib61a88b2019-11-12 22:50:34 -0800235 eraseSession(handler, session);
Kun Yic892f4a2019-11-19 13:42:46 -0800236 return true;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700237 }
Kun Yic892f4a2019-11-19 13:42:46 -0800238 return false;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700239}
240
241std::vector<uint8_t> BlobManager::read(uint16_t session, uint32_t offset,
242 uint32_t requestedSize)
243{
Patrick Venture86c87f52019-02-01 14:44:15 -0800244 /* TODO: Currently, configure_ac isn't finding libuserlayer, w.r.t the
245 * symbols I need.
246 */
247
248 /** The channel to use for now.
249 * TODO: We will receive this information through the IPMI message call.
250 */
251 // const int ipmiChannel = ipmi::currentChNum;
252 /** This information is transport specific.
253 * TODO: We need a way to know this dynamically.
254 * on BT, 4 bytes of header, and 1 reply code.
255 */
256 // uint32_t maxTransportSize = ipmi::getChannelMaxTransferSize(ipmiChannel);
257
Kun Yic892f4a2019-11-19 13:42:46 -0800258 if (auto handler = getActionHandle(session, OpenFlags::read))
259 {
260 return handler->read(session, offset,
261 std::min(maximumReadSize, requestedSize));
262 }
263 return {};
Patrick Ventureef3aead2018-09-12 08:53:29 -0700264}
265
266bool BlobManager::write(uint16_t session, uint32_t offset,
267 const std::vector<uint8_t>& data)
268{
Kun Yic892f4a2019-11-19 13:42:46 -0800269 if (auto handler = getActionHandle(session, OpenFlags::write))
Patrick Ventureef3aead2018-09-12 08:53:29 -0700270 {
Kun Yic892f4a2019-11-19 13:42:46 -0800271 return handler->write(session, offset, data);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700272 }
Kun Yifea1d812019-11-14 11:38:44 -0800273 return false;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700274}
275
276bool BlobManager::deleteBlob(const std::string& path)
277{
278 GenericBlobInterface* handler = getHandler(path);
279
280 /* No handler found. */
281 if (!handler)
282 {
283 return false;
284 }
285
286 /* Check if the file has any open handles. */
Kun Yi9ce83482019-11-14 13:08:39 -0800287 if (openFiles[path] > 0)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700288 {
289 return false;
290 }
291
292 /* Try deleting it. */
293 return handler->deleteBlob(path);
294}
295
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700296bool BlobManager::writeMeta(uint16_t session, uint32_t offset,
297 const std::vector<uint8_t>& data)
298{
Kun Yic892f4a2019-11-19 13:42:46 -0800299 if (auto handler = getActionHandle(session))
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700300 {
Kun Yic892f4a2019-11-19 13:42:46 -0800301 return handler->writeMeta(session, offset, data);
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700302 }
Kun Yic892f4a2019-11-19 13:42:46 -0800303 return false;
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700304}
305
Patrick Ventureef3aead2018-09-12 08:53:29 -0700306bool BlobManager::getSession(uint16_t* sess)
307{
308 uint16_t tries = 0;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700309
310 if (!sess)
311 {
312 return false;
313 }
314
315 /* This is not meant to fail as you have 64KiB values available. */
316
317 /* TODO(venture): We could just count the keys in the session map to know
318 * if it's full.
319 */
320 do
321 {
Patrick Venturec9ad5ff2018-10-12 17:05:49 -0700322 uint16_t lsess = next++;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700323 if (!sessions.count(lsess))
324 {
325 /* value not in use, return it. */
326 (*sess) = lsess;
327 return true;
328 }
329 } while (++tries < 0xffff);
330
331 return false;
332}
Patrick Ventureb3e07e22018-09-27 15:11:57 -0700333
334static std::unique_ptr<BlobManager> manager;
335
Patrick Venture73eb6872018-10-01 18:37:34 -0700336ManagerInterface* getBlobManager()
Patrick Ventureb3e07e22018-09-27 15:11:57 -0700337{
338 if (manager == nullptr)
339 {
340 manager = std::make_unique<BlobManager>();
341 }
342
343 return manager.get();
344}
345
Patrick Ventureef3aead2018-09-12 08:53:29 -0700346} // namespace blobs