Bluetooth: Mesh: Remove outdated RPL entries in settings work item
This allows to move flash operations from the context that triggered IVI update to the mesh settings work item that runs on the system workqueue. After this change, the outdated RPL entries will be removed in the setting work item triggered by store_pending function in mesh/settings.c. This is required to for a case where the mesh settings work item is running on a separate thread instead of the system workqueue to unblock the system workqueue eventually. Signed-off-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
This commit is contained in:
parent
c743edaaa6
commit
1fdf283531
1 changed files with 110 additions and 52 deletions
|
@ -37,7 +37,12 @@ struct rpl_val {
|
|||
|
||||
static struct bt_mesh_rpl replay_list[CONFIG_BT_MESH_CRPL];
|
||||
static ATOMIC_DEFINE(store, CONFIG_BT_MESH_CRPL);
|
||||
static atomic_t clear;
|
||||
|
||||
enum {
|
||||
PENDING_CLEAR,
|
||||
PENDING_RESET,
|
||||
};
|
||||
static atomic_t rpl_flags;
|
||||
|
||||
static inline int rpl_idx(const struct bt_mesh_rpl *rpl)
|
||||
{
|
||||
|
@ -53,6 +58,8 @@ static void clear_rpl(struct bt_mesh_rpl *rpl)
|
|||
return;
|
||||
}
|
||||
|
||||
atomic_clear_bit(store, rpl_idx(rpl));
|
||||
|
||||
snprintk(path, sizeof(path), "bt/mesh/RPL/%x", rpl->src);
|
||||
err = settings_delete(path);
|
||||
if (err) {
|
||||
|
@ -60,9 +67,6 @@ static void clear_rpl(struct bt_mesh_rpl *rpl)
|
|||
} else {
|
||||
LOG_DBG("Cleared RPL");
|
||||
}
|
||||
|
||||
(void)memset(rpl, 0, sizeof(*rpl));
|
||||
atomic_clear_bit(store, rpl_idx(rpl));
|
||||
}
|
||||
|
||||
static void schedule_rpl_store(struct bt_mesh_rpl *entry, bool force)
|
||||
|
@ -105,6 +109,7 @@ void bt_mesh_rpl_update(struct bt_mesh_rpl *rpl,
|
|||
bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx,
|
||||
struct bt_mesh_rpl **match)
|
||||
{
|
||||
struct bt_mesh_rpl *rpl;
|
||||
int i;
|
||||
|
||||
/* Don't bother checking messages from ourselves */
|
||||
|
@ -118,34 +123,33 @@ bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx,
|
|||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(replay_list); i++) {
|
||||
struct bt_mesh_rpl *rpl = &replay_list[i];
|
||||
rpl = &replay_list[i];
|
||||
|
||||
/* Empty slot */
|
||||
if (!rpl->src) {
|
||||
if (match) {
|
||||
*match = rpl;
|
||||
} else {
|
||||
bt_mesh_rpl_update(rpl, rx);
|
||||
}
|
||||
|
||||
return false;
|
||||
goto match;
|
||||
}
|
||||
|
||||
/* Existing slot for given address */
|
||||
if (rpl->src == rx->ctx.addr) {
|
||||
if (!rpl->old_iv &&
|
||||
atomic_test_bit(&rpl_flags, PENDING_RESET) &&
|
||||
!atomic_test_bit(store, i)) {
|
||||
/* Until rpl reset is finished, entry with old_iv == false and
|
||||
* without "store" bit set will be removed, therefore it can be
|
||||
* reused. If such entry is reused, "store" bit will be set and
|
||||
* the entry won't be removed.
|
||||
*/
|
||||
goto match;
|
||||
}
|
||||
|
||||
if (rx->old_iv && !rpl->old_iv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((!rx->old_iv && rpl->old_iv) ||
|
||||
rpl->seq < rx->seq) {
|
||||
if (match) {
|
||||
*match = rpl;
|
||||
} else {
|
||||
bt_mesh_rpl_update(rpl, rx);
|
||||
}
|
||||
|
||||
return false;
|
||||
goto match;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
@ -154,6 +158,15 @@ bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx,
|
|||
|
||||
LOG_ERR("RPL is full!");
|
||||
return true;
|
||||
|
||||
match:
|
||||
if (match) {
|
||||
*match = rpl;
|
||||
} else {
|
||||
bt_mesh_rpl_update(rpl, rx);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void bt_mesh_rpl_clear(void)
|
||||
|
@ -165,7 +178,7 @@ void bt_mesh_rpl_clear(void)
|
|||
return;
|
||||
}
|
||||
|
||||
(void)atomic_cas(&clear, 0, 1);
|
||||
atomic_set_bit(&rpl_flags, PENDING_CLEAR);
|
||||
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_RPL_PENDING);
|
||||
}
|
||||
|
@ -199,41 +212,56 @@ static struct bt_mesh_rpl *bt_mesh_rpl_alloc(uint16_t src)
|
|||
|
||||
void bt_mesh_rpl_reset(void)
|
||||
{
|
||||
int shift = 0;
|
||||
int last = 0;
|
||||
|
||||
/* Discard "old old" IV Index entries from RPL and flag
|
||||
* any other ones (which are valid) as old.
|
||||
*/
|
||||
for (int i = 0; i < ARRAY_SIZE(replay_list); i++) {
|
||||
struct bt_mesh_rpl *rpl = &replay_list[i];
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
int i;
|
||||
|
||||
if (rpl->src) {
|
||||
if (rpl->old_iv) {
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
clear_rpl(rpl);
|
||||
} else {
|
||||
(void)memset(rpl, 0, sizeof(*rpl));
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(replay_list); i++) {
|
||||
struct bt_mesh_rpl *rpl = &replay_list[i];
|
||||
|
||||
shift++;
|
||||
} else {
|
||||
rpl->old_iv = true;
|
||||
|
||||
if (shift > 0) {
|
||||
replay_list[i - shift] = *rpl;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
schedule_rpl_store(&replay_list[i - shift], true);
|
||||
}
|
||||
if (!rpl->src) {
|
||||
continue;
|
||||
}
|
||||
|
||||
last = i;
|
||||
/* Entries with "store" bit set will be stored, other entries will be
|
||||
* removed.
|
||||
*/
|
||||
atomic_set_bit_to(store, i, !rpl->old_iv);
|
||||
rpl->old_iv = !rpl->old_iv;
|
||||
}
|
||||
}
|
||||
|
||||
(void) memset(&replay_list[last - shift + 1], 0, sizeof(struct bt_mesh_rpl) * shift);
|
||||
if (i != 0) {
|
||||
atomic_set_bit(&rpl_flags, PENDING_RESET);
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_RPL_PENDING);
|
||||
}
|
||||
} else {
|
||||
int shift = 0;
|
||||
int last = 0;
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(replay_list); i++) {
|
||||
struct bt_mesh_rpl *rpl = &replay_list[i];
|
||||
|
||||
if (rpl->src) {
|
||||
if (rpl->old_iv) {
|
||||
(void)memset(rpl, 0, sizeof(*rpl));
|
||||
|
||||
shift++;
|
||||
} else {
|
||||
rpl->old_iv = true;
|
||||
|
||||
if (shift > 0) {
|
||||
replay_list[i - shift] = *rpl;
|
||||
}
|
||||
}
|
||||
|
||||
last = i;
|
||||
}
|
||||
}
|
||||
|
||||
(void)memset(&replay_list[last - shift + 1], 0, sizeof(struct bt_mesh_rpl) * shift);
|
||||
}
|
||||
}
|
||||
|
||||
static int rpl_set(const char *name, size_t len_rd,
|
||||
|
@ -315,7 +343,10 @@ static void store_rpl(struct bt_mesh_rpl *entry)
|
|||
|
||||
void bt_mesh_rpl_pending_store(uint16_t addr)
|
||||
{
|
||||
int shift = 0;
|
||||
int last = 0;
|
||||
bool clr;
|
||||
bool rst;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_BT_SETTINGS) ||
|
||||
(!BT_MESH_ADDR_IS_UNICAST(addr) &&
|
||||
|
@ -327,22 +358,49 @@ void bt_mesh_rpl_pending_store(uint16_t addr)
|
|||
bt_mesh_settings_store_cancel(BT_MESH_SETTINGS_RPL_PENDING);
|
||||
}
|
||||
|
||||
clr = atomic_cas(&clear, 1, 0);
|
||||
clr = atomic_test_and_clear_bit(&rpl_flags, PENDING_CLEAR);
|
||||
rst = atomic_test_bit(&rpl_flags, PENDING_RESET);
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(replay_list); i++) {
|
||||
if (addr != BT_MESH_ADDR_ALL_NODES &&
|
||||
addr != replay_list[i].src) {
|
||||
struct bt_mesh_rpl *rpl = &replay_list[i];
|
||||
|
||||
if (addr != BT_MESH_ADDR_ALL_NODES && addr != rpl->src) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clr) {
|
||||
clear_rpl(&replay_list[i]);
|
||||
} else if (atomic_test_and_clear_bit(store, rpl_idx(&replay_list[i]))) {
|
||||
store_rpl(&replay_list[i]);
|
||||
clear_rpl(rpl);
|
||||
shift++;
|
||||
} else if (atomic_test_and_clear_bit(store, i)) {
|
||||
if (shift > 0) {
|
||||
replay_list[i - shift] = *rpl;
|
||||
}
|
||||
|
||||
store_rpl(&replay_list[i - shift]);
|
||||
} else if (rst) {
|
||||
clear_rpl(rpl);
|
||||
|
||||
/* Check if this entry was re-used during removal. If so, shift it as well.
|
||||
* Otherwise, increment shift counter.
|
||||
*/
|
||||
if (atomic_test_and_clear_bit(store, i)) {
|
||||
replay_list[i - shift] = *rpl;
|
||||
atomic_set_bit(store, i - shift);
|
||||
} else {
|
||||
shift++;
|
||||
}
|
||||
}
|
||||
|
||||
last = i;
|
||||
|
||||
if (addr != BT_MESH_ADDR_ALL_NODES) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
atomic_test_and_clear_bit(&rpl_flags, PENDING_RESET);
|
||||
|
||||
if (addr == BT_MESH_ADDR_ALL_NODES) {
|
||||
(void)memset(&replay_list[last - shift + 1], 0, sizeof(struct bt_mesh_rpl) * shift);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue