blob: 286b81aebc10be88ce17c9f20e7f16a49060b098 [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
28void BlobManager::incrementOpen(const std::string& path)
29{
30 if (path.empty())
31 {
32 return;
33 }
34
35 openFiles[path] += 1;
36}
37
38void BlobManager::decrementOpen(const std::string& path)
39{
40 if (path.empty())
41 {
42 return;
43 }
44
45 /* TODO(venture): Check into the iterator from find, does it makes sense
46 * to just update it directly? */
47 auto entry = openFiles.find(path);
48 if (entry != openFiles.end())
49 {
50 /* found it, decrement it and remove it if 0. */
51 openFiles[path] -= 1;
52 if (openFiles[path] == 0)
53 {
54 openFiles.erase(path);
55 }
56 }
57}
58
59int BlobManager::getOpen(const std::string& path) const
60{
61 /* No need to input check on the read-only call. */
62 auto entry = openFiles.find(path);
63 if (entry != openFiles.end())
64 {
65 return entry->second;
66 }
67
68 return 0;
69}
70
Kun Yib61a88b2019-11-12 22:50:34 -080071void BlobManager::eraseSession(GenericBlobInterface* handler, uint16_t session)
72{
73 sessions.erase(session);
74 /* Ok for openSessions[handler] to be an empty set */
75 openSessions[handler].erase(session);
76 decrementOpen(getPath(session));
77}
78
79void BlobManager::cleanUpStaleSessions(GenericBlobInterface* handler)
80{
81 if (openSessions.count(handler) == 0)
82 {
83 return;
84 }
85
86 auto timeNow = std::chrono::steady_clock::now();
87 std::set<uint16_t> expiredSet;
88
89 for (auto sessionId : openSessions[handler])
90 {
91 if (timeNow - sessions[sessionId].lastActionTime >= sessionTimeout)
92 {
93 expiredSet.insert(sessionId);
94 }
95 }
96
97 for (auto sessionId : expiredSet)
98 {
99 std::cerr << "phosphor-ipmi-blobs: expiring stale session " << sessionId
100 << std::endl;
101
102 /* We do a best case recovery by issuing an expire call. If it fails
103 * don't erase sessions since the handler side might be still tracking
104 * it as open. */
105 if (handler->expire(sessionId))
106 {
107 eraseSession(handler, sessionId);
108 }
109 else
110 {
111 std::cerr << "phosphor-ipmi-blobs: failed to expire session "
112 << sessionId << std::endl;
113 }
114 }
115}
116
Patrick Ventureef3aead2018-09-12 08:53:29 -0700117bool BlobManager::registerHandler(std::unique_ptr<GenericBlobInterface> handler)
118{
119 if (!handler)
120 {
121 return false;
122 }
123
124 handlers.push_back(std::move(handler));
125 return true;
126}
127
128uint32_t BlobManager::buildBlobList()
129{
130 /* Clear out the current list (IPMI handler is presently single-threaded).
131 */
132 ids.clear();
133
134 /* Grab the list of blobs and extend the local list */
Patrick Venturea6e21a02018-10-23 09:45:04 -0700135 for (const auto& h : handlers)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700136 {
137 std::vector<std::string> blobs = h->getBlobIds();
138 ids.insert(ids.end(), blobs.begin(), blobs.end());
139 }
140
141 return ids.size();
142}
143
144std::string BlobManager::getBlobId(uint32_t index)
145{
146 /* Range check. */
147 if (index >= ids.size())
148 {
149 return "";
150 }
151
152 return ids[index];
153}
154
155bool BlobManager::open(uint16_t flags, const std::string& path,
156 uint16_t* session)
157{
158 GenericBlobInterface* handler = getHandler(path);
159
160 /* No handler found. */
161 if (!handler)
162 {
163 return false;
164 }
165
Patrick Venture2f581512019-01-10 09:30:36 -0800166 /* No sessions available... */
Patrick Ventureef3aead2018-09-12 08:53:29 -0700167 if (!getSession(session))
168 {
169 return false;
170 }
171
172 /* Verify flags - must be at least read or write */
173 if (!(flags & (OpenFlags::read | OpenFlags::write)))
174 {
175 /* Neither read not write set, which means calls to Read/Write will
176 * reject. */
177 return false;
178 }
179
Kun Yib61a88b2019-11-12 22:50:34 -0800180 /* Try to clean up anything that's falling out of cleanup timeout for this
181 * handler */
182 cleanUpStaleSessions(handler);
183
Patrick Ventureef3aead2018-09-12 08:53:29 -0700184 if (!handler->open(*session, flags, path))
185 {
186 return false;
187 }
188
189 /* Associate session with handler */
190 sessions[*session] = SessionInfo(path, handler, flags);
Kun Yib61a88b2019-11-12 22:50:34 -0800191 openSessions[handler].insert(*session);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700192 incrementOpen(path);
193 return true;
194}
195
196GenericBlobInterface* BlobManager::getHandler(const std::string& path)
197{
198 /* Find a handler. */
Patrick Venturee50d4e42018-10-23 09:50:27 -0700199 auto h = std::find_if(
200 handlers.begin(), handlers.end(),
201 [&path](const auto& iter) { return (iter->canHandleBlob(path)); });
202 if (h != handlers.end())
Patrick Ventureef3aead2018-09-12 08:53:29 -0700203 {
Patrick Venturee50d4e42018-10-23 09:50:27 -0700204 return h->get();
Patrick Ventureef3aead2018-09-12 08:53:29 -0700205 }
206
Patrick Venturee50d4e42018-10-23 09:50:27 -0700207 return nullptr;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700208}
209
Patrick Ventureef3aead2018-09-12 08:53:29 -0700210std::string BlobManager::getPath(uint16_t session) const
211{
212 auto item = sessions.find(session);
213 if (item == sessions.end())
214 {
215 return "";
216 }
217
218 return item->second.blobId;
219}
220
Patrick Venture8bc11772019-06-04 07:20:24 -0700221bool BlobManager::stat(const std::string& path, BlobMeta* meta)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700222{
223 /* meta should never be NULL. */
224 GenericBlobInterface* handler = getHandler(path);
225
226 /* No handler found. */
227 if (!handler)
228 {
229 return false;
230 }
231
232 return handler->stat(path, meta);
233}
234
Patrick Venture8bc11772019-06-04 07:20:24 -0700235bool BlobManager::stat(uint16_t session, BlobMeta* meta)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700236{
Kun Yic892f4a2019-11-19 13:42:46 -0800237 if (auto handler = getActionHandle(session))
Patrick Ventureef3aead2018-09-12 08:53:29 -0700238 {
Kun Yic892f4a2019-11-19 13:42:46 -0800239 return handler->stat(session, meta);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700240 }
Kun Yic892f4a2019-11-19 13:42:46 -0800241 return false;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700242}
243
244bool BlobManager::commit(uint16_t session, const std::vector<uint8_t>& data)
245{
Kun Yic892f4a2019-11-19 13:42:46 -0800246 if (auto handler = getActionHandle(session))
Patrick Ventureef3aead2018-09-12 08:53:29 -0700247 {
Kun Yic892f4a2019-11-19 13:42:46 -0800248 return handler->commit(session, data);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700249 }
Kun Yic892f4a2019-11-19 13:42:46 -0800250 return false;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700251}
252
253bool BlobManager::close(uint16_t session)
254{
Kun Yic892f4a2019-11-19 13:42:46 -0800255 if (auto handler = getActionHandle(session))
Patrick Ventureef3aead2018-09-12 08:53:29 -0700256 {
Kun Yic892f4a2019-11-19 13:42:46 -0800257 if (!handler->close(session))
258 {
259 return false;
260 }
Kun Yib61a88b2019-11-12 22:50:34 -0800261 eraseSession(handler, session);
Kun Yic892f4a2019-11-19 13:42:46 -0800262 return true;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700263 }
Kun Yic892f4a2019-11-19 13:42:46 -0800264 return false;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700265}
266
267std::vector<uint8_t> BlobManager::read(uint16_t session, uint32_t offset,
268 uint32_t requestedSize)
269{
Patrick Venture86c87f52019-02-01 14:44:15 -0800270 /* TODO: Currently, configure_ac isn't finding libuserlayer, w.r.t the
271 * symbols I need.
272 */
273
274 /** The channel to use for now.
275 * TODO: We will receive this information through the IPMI message call.
276 */
277 // const int ipmiChannel = ipmi::currentChNum;
278 /** This information is transport specific.
279 * TODO: We need a way to know this dynamically.
280 * on BT, 4 bytes of header, and 1 reply code.
281 */
282 // uint32_t maxTransportSize = ipmi::getChannelMaxTransferSize(ipmiChannel);
283
Kun Yic892f4a2019-11-19 13:42:46 -0800284 if (auto handler = getActionHandle(session, OpenFlags::read))
285 {
286 return handler->read(session, offset,
287 std::min(maximumReadSize, requestedSize));
288 }
289 return {};
Patrick Ventureef3aead2018-09-12 08:53:29 -0700290}
291
292bool BlobManager::write(uint16_t session, uint32_t offset,
293 const std::vector<uint8_t>& data)
294{
Kun Yic892f4a2019-11-19 13:42:46 -0800295 if (auto handler = getActionHandle(session, OpenFlags::write))
Patrick Ventureef3aead2018-09-12 08:53:29 -0700296 {
Kun Yic892f4a2019-11-19 13:42:46 -0800297 return handler->write(session, offset, data);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700298 }
Kun Yic892f4a2019-11-19 13:42:46 -0800299 return {};
Patrick Ventureef3aead2018-09-12 08:53:29 -0700300}
301
302bool BlobManager::deleteBlob(const std::string& path)
303{
304 GenericBlobInterface* handler = getHandler(path);
305
306 /* No handler found. */
307 if (!handler)
308 {
309 return false;
310 }
311
312 /* Check if the file has any open handles. */
313 if (getOpen(path) > 0)
314 {
315 return false;
316 }
317
318 /* Try deleting it. */
319 return handler->deleteBlob(path);
320}
321
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700322bool BlobManager::writeMeta(uint16_t session, uint32_t offset,
323 const std::vector<uint8_t>& data)
324{
Kun Yic892f4a2019-11-19 13:42:46 -0800325 if (auto handler = getActionHandle(session))
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700326 {
Kun Yic892f4a2019-11-19 13:42:46 -0800327 return handler->writeMeta(session, offset, data);
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700328 }
Kun Yic892f4a2019-11-19 13:42:46 -0800329 return false;
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700330}
331
Patrick Ventureef3aead2018-09-12 08:53:29 -0700332bool BlobManager::getSession(uint16_t* sess)
333{
334 uint16_t tries = 0;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700335
336 if (!sess)
337 {
338 return false;
339 }
340
341 /* This is not meant to fail as you have 64KiB values available. */
342
343 /* TODO(venture): We could just count the keys in the session map to know
344 * if it's full.
345 */
346 do
347 {
Patrick Venturec9ad5ff2018-10-12 17:05:49 -0700348 uint16_t lsess = next++;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700349 if (!sessions.count(lsess))
350 {
351 /* value not in use, return it. */
352 (*sess) = lsess;
353 return true;
354 }
355 } while (++tries < 0xffff);
356
357 return false;
358}
Patrick Ventureb3e07e22018-09-27 15:11:57 -0700359
360static std::unique_ptr<BlobManager> manager;
361
Patrick Venture73eb6872018-10-01 18:37:34 -0700362ManagerInterface* getBlobManager()
Patrick Ventureb3e07e22018-09-27 15:11:57 -0700363{
364 if (manager == nullptr)
365 {
366 manager = std::make_unique<BlobManager>();
367 }
368
369 return manager.get();
370}
371
Patrick Ventureef3aead2018-09-12 08:53:29 -0700372} // namespace blobs