|
1 | 1 | /* |
2 | | - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD |
| 2 | + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD |
3 | 3 | * |
4 | 4 | * SPDX-License-Identifier: Apache-2.0 |
5 | 5 | */ |
@@ -56,77 +56,79 @@ esp_err_t PageManager::load(Partition *partition, uint32_t baseSector, uint32_t |
56 | 56 |
|
57 | 57 | // if power went out after a new item for the given key was written, |
58 | 58 | // but before the old one was erased, we end up with a duplicate item |
59 | | - Page& lastPage = back(); |
60 | | - size_t lastItemIndex = SIZE_MAX; |
61 | | - Item item; |
62 | | - size_t itemIndex = 0; |
63 | | - while (lastPage.findItem(Page::NS_ANY, ItemType::ANY, nullptr, itemIndex, item) == ESP_OK) { |
64 | | - itemIndex += item.span; |
65 | | - lastItemIndex = itemIndex; |
66 | | - } |
67 | | - |
68 | | - if (lastItemIndex != SIZE_MAX) { |
69 | | - auto last = PageManager::TPageListIterator(&lastPage); |
70 | | - TPageListIterator it; |
| 59 | + if (!partition->get_readonly()) { |
| 60 | + Page& lastPage = back(); |
| 61 | + size_t lastItemIndex = SIZE_MAX; |
| 62 | + Item item; |
| 63 | + size_t itemIndex = 0; |
| 64 | + while (lastPage.findItem(Page::NS_ANY, ItemType::ANY, nullptr, itemIndex, item) == ESP_OK) { |
| 65 | + itemIndex += item.span; |
| 66 | + lastItemIndex = itemIndex; |
| 67 | + } |
71 | 68 |
|
72 | | - for (it = begin(); it != last; ++it) { |
| 69 | + if (lastItemIndex != SIZE_MAX) { |
| 70 | + auto last = PageManager::TPageListIterator(&lastPage); |
| 71 | + TPageListIterator it; |
73 | 72 |
|
74 | | - if ((it->state() != Page::PageState::FREEING) && |
75 | | - (it->eraseItem(item.nsIndex, item.datatype, item.key, item.chunkIndex) == ESP_OK)) { |
76 | | - break; |
77 | | - } |
78 | | - } |
79 | | - if ((it == last) && (item.datatype == ItemType::BLOB_IDX)) { |
80 | | - /* Rare case in which the blob was stored using old format, but power went just after writing |
81 | | - * blob index during modification. Loop again and delete the old version blob*/ |
82 | 73 | for (it = begin(); it != last; ++it) { |
83 | 74 |
|
84 | 75 | if ((it->state() != Page::PageState::FREEING) && |
85 | | - (it->eraseItem(item.nsIndex, ItemType::BLOB, item.key, item.chunkIndex) == ESP_OK)) { |
| 76 | + (it->eraseItem(item.nsIndex, item.datatype, item.key, item.chunkIndex) == ESP_OK)) { |
86 | 77 | break; |
87 | 78 | } |
88 | 79 | } |
| 80 | + if ((it == last) && (item.datatype == ItemType::BLOB_IDX)) { |
| 81 | + /* Rare case in which the blob was stored using old format, but power went just after writing |
| 82 | + * blob index during modification. Loop again and delete the old version blob*/ |
| 83 | + for (it = begin(); it != last; ++it) { |
| 84 | + |
| 85 | + if ((it->state() != Page::PageState::FREEING) && |
| 86 | + (it->eraseItem(item.nsIndex, ItemType::BLOB, item.key, item.chunkIndex) == ESP_OK)) { |
| 87 | + break; |
| 88 | + } |
| 89 | + } |
| 90 | + } |
89 | 91 | } |
90 | | - } |
91 | 92 |
|
92 | | - // check if power went out while page was being freed |
93 | | - for (auto it = begin(); it!= end(); ++it) { |
94 | | - if (it->state() == Page::PageState::FREEING) { |
95 | | - Page* newPage = &mPageList.back(); |
96 | | - if (newPage->state() == Page::PageState::ACTIVE) { |
97 | | - auto err = newPage->erase(); |
| 93 | + // check if power went out while page was being freed |
| 94 | + for (auto it = begin(); it!= end(); ++it) { |
| 95 | + if (it->state() == Page::PageState::FREEING) { |
| 96 | + Page* newPage = &mPageList.back(); |
| 97 | + if (newPage->state() == Page::PageState::ACTIVE) { |
| 98 | + auto err = newPage->erase(); |
| 99 | + if (err != ESP_OK) { |
| 100 | + return err; |
| 101 | + } |
| 102 | + mPageList.erase(newPage); |
| 103 | + mFreePageList.push_back(newPage); |
| 104 | + } |
| 105 | + auto err = activatePage(); |
98 | 106 | if (err != ESP_OK) { |
99 | 107 | return err; |
100 | 108 | } |
101 | | - mPageList.erase(newPage); |
102 | | - mFreePageList.push_back(newPage); |
103 | | - } |
104 | | - auto err = activatePage(); |
105 | | - if (err != ESP_OK) { |
106 | | - return err; |
107 | | - } |
108 | | - newPage = &mPageList.back(); |
| 109 | + newPage = &mPageList.back(); |
109 | 110 |
|
110 | | - err = it->copyItems(*newPage); |
111 | | - if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) { |
112 | | - return err; |
113 | | - } |
| 111 | + err = it->copyItems(*newPage); |
| 112 | + if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) { |
| 113 | + return err; |
| 114 | + } |
114 | 115 |
|
115 | | - err = it->erase(); |
116 | | - if (err != ESP_OK) { |
117 | | - return err; |
118 | | - } |
| 116 | + err = it->erase(); |
| 117 | + if (err != ESP_OK) { |
| 118 | + return err; |
| 119 | + } |
119 | 120 |
|
120 | | - Page* p = static_cast<Page*>(it); |
121 | | - mPageList.erase(it); |
122 | | - mFreePageList.push_back(p); |
123 | | - break; |
| 121 | + Page* p = static_cast<Page*>(it); |
| 122 | + mPageList.erase(it); |
| 123 | + mFreePageList.push_back(p); |
| 124 | + break; |
| 125 | + } |
124 | 126 | } |
125 | | - } |
126 | 127 |
|
127 | | - // partition should have at least one free page |
128 | | - if (mFreePageList.empty()) { |
129 | | - return ESP_ERR_NVS_NO_FREE_PAGES; |
| 128 | + // partition should have at least one free page if it is not read-only |
| 129 | + if (mFreePageList.empty()) { |
| 130 | + return ESP_ERR_NVS_NO_FREE_PAGES; |
| 131 | + } |
130 | 132 | } |
131 | 133 |
|
132 | 134 | return ESP_OK; |
|
0 commit comments