Skip to content

Commit bb1328b

Browse files
soleenrppt
authored andcommitted
liveupdate: block session mutations during reboot
During the reboot() syscall, user processes may still be running concurrently and attempting to mutate sessions (e.g., creating, retrieving, or releasing sessions). To prevent this, introduce luo_session_serialize_rwsem to synchronize mutations with the serialization process. All session mutation operations (create, retrieve, release, ioctl) take the read lock. The serialization process (luo_session_serialize) takes the write lock and holds it indefinitely on success. This effectively freezes the LUO session subsystem during the transition to the new kernel. If serialization fails, the lock is released to allow recovery. Fixes: 0153094 ("liveupdate: luo_session: add sessions support") Reported-by: Oskar Gerlicz Kowalczuk <oskar@gerlicz.space> Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com> Reviewed-by: Pratyush Yadav (Google) <pratyush@kernel.org> Link: https://patch.msgid.link/20260527202737.1345192-4-pasha.tatashin@soleen.com Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
1 parent d3ae9e7 commit bb1328b

1 file changed

Lines changed: 48 additions & 3 deletions

File tree

kernel/liveupdate/luo_session.c

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,38 @@
4646
* 4. Retrieval: A userspace agent in the new kernel can then call
4747
* `luo_session_retrieve()` with a session name to get a new file
4848
* descriptor and access the preserved state.
49+
*
50+
* Locking:
51+
*
52+
* The LUO session subsystem uses a three-tier locking hierarchy to ensure thread
53+
* safety and prevent deadlocks during concurrent session mutations and kexec
54+
* serialization:
55+
*
56+
* 1. `luo_session_serialize_rwsem` (global rwsem):
57+
* Protects session mutations (creation, retrieval, release, and ioctls)
58+
* against the serialization process during reboot.
59+
*
60+
* - Readers: Taken by any path modifying or accessing session state (e.g.,
61+
* `luo_session_create()`, `luo_session_retrieve()`, `luo_session_release()`,
62+
* and `luo_session_ioctl()`).
63+
* - Writer: Taken by the serialization process (`luo_session_serialize()`)
64+
* during reboot. On success, the write lock is held indefinitely to freeze
65+
* the subsystem. On failure, it is released to allow recovery.
66+
*
67+
* 2. `luo_session_header->rwsem` (per-list rwsem):
68+
* Synchronizes list-level operations for the incoming and outgoing session headers.
69+
*
70+
* - Writer: Taken during list mutation operations (inserting or removing a
71+
* session from the list).
72+
* - Reader: Taken when traversing the list (e.g., retrieving a session by name).
73+
*
74+
* 3. `luo_session->mutex` (per-session mutex):
75+
* Protects the internal state and file sets of an individual session. It is
76+
* acquired during per-session operations such as preserving, retrieving,
77+
* or freezing files.
78+
*
79+
* Lock Hierarchy:
80+
* `luo_session_serialize_rwsem` -> `luo_session_header->rwsem` -> `luo_session->mutex`
4981
*/
5082

5183
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -75,6 +107,8 @@
75107
sizeof(struct luo_session_header_ser)) / \
76108
sizeof(struct luo_session_ser))
77109

110+
static DECLARE_RWSEM(luo_session_serialize_rwsem);
111+
78112
/**
79113
* struct luo_session_header - Header struct for managing LUO sessions.
80114
* @count: The number of sessions currently tracked in the @list.
@@ -205,6 +239,7 @@ static int luo_session_release(struct inode *inodep, struct file *filep)
205239
struct luo_session *session = filep->private_data;
206240
struct luo_session_header *sh;
207241

242+
guard(rwsem_read)(&luo_session_serialize_rwsem);
208243
/* If retrieved is set, it means this session is from incoming list */
209244
if (session->retrieved) {
210245
int err = luo_session_finish_one(session);
@@ -398,6 +433,7 @@ static long luo_session_ioctl(struct file *filep, unsigned int cmd,
398433
if (ret)
399434
return ret;
400435

436+
guard(rwsem_read)(&luo_session_serialize_rwsem);
401437
return op->execute(session, &ucmd);
402438
}
403439

@@ -437,21 +473,25 @@ int luo_session_create(const char *name, struct file **filep)
437473
if (IS_ERR(session))
438474
return PTR_ERR(session);
439475

476+
down_read(&luo_session_serialize_rwsem);
440477
err = luo_session_insert(&luo_session_global.outgoing, session);
441478
if (err)
442479
goto err_free;
443480

444-
scoped_guard(mutex, &session->mutex)
445-
err = luo_session_getfile(session, filep);
481+
mutex_lock(&session->mutex);
482+
err = luo_session_getfile(session, filep);
483+
mutex_unlock(&session->mutex);
446484
if (err)
447485
goto err_remove;
486+
up_read(&luo_session_serialize_rwsem);
448487

449488
return 0;
450489

451490
err_remove:
452491
luo_session_remove(&luo_session_global.outgoing, session);
453492
err_free:
454493
luo_session_free(session);
494+
up_read(&luo_session_serialize_rwsem);
455495

456496
return err;
457497
}
@@ -463,6 +503,7 @@ int luo_session_retrieve(const char *name, struct file **filep)
463503
struct luo_session *it;
464504
int err;
465505

506+
guard(rwsem_read)(&luo_session_serialize_rwsem);
466507
guard(rwsem_read)(&sh->rwsem);
467508
list_for_each_entry(it, &sh->list, list) {
468509
if (!strncmp(it->name, name, sizeof(it->name))) {
@@ -635,7 +676,8 @@ int luo_session_serialize(void)
635676
int i = 0;
636677
int err;
637678

638-
guard(rwsem_write)(&sh->rwsem);
679+
down_write(&luo_session_serialize_rwsem);
680+
down_write(&sh->rwsem);
639681
list_for_each_entry(session, &sh->list, list) {
640682
err = luo_session_freeze_one(session, &sh->ser[i]);
641683
if (err)
@@ -646,6 +688,7 @@ int luo_session_serialize(void)
646688
i++;
647689
}
648690
sh->header_ser->count = sh->count;
691+
up_write(&sh->rwsem);
649692

650693
return 0;
651694

@@ -655,6 +698,8 @@ int luo_session_serialize(void)
655698
luo_session_unfreeze_one(session, &sh->ser[i]);
656699
memset(sh->ser[i].name, 0, sizeof(sh->ser[i].name));
657700
}
701+
up_write(&sh->rwsem);
702+
up_write(&luo_session_serialize_rwsem);
658703

659704
return err;
660705
}

0 commit comments

Comments
 (0)