Bluetooth: Mesh: Use separate workq for storing mesh settings
Currently mesh settings are stored in the system workqueue context. Most of other stack functionality, such that advertisements (incl relay), loopback, transport sar, beacons transmission, etc. is also processed in the system workqueue context. When a massive amount of data needs to be stored and in particularly when page erase needs to be triggered by GC of NVS subsystem to allocate flash pages, the execution of the stack (and other functionality that uses the system workqueue) will be blocked until storing is finished. For example, right after the provisioning of a erased device, a node may not be responsive for up to 400ms before it can continue sending messages. The waiting time may increase if there is a GATT connection in the mean time. When write or erase operation is triggered, the flash driver waits for Bluetooth controller to allocate a time needed to perform the operation. During the whole operation, the context from which the operation was triggered is put to sleep. This allows other threads to run until Bluetooth controller finds the time for the flash driver. In other words, every settings_save_one or settings_delete should be considered as rescheduling points. Considering this, Bluetooth mesh can use another thread to store its settings, thus releasing the system workqueue for other tasks including the operation of the stack itself. The consistency of the data to be stored is guaranteed by the current implementation where the data is copied to another struct before calling settings_save_one. The pending flag of a particular module is dropped in settings.c before starting to store the corresponding data. Thus, if during the sleep the node receives a message that triggers a change in a module which data is currently being stored, the pending flag will be restored and the new change will be stored eventually. Having this option enabled including with the partial erase, will make the node more responsive in the described situations. Signed-off-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
This commit is contained in:
parent
a6af1dd43d
commit
e33a4ace0f
3 changed files with 102 additions and 2 deletions
|
@ -67,6 +67,46 @@ vulnerability and flash wear out.
|
|||
the RPL between reboots, will make the device vulnerable to replay attacks
|
||||
and not perform the replay protection required by the spec.
|
||||
|
||||
Persistent storage
|
||||
******************
|
||||
|
||||
The mesh stack uses the :ref:`Settings Subsystem <settings_api>` for storing the
|
||||
device configuration persistently. When the stack configuration changes and
|
||||
the change needs to be stored persistently, the stack schedules a work item.
|
||||
The delay between scheduling the work item and submitting it to the workqueue
|
||||
is defined by the :kconfig:option:`CONFIG_BT_MESH_STORE_TIMEOUT` option. Once
|
||||
storing of data is scheduled, it can not be rescheduled until the work item is
|
||||
processed. Exceptions are made in certain cases as described below.
|
||||
|
||||
When IV index, Sequence Number or CDB configuration have to be stored, the work
|
||||
item is submitted to the workqueue without the delay. If the work item was
|
||||
previously scheduled, it will be rescheduled without the delay.
|
||||
|
||||
The Replay Protection List uses the same work item to store RPL entries. If
|
||||
storing of RPL entries is requested and no other configuration is pending to be
|
||||
stored, the delay is set to :kconfig:option:`CONFIG_BT_MESH_RPL_STORE_TIMEOUT`.
|
||||
If other stack configuration has to be stored, the delay defined by
|
||||
the :kconfig:option:`CONFIG_BT_MESH_STORE_TIMEOUT` option is less than
|
||||
:kconfig:option:`CONFIG_BT_MESH_RPL_STORE_TIMEOUT`, and the work item was
|
||||
scheduled by the Replay Protection List, the work item will be rescheduled.
|
||||
|
||||
When the work item is running, the stack will store all pending configuration,
|
||||
including the RPL entries.
|
||||
|
||||
Work item execution context
|
||||
===========================
|
||||
|
||||
The :kconfig:option:`CONFIG_BT_MESH_SETTINGS_WORKQ` option configures the
|
||||
context from which the work item is executed. This option is enabled by
|
||||
default, and results in stack using a dedicated cooperative thread to
|
||||
process the work item. This allows the stack to process other incoming and
|
||||
outgoing messages, as well as other work items submitted to the system
|
||||
workqueue, while the stack configuration is being stored.
|
||||
|
||||
When this option is disabled, the work item is submitted to the system workqueue.
|
||||
This means that the system workqueue is blocked for the time it takes to store
|
||||
the stack's configuration. It is not recommended to disable this option as this
|
||||
will make the device non-responsive for a noticeable amount of time.
|
||||
|
||||
API reference
|
||||
**************
|
||||
|
|
|
@ -1584,6 +1584,34 @@ config BT_MESH_SEQ_STORE_RATE
|
|||
off with a value that's guaranteed to be larger than the last
|
||||
one used before power off.
|
||||
|
||||
config BT_MESH_SETTINGS_WORKQ
|
||||
bool "Store the Bluetooth mesh settings in a separate work queue"
|
||||
default y
|
||||
help
|
||||
This option enables a separate cooperative thread which is used to
|
||||
store Bluetooth mesh configuration. When this option is disabled,
|
||||
the stack's configuration is stored in the system workqueue. This
|
||||
means that the system workqueue will be blocked for the time needed
|
||||
to store the pending data. This time may significantly increase if
|
||||
the flash driver does the erase operation. Enabling this option
|
||||
allows Bluetooth mesh not to block the system workqueue, and thus
|
||||
process the incoming and outgoing messages while the flash driver
|
||||
waits for the controller to allocate the time needed to write the
|
||||
data and/or erase the required flash pages.
|
||||
|
||||
if BT_MESH_SETTINGS_WORKQ
|
||||
|
||||
config BT_MESH_SETTINGS_WORKQ_PRIO
|
||||
int
|
||||
default 1
|
||||
|
||||
config BT_MESH_SETTINGS_WORKQ_STACK_SIZE
|
||||
int "Stack size of the settings workq"
|
||||
default 880
|
||||
help
|
||||
Size of the settings workqueue stack.
|
||||
|
||||
endif # BT_MESH_SETTINGS_WORKQ
|
||||
endif # BT_SETTINGS
|
||||
|
||||
if BT_MESH_LOG_LEVEL_DBG
|
||||
|
|
|
@ -40,6 +40,21 @@ LOG_MODULE_REGISTER(bt_mesh_settings);
|
|||
#define RPL_STORE_TIMEOUT (-1)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_MESH_SETTINGS_WORKQ_PRIO
|
||||
#define SETTINGS_WORKQ_PRIO CONFIG_BT_MESH_SETTINGS_WORKQ_PRIO
|
||||
#else
|
||||
#define SETTINGS_WORKQ_PRIO 1
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_MESH_SETTINGS_WORKQ_STACK_SIZE
|
||||
#define SETTINGS_WORKQ_STACK_SIZE CONFIG_BT_MESH_SETTINGS_WORKQ_STACK_SIZE
|
||||
#else
|
||||
#define SETTINGS_WORKQ_STACK_SIZE 0
|
||||
#endif
|
||||
|
||||
static struct k_work_q settings_work_q;
|
||||
static K_THREAD_STACK_DEFINE(settings_work_stack, SETTINGS_WORKQ_STACK_SIZE);
|
||||
|
||||
static struct k_work_delayable pending_store;
|
||||
static ATOMIC_DEFINE(pending_flags, BT_MESH_SETTINGS_FLAG_COUNT);
|
||||
|
||||
|
@ -144,11 +159,21 @@ void bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag)
|
|||
* deadline.
|
||||
*/
|
||||
if (timeout_ms < remaining_ms) {
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_SETTINGS_WORKQ)) {
|
||||
k_work_reschedule_for_queue(&settings_work_q, &pending_store,
|
||||
K_MSEC(timeout_ms));
|
||||
} else {
|
||||
k_work_reschedule(&pending_store, K_MSEC(timeout_ms));
|
||||
}
|
||||
} else {
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_SETTINGS_WORKQ)) {
|
||||
k_work_schedule_for_queue(&settings_work_q, &pending_store,
|
||||
K_MSEC(timeout_ms));
|
||||
} else {
|
||||
k_work_schedule(&pending_store, K_MSEC(timeout_ms));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bt_mesh_settings_store_cancel(enum bt_mesh_settings_flag flag)
|
||||
{
|
||||
|
@ -240,6 +265,13 @@ static void store_pending(struct k_work *work)
|
|||
|
||||
void bt_mesh_settings_init(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_SETTINGS_WORKQ)) {
|
||||
k_work_queue_start(&settings_work_q, settings_work_stack,
|
||||
K_THREAD_STACK_SIZEOF(settings_work_stack),
|
||||
K_PRIO_COOP(SETTINGS_WORKQ_PRIO), NULL);
|
||||
k_thread_name_set(&settings_work_q.thread, "BT Mesh settings workq");
|
||||
}
|
||||
|
||||
k_work_init_delayable(&pending_store, store_pending);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue