-
Notifications
You must be signed in to change notification settings - Fork 647
wip! many: inject XKB configs in kcmdline #16338
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
wip! many: inject XKB configs in kcmdline #16338
Conversation
Signed-off-by: Zeyad Gouda <zeyad.gouda@canonical.com>
7fc6274 to
77fbd44
Compare
|
Wed Dec 3 20:29:54 UTC 2025 No spread failures reported |
|
|
||
| config := &XKBConfig{ | ||
| Layouts: strings.Split(vals["X11Layout"], ","), | ||
| Models: strings.Split(vals["X11Model"], ","), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The xkb configuration file only supports specifying one model. It might be a good idea to change the datatype from []string to just string
| ) | ||
|
|
||
| type XKBConfig struct { | ||
| Models []string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The configuration file can only specify one model so we may want to rename this to Model and change the datatype to just string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would likely mean that the Model field needs to be parsed separately from the map used by the other fields.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I do not think we can have multiple models.
| } | ||
|
|
||
| func CurrentXKBConfig() (*XKBConfig, error) { | ||
| conn, err := dbusutil.SystemBus() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this function verify the configuration as well? AFAIK, the default model and layout if not specified are pc105 and us, but if Variants is not empty we expect the same number of elements in Layouts. I would say that verification is unnecessary however, if there are existing assertions that prevent an invalid state.
| config := &XKBConfig{ | ||
| Layouts: strings.Split(vals["X11Layout"], ","), | ||
| Models: strings.Split(vals["X11Model"], ","), | ||
| Variants: strings.Split(vals["X11Variant"], ","), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should check that Variants and Layouts have the same lentgth and warn if not.
| return nil, err | ||
| } | ||
|
|
||
| xkbConfigFile := filepath.Join(dirs.GlobalRootDir, "/etc/default/keyboard") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does inotify_add_watch follow symbolic link? If not we should also watch /etc/vconsole.conf. I expect at some point /etc/default/keyboard becomes the symlink as a backward compliant file.
|
|
||
| simplified := fmt.Sprintf("%s,%s,%s,%s", layout, model, variant, opts) | ||
|
|
||
| updated, err := setExtraSnapdKernelCommandLineArg(m.state, extraSnapdKernelCmdlineArgXKB, simplified) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we not cache here the value? I suppose we can get lots of notifications, and not all will modify the keyboard configuration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the config didn't change, setExtraSnapdKernelCommandLineArg is a no-op.
|
@ZeyadYasser there's a conflict here now |
pedronis
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some questions
| taskParam string) (string, error) { | ||
|
|
||
| var value string | ||
| err := tsk.Get(taskParam, &value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this code used only in tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This helper was unchanged, only moved to a new file and renamed. I looked in the code base, This is used when setting cmdline-append config:
snapd/overlord/configstate/configcore/kernel.go
Lines 161 to 168 in 4fc4cfa
| t := st.NewTask("update-gadget-cmdline", | |
| "Update kernel command line from system configuration") | |
| // Pass options to the task (changes in the options are not | |
| // committed yet so the task cannot simply get them from the | |
| // configuration) | |
| for _, arg := range args { | |
| t.Set(arg.name, arg.cmdline) | |
| } |
| t := st.NewTask("update-managed-boot-config", summary) | ||
| t.Set("no-restart", true) | ||
|
|
||
| chg := st.NewChange("set-extra-snapd-kcmdline-arg", summary) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what happens if this kind of changes happens between a applyCmdlineChangeKind (see configcore/kernel.go) and the point that code really commits the change to the config, will we use the additions? do we have conflict logic atm moment that prevent that one and the current handlers changes interfering? but that will not cover this case and we can't use conflicts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand the first question, given that the additions are added to the state (with the state lock held and later released) shouldn't the additions always be taken into consideration when any of the kernel cmdline update tasks run regardless of the parent change? and since we create a change anyway, it shouldn't matter if some ongoing change that updates the kcmdline missed it.
For the second part regarding conflicts, you are right we can't use conflicts, instead we should block them from running in parallel using AddBlocked because during reseals the state might actually be unlocked. The blocking mechanism here might actually even be more important than fde/kcmdline blocking we were discussing before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
consider that the configcore code is using a Change so I'm quite sure it needs to release the lock, so we are not keeping the lock that's why I'm worried about this clashing with such a change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought deeper about this, conflicts will minimize the window where this could happen but not completely fix it, which indicates that this is a bug in snapd not specific to xkb arg injection (e.g. imagine a gadget refresh change runs right after the core config change finished but before the config transaction was committed).
One thing we can do, is extend the conflict detection CheckUpdateKernelCommandLineConflict to fail if there is some hook running (which should cover the core configs) using HookManager.NumRunningHooks, I wonder if there is a way to only fail for core config "hijacked" hook to avoid conflict detection failing for irrelevant cases.
This should fix the conflict detection logic for snapd and gadget refresh changes.
For xkb configs, it can simply wait until the conflict detection doesn't return an error because the listener runs in it own go routine, or to make things simpler it can just fail and the new values will be picked up in the next ensure loop.
If I understand correctly, this is only a problem if some other kcmdline changing change is running after core config change is triggered were the config transaction wouldn't have been committed yet but running before is fine because of the conflict detection in place, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a better idea, we could do blocking/conflict detection on the core configure-hook run-hook task. We could add some helper to hookstate to check if a given task is a core configure hook, we can even add extra logic to detect if is a core configure hook affecting specific parameters since we only care about cmdline-append and dangerous-cmdline-append. To make it generic it could be parameterized by the hookName and snapName.
This works because it the config transaction should have been committed if the parent run-hook task finishes.
This sounds like an existing bug that was only highlighted by this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A much simpler approach to achieve the same outcome is to inject the parent run-hook task-id into applyCmdlineChangeKind change's state, and update the conflict detection to detect that and fail if the parent run-hook task is not ready.
This draft PR allows snapd to inject XKB configs as a kernel cmdline argument to be consumed by
plymouth-set-keymap.servicefrom #16269 early in boot to set the correct keyboard layout configuration for plymouth.This is only a draft to discuss and converge on the approach, afterwards it will be closed and split into several tested PRs.
I went with a generic approach for "extra snapd kcmdline args" that we might utilize in the future when we need to inject similar configurations for early boot in FDE systems.