blob: 894e743219c623f525ee20a8099a71d3b3423197 [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
Patrick Ventureef3aead2018-09-12 08:53:29 -070028bool BlobManager::registerHandler(std::unique_ptr<GenericBlobInterface> handler)
29{
30 if (!handler)
31 {
32 return false;
33 }
34
35 handlers.push_back(std::move(handler));
36 return true;
37}
38
39uint32_t BlobManager::buildBlobList()
40{
41 /* Clear out the current list (IPMI handler is presently single-threaded).
42 */
43 ids.clear();
44
45 /* Grab the list of blobs and extend the local list */
Patrick Venturea6e21a02018-10-23 09:45:04 -070046 for (const auto& h : handlers)
Patrick Ventureef3aead2018-09-12 08:53:29 -070047 {
48 std::vector<std::string> blobs = h->getBlobIds();
49 ids.insert(ids.end(), blobs.begin(), blobs.end());
50 }
51
52 return ids.size();
53}
54
55std::string BlobManager::getBlobId(uint32_t index)
56{
57 /* Range check. */
58 if (index >= ids.size())
59 {
60 return "";
61 }
62
63 return ids[index];
64}
65
66bool BlobManager::open(uint16_t flags, const std::string& path,
67 uint16_t* session)
68{
69 GenericBlobInterface* handler = getHandler(path);
70
71 /* No handler found. */
72 if (!handler)
73 {
74 return false;
75 }
76
Patrick Venture2f581512019-01-10 09:30:36 -080077 /* No sessions available... */
Patrick Ventureef3aead2018-09-12 08:53:29 -070078 if (!getSession(session))
79 {
80 return false;
81 }
82
83 /* Verify flags - must be at least read or write */
84 if (!(flags & (OpenFlags::read | OpenFlags::write)))
85 {
86 /* Neither read not write set, which means calls to Read/Write will
87 * reject. */
88 return false;
89 }
90
Kun Yib61a88b2019-11-12 22:50:34 -080091 /* Try to clean up anything that's falling out of cleanup timeout for this
92 * handler */
93 cleanUpStaleSessions(handler);
94
Patrick Ventureef3aead2018-09-12 08:53:29 -070095 if (!handler->open(*session, flags, path))
96 {
97 return false;
98 }
99
100 /* Associate session with handler */
101 sessions[*session] = SessionInfo(path, handler, flags);
Kun Yib61a88b2019-11-12 22:50:34 -0800102 openSessions[handler].insert(*session);
Kun Yi9ce83482019-11-14 13:08:39 -0800103 openFiles[path]++;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700104 return true;
105}
106
Patrick Venture8bc11772019-06-04 07:20:24 -0700107bool BlobManager::stat(const std::string& path, BlobMeta* meta)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700108{
109 /* meta should never be NULL. */
110 GenericBlobInterface* handler = getHandler(path);
111
112 /* No handler found. */
113 if (!handler)
114 {
115 return false;
116 }
117
118 return handler->stat(path, meta);
119}
120
Patrick Venture8bc11772019-06-04 07:20:24 -0700121bool BlobManager::stat(uint16_t session, BlobMeta* meta)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700122{
Kun Yi9cd8f762019-11-22 20:11:42 -0800123 if (auto handler = getActionHandler(session))
Patrick Ventureef3aead2018-09-12 08:53:29 -0700124 {
Kun Yic892f4a2019-11-19 13:42:46 -0800125 return handler->stat(session, meta);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700126 }
Kun Yic892f4a2019-11-19 13:42:46 -0800127 return false;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700128}
129
130bool BlobManager::commit(uint16_t session, const std::vector<uint8_t>& data)
131{
Kun Yi9cd8f762019-11-22 20:11:42 -0800132 if (auto handler = getActionHandler(session))
Patrick Ventureef3aead2018-09-12 08:53:29 -0700133 {
Kun Yic892f4a2019-11-19 13:42:46 -0800134 return handler->commit(session, data);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700135 }
Kun Yic892f4a2019-11-19 13:42:46 -0800136 return false;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700137}
138
139bool BlobManager::close(uint16_t session)
140{
Kun Yi9cd8f762019-11-22 20:11:42 -0800141 if (auto handler = getActionHandler(session))
Patrick Ventureef3aead2018-09-12 08:53:29 -0700142 {
Kun Yic892f4a2019-11-19 13:42:46 -0800143 if (!handler->close(session))
144 {
145 return false;
146 }
Kun Yib61a88b2019-11-12 22:50:34 -0800147 eraseSession(handler, session);
Kun Yic892f4a2019-11-19 13:42:46 -0800148 return true;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700149 }
Kun Yic892f4a2019-11-19 13:42:46 -0800150 return false;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700151}
152
153std::vector<uint8_t> BlobManager::read(uint16_t session, uint32_t offset,
154 uint32_t requestedSize)
155{
Patrick Venture86c87f52019-02-01 14:44:15 -0800156 /* TODO: Currently, configure_ac isn't finding libuserlayer, w.r.t the
157 * symbols I need.
158 */
159
160 /** The channel to use for now.
161 * TODO: We will receive this information through the IPMI message call.
162 */
163 // const int ipmiChannel = ipmi::currentChNum;
164 /** This information is transport specific.
165 * TODO: We need a way to know this dynamically.
166 * on BT, 4 bytes of header, and 1 reply code.
167 */
168 // uint32_t maxTransportSize = ipmi::getChannelMaxTransferSize(ipmiChannel);
169
Kun Yi9cd8f762019-11-22 20:11:42 -0800170 if (auto handler = getActionHandler(session, OpenFlags::read))
Kun Yic892f4a2019-11-19 13:42:46 -0800171 {
172 return handler->read(session, offset,
173 std::min(maximumReadSize, requestedSize));
174 }
175 return {};
Patrick Ventureef3aead2018-09-12 08:53:29 -0700176}
177
178bool BlobManager::write(uint16_t session, uint32_t offset,
179 const std::vector<uint8_t>& data)
180{
Kun Yi9cd8f762019-11-22 20:11:42 -0800181 if (auto handler = getActionHandler(session, OpenFlags::write))
Patrick Ventureef3aead2018-09-12 08:53:29 -0700182 {
Kun Yic892f4a2019-11-19 13:42:46 -0800183 return handler->write(session, offset, data);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700184 }
Kun Yifea1d812019-11-14 11:38:44 -0800185 return false;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700186}
187
188bool BlobManager::deleteBlob(const std::string& path)
189{
190 GenericBlobInterface* handler = getHandler(path);
191
192 /* No handler found. */
193 if (!handler)
194 {
195 return false;
196 }
197
198 /* Check if the file has any open handles. */
Kun Yi9ce83482019-11-14 13:08:39 -0800199 if (openFiles[path] > 0)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700200 {
201 return false;
202 }
203
204 /* Try deleting it. */
205 return handler->deleteBlob(path);
206}
207
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700208bool BlobManager::writeMeta(uint16_t session, uint32_t offset,
209 const std::vector<uint8_t>& data)
210{
Kun Yi9cd8f762019-11-22 20:11:42 -0800211 if (auto handler = getActionHandler(session))
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700212 {
Kun Yic892f4a2019-11-19 13:42:46 -0800213 return handler->writeMeta(session, offset, data);
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700214 }
Kun Yic892f4a2019-11-19 13:42:46 -0800215 return false;
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700216}
217
Patrick Ventureef3aead2018-09-12 08:53:29 -0700218bool BlobManager::getSession(uint16_t* sess)
219{
220 uint16_t tries = 0;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700221
222 if (!sess)
223 {
224 return false;
225 }
226
227 /* This is not meant to fail as you have 64KiB values available. */
228
229 /* TODO(venture): We could just count the keys in the session map to know
230 * if it's full.
231 */
232 do
233 {
Patrick Venturec9ad5ff2018-10-12 17:05:49 -0700234 uint16_t lsess = next++;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700235 if (!sessions.count(lsess))
236 {
237 /* value not in use, return it. */
238 (*sess) = lsess;
239 return true;
240 }
241 } while (++tries < 0xffff);
242
243 return false;
244}
Patrick Ventureb3e07e22018-09-27 15:11:57 -0700245
Kun Yi9cd8f762019-11-22 20:11:42 -0800246GenericBlobInterface* BlobManager::getHandler(const std::string& path)
247{
248 /* Find a handler. */
249 auto h = std::find_if(
250 handlers.begin(), handlers.end(),
251 [&path](const auto& iter) { return (iter->canHandleBlob(path)); });
252 if (h != handlers.end())
253 {
254 return h->get();
255 }
256
257 return nullptr;
258}
259
260GenericBlobInterface* BlobManager::getActionHandler(uint16_t session,
261 uint16_t requiredFlags)
262{
263 if (auto item = sessions.find(session);
264 item != sessions.end() && (item->second.flags & requiredFlags))
265 {
266 item->second.lastActionTime = std::chrono::steady_clock::now();
267 return item->second.handler;
268 }
269 return nullptr;
270}
271
272void BlobManager::eraseSession(GenericBlobInterface* const handler,
273 uint16_t session)
274{
275 if (auto item = sessions.find(session); item != sessions.end())
276 {
277 const auto& blobId = item->second.blobId;
278
279 /* Ok for openSessions[handler] to be an empty set */
280 openSessions[handler].erase(session);
281 openFiles[blobId]--;
282 if (openFiles[blobId] == 0)
283 {
284 openFiles.erase(blobId);
285 }
286
287 /* Erase at the end after using the session info */
288 sessions.erase(session);
289 }
290}
291
292void BlobManager::cleanUpStaleSessions(GenericBlobInterface* const handler)
293{
294 if (openSessions.count(handler) == 0)
295 {
296 return;
297 }
298
299 auto timeNow = std::chrono::steady_clock::now();
300 std::set<uint16_t> expiredSet;
301
302 for (auto sessionId : openSessions[handler])
303 {
304 if (timeNow - sessions[sessionId].lastActionTime >= sessionTimeout)
305 {
306 expiredSet.insert(sessionId);
307 }
308 }
309
310 for (auto sessionId : expiredSet)
311 {
312 std::cerr << "phosphor-ipmi-blobs: expiring stale session " << sessionId
313 << std::endl;
314
315 /* We do a best case recovery by issuing an expire call. If it fails
316 * don't erase sessions since the handler side might be still tracking
317 * it as open. */
318 if (handler->expire(sessionId))
319 {
320 eraseSession(handler, sessionId);
321 }
322 else
323 {
324 std::cerr << "phosphor-ipmi-blobs: failed to expire session "
325 << sessionId << std::endl;
326 }
327 }
328}
329
Patrick Ventureb3e07e22018-09-27 15:11:57 -0700330static std::unique_ptr<BlobManager> manager;
331
Patrick Venture73eb6872018-10-01 18:37:34 -0700332ManagerInterface* getBlobManager()
Patrick Ventureb3e07e22018-09-27 15:11:57 -0700333{
334 if (manager == nullptr)
335 {
336 manager = std::make_unique<BlobManager>();
337 }
338
339 return manager.get();
340}
341
Patrick Ventureef3aead2018-09-12 08:53:29 -0700342} // namespace blobs