diff --git a/doc/connectivity/bluetooth/api/mesh/core.rst b/doc/connectivity/bluetooth/api/mesh/core.rst index c06ce3771e2..e27f29a3135 100644 --- a/doc/connectivity/bluetooth/api/mesh/core.rst +++ b/doc/connectivity/bluetooth/api/mesh/core.rst @@ -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 ` 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 ************** diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index cdfe3590130..94888dbb31a 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -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 diff --git a/subsys/bluetooth/mesh/settings.c b/subsys/bluetooth/mesh/settings.c index 56149cf7025..2c3ef3bc902 100644 --- a/subsys/bluetooth/mesh/settings.c +++ b/subsys/bluetooth/mesh/settings.c @@ -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,9 +159,19 @@ void bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag) * deadline. */ if (timeout_ms < remaining_ms) { - k_work_reschedule(&pending_store, K_MSEC(timeout_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 { - k_work_schedule(&pending_store, K_MSEC(timeout_ms)); + 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)); + } } } @@ -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); }