Review: Ties That Bond in Gretna Green, by Linzi Day
Series:
Midlife Recorder #3
Publisher:
Linzi Day
Copyright:
February 2023
ISBN:
9798376517017
Format:
Kindle
Pages:
616
Ties That Bond in Gretna Green is a self-published fantasy novel
and the third book in the Midlife Recorder series. As with the previous
book, it picks up almost immediately after Painting the Blues in Gretna Green. Day calls the genre
paranormal women's fantasy, and that sounds about right to me.
There is an intervening short story that you can get by
joining Day's mailing list (along
with an epilogue to the first book and to this book). I don't think it's
that important, but there are frequent references to it at the start of
this novel that become somewhat annoying if you haven't read it.
Valentine's Day is fast approaching. This the busiest day of the year for
the part of the Recorder's job that Niki already knew how to do: marrying
people. She performed marriage ceremonies in her previous job before her
inheritance, and she loved that work despite her awful boss. Performing
marriages in the Gateway sounds even more rewarding, but the sheer number
of couples and the political complications from the first two books create
logistical problems she has to solve first.
Also, the remaining member of her staff held over from her grandmother's
time has returned from vacation to discover that Niki has upended most of
what she thought she knew about the job. Time for Niki to apply what she
learned from the change management training her old boss forced her to
attend and then ignored! (If you just groaned, rest assured that Day
somehow makes this work, although she clearly has a higher opinion of
corporate training than I do.)
This plot was more to my taste than Painting the Blues, mostly
because Niki seemed on top of the problems and didn't postpone looking at
them for half the book. There is more of the management competence porn
that readers have come to expect of the series, a few more revelations
about Niki's magic, more mysterious manifestations and the first mention
of a prophecy, and a few political developments. As always, the pacing is
exceptional. These books grab me and pull me along, page after page, often
robbing me of sleep because I find them nearly impossible to put down.
Ties that Bond (and to some extent the last book) looked like it
was going to introduce a romantic subplot, and I was preparing to be
annoyed by it because I did not like the man in the subplot at all. I
won't spoil how it works out in this book, but I will say that Niki
surprised me and showed more sense than I thought the author was
telegraphing. This is not the first time that Day has surprised me with
what I thought was foreshadowing that did not turn out how I expected,
usually for the better. If she can keep that up, it's a nice effect (if a
bit unbalancing) and adds to my desire to read just one more chapter.
The way the world-building of these books is structured continues to
intrigue me. Day gets away with some problems that I think would be more
noticeable in other books thanks to the excellent pacing (no time to ponder
the world-building, we're on to the next crisis!) and the tight
third-person perspective. Niki is not a detail person, to say the least,
but she does keep returning to bits of world-building and poking at them a
bit harder, which gives Day repeated opportunities to shore up ideas that
felt shaky and dubious at first glance. Still, this is not a book that
prizes deep logical consistency or full exploration of the ramifications
of a bit of magic. You have to be willing to go along with the ride and
not think too hard.
For example, Niki can see bonds between couples and judge their strength.
This is apparently a long-standing power of the Recorder's line (she was
able to do that before she became the Recorder), and part of her
responsibility in these weddings is to check the bonds of the couples.
This leads to some well-handled scenes where she diagnoses a problem or
resolves a conflict because she can magically see the true relationship
structure.
Everyone in the book just takes this power in stride. This is wild to me!
This ability would completely upend half of society if you fully worked
out its ramifications and could find people other than Niki with the same
ability. Even if one assumes that a bond only forms over time and can't be
sensed in the early stages of a relationship (something the book never
establishes), can you imagine the implications of having an infallible
oracle that says at a glance whether a marriage will work (permanently,
the book strongly implies)? The implications for how to structure
marriage, for family planning, for psychology and psychiatry, for how to
structure dating, even for living arrangements and housing markets? This
is not a small world-building detail, and yet it's treated more like part
of Niki's characterization than like a foundation of society.
I think some of this all-vibes world-building may come from the general
new-age feel to how magic works. Day makes a grab-bag of random magic
canonical in this world: psychic lie detecting abilities, auras, chakras,
premonitions, and other bits of the sort of spiritualism that tends to be
heavily marketed to middle-class women. I have that niggling feeling that
one sometimes gets in SF that a lot of this is in the world-building
because the author believes it's partly real (see, for instance, psychic
powers and the Dean drive in 1960s science fiction). If one believes that
psychic powers and various bits of mysticism are true in our world, one
has already developed the rationalization mechanisms to explain away their
almost total lack of influence or impact on how the world is structured.
If one then introduces them into a true fantasy world, one may not notice
how many implications that should have for how society is structured,
since one is used to believing magic exists but has no significant
implications.
I could be entirely wrong about this analysis, and maybe it's a bit unfair
to Day. I should also be clear that this is not a complaint, just a point
of fascination to me when I think back over one of these books after I
finished it. There is a glut of fantasy out there that's constructed like
an engineering problem or that goes deep into politics or social theory,
usually written by people with strong opinions but not a lot of training
in real sociology. One of the joys of self-published books is that you
occasionally get something that assembles genre conventions in a way that
feels odd and delightfully strange. What if, in addition to dimensional
gates and overwhelming protean power invested in a true heir, all the
magic sold by the local Tarot and crystal store was also true? Sure, why
not! If the pacing is good and the story is grabby, it works for me.
It does seem worth attaching a warning for the folks who need scientific
reproducibility and explored implications in their world-building, though.
If you're the sort of reader who is bothered by political boundaries and
economic systems that match our world despite the existence of magic, this
series may cause you problems.
This continues to be a grabby, highly entertaining story of a woman who
finally gets to run her own small business the way that she always thought
the business should be run after years of working for an awful manager,
except that her business is total magical power over an interchange point
between dimensions, she's the chosen one, and the setting is a high
fantasy world with prophecies and gods. If that sounds appealing, don't
start here, but I highly recommend giving Midlife in Gretna Green a try. The series seems to be holding up.
Followed by a short story epilogue available by joining Day's mailing
list, an optional novella (maybe novelette) published in Spilling
the Tea in Gretna Green, and then Seeing Red in Gretna Green.
Rating: 7 out of 10
Posted on July 27, 2026
Tags: madeof:atoms, craft:sewing, FreeSoftWear
The recurring joke is that because of some health issues, in summer I
dress like a Victorian Vampire.
But how would an actual Late Victorian Vampire dress? Picture her, she
would look like some kind of eccentric gentlewoman, as vampires usually
do, probably with a style that is a bit conservative, rather than
following the latest fashions.
Now, she wouldn t probably wear men s shirts. But what if she was a
lesbian1 vampire? Wouldn t she need a fancy, frilly shirt to
go with her tailored cycling suit when she s out seducing the more
active ladies in the neighbourhood?
Or maybe not. It s not making a lot of sense, is it? But I do have a
lot of shirt fabric in my stash2, and I could use a few more
shirts that were practical and comfortable, but also somewhat over the
top.
For the practical and comfortable I went to my trusted 1880s shirt,
while for the over the top part I looked at inspiration from the earlier
18th century frilly shirts, and their later imitations.
I decided to use some nice cotton batiste I had bought quite a few years
ago to make one of my first historically inspired shirtwaists: I may
have a tendency to buy a bit more fabric than actually needed by the
pattern, but that s what everybody does, right?
For the ruffles I decided to use a lighter weight cotton voile, also
from the stash.
At the front, I wanted the ruffle to be inserted in the yoke, but I was
also whipstitching the gathers to it to make them neater, so I started
bu attaching the yoke lining to the gathered front, then I whipstitched
the ruffle to the front, catching each gather, and finally I
whipstitched the other yoke on the ruffle and the rest of the gathered
front.
And then after sewing the collar, I realized that this way the slit
would have remained open in the front (or the collar too narrow), so I
had to unpick the front part of the yoke, and sew it again, this time
leaving an excess of fabric as wide as half the placket width from the
pattern, to be sewn directly in the collar band.
From then, things progressed smoothly, with some interruptions, until I
got to the first sleeve, which I failed to insert twice, as one does.
On the third attempt, with a different method, I succeeded, I tried the
shirt on, and it already felt extra.
But it could be even more extra. With some ruffles also at the collar.
The shirt had been made with a simple collar band, and I could have just
added the ruffle to it, but I also wanted to be able to wear it with
other detachable collars, so I decided to make another collar band with
ruffles, to wear on top.
And that was mostly it, except for the reinforcement patches at the
side seams and cuffs: I love having them, because they make the seam
end neater and stronger, but they are a bit of a hassle to make, so they
got postponed a few days.
But finally, the shirt was done.
And I tried it on, and it was good.
But now I really need a pair of cycling breeches, don t I?
Finally, some light at the end of the tunnel!
As I have said in this
blog
and elsewhere, after putting quite a bit of work into generating the Debian
Raspberry Pi images between late
2018
and 2023, I had to recognize I don t have the time and energy to properly
care for it.
I even registered a GSoC project for it. I mentored Kurva Prashanth, who
did good work on the vmdb2
scripts we use for the image generation but in the end, was unable to
push them to be built in Debian infrastructure. Maybe a different approach
was needed! While I adopted the images as they were conceived by Michael
Stapelberg,
sometimes it s easier to start from scratch and build a fresh approach.
So, I m not yet pointing at a stable, proven release, but to a good
promise. And I hope I m not being pushy by making this public: in the
#debian-raspberrypi channel, waldi has shared the images he has created
with the Debian Cloud Team s infrastructure.
So, right now, the images built so
far
support Raspberry Pi families 4 and 5 (notably, not the 500 computer I
have, due to a missing Device Tree, but I ll try to help figure that bit
out Anyway, p400/500/500+ systems are not that usual). Work is
underway to get the 3B+ to boot (some hackery is needed, as it only
understands MBR partition schemes, so creating a hybrid image seems to be
needed).
Sadly, I don t think the effort will be extended to cover older,
32-bit-only systems (RPi 0, 1 and 2).
Anyway, as this effort stabilizes, I will phase out my (stale!) work on
raspi.debian.net, and will redirect it to point at the new images.
Comments
Andrea Pappacoda tachi@d.o 2026-01-26 17:39:14 GMT+1
Are there any particular caveats compared to using the regular Raspberry Pi
OS?
Are they documented anywhere?
Gunnar Wolf gwolf.blog@gwolf.org 2026-01-26 11:02:29 GMT-6
Well, the Raspberry Pi OS includes quite a bit of software that s not
packaged in Debian for various reasons some of it because it s non-free
demo-ware, some of it because it s RPiOS-specific configuration, some of
it I don t care, I like running Debian wherever possible
Andrea Pappacoda tachi@d.o 2026-01-26 18:20:24 GMT+1
Thanks for the reply! Yeah, sorry, I should ve been more specific. I also
just care about the Debian part. But: are there any hardware issues or
unsupported stuff, like booting from an SSD (which I m currently doing)?
Gunnar Wolf gwolf.blog@gwolf.org 2026-01-26 12:16:29 GMT-6
That s beyond my knowledge Although I can tell you that:
Raspberry Pi OS has hardware support as soon as their new boards hit the
market. The ability to even boot a board can take over a year for the
mainline Linux kernel (at least, it has, both in the cases of the 4 and
the 5 families).
Also, sometimes some bits of hardware are not discovered by the Linux
kernels even if the general family boots because they are not declared in
the right place of the Device Tree (i.e. the wireless network interface
in the 02W is in a different address than in the 3B+, or the 500 does not
fully boot while the 5B now does). Usually it is a matter of just
declaring stuff in the right place, but it s not a skill many of us have.
Also, many RPi hats ship with their own Device Tree overlays, and they
cannot always be loaded on top of mainline kernels.
Andrea Pappacoda tachi@d.o 2026-01-26 19:31:55 GMT+1
That s beyond my knowledge Although I can tell you that:
Raspberry Pi OS has hardware support as soon as their new boards hit the
market. The ability to even boot a board can take over a year for the
mainline Linux kernel (at least, it has, both in the cases of the 4 and
the 5 families).
Yeah, unfortunately I m aware of that I ve also been trying to boot
OpenBSD on my rpi5 out of curiosity, but been blocked by my somewhat
unusual setup involving an NVMe SSD as the boot drive :/
Also, sometimes some bits of hardware are not discovered by the Linux
kernels even if the general family boots because they are not declared in
the right place of the Device Tree (i.e. the wireless network interface
in the 02W is in a different address than in the 3B+, or the 500 does not
fully boot while the 5B now does). Usually it is a matter of just
declaring stuff in the right place, but it s not a skill many of us have.
At some point in my life I had started reading a bit about device trees and
stuff, but got distracted by other stuff before I could develop any
familiarity with it. So I don t have the skills either :)
Also, many RPi hats ship with their own Device Tree overlays, and they
cannot always be loaded on top of mainline kernels.
I m definitely not happy to hear this!
Guess I ll have to try, and maybe report back once some page for these new
builds materializes.
It's Sunday and I'm now sitting in the train from Brest to Paris where I will be changing to Germany, on the way back from the annual Debian conference. A full week of presentations, discussions, talks and socializing is laying behind me and my head is still spinning from the intensity.
Pollito and the gang of DebConf mascots wearing their conference badges (photo: Christoph Berg)
Table of Contents
Sunday, July 13th
It started last Sunday with traveling to the conference. I got on the Eurostar in Duisburg and we left on time, but even before reaching Cologne, the train was already one hour delayed for external reasons, collecting yet another hour between Aachen and Liege for its own technical problems. "The train driver is working on trying to fix the problem." My original schedule had well over two hours for changing train stations in Paris, but being that late, I missed the connection to Brest in Montparnasse. At least in the end, the total delay was only one hour when finally arriving at the destination. Due to the French julliet quatorze fireworks approaching, buses in Brest were rerouted, but I managed to catch the right bus to the conference venue, already meeting a few Debian people on the way.
The conference was hosted at the IMT Atlantique Brest campus, giving the event a nice university touch. I arrived shortly after 10 in the evening and after settling down a bit, got on one of the "magic" buses for transportation to the camping site where half of the attendees where stationed. I shared a mobile home with three other Debianites, where I got a small room for myself.
Monday, July 14th
Next morning, we took the bus back to the venue with a small breakfast and the opening session where Enrico Zini invited me to come to his and Nicolas Dandrimont's session about Debian community governance and curation, which I gladly did. Many ideas about conflict moderation and community steering were floated around. I hope some of that can be put into effect to make flamewars on the mailing lists less heated and more directed. After that, I attended Olly Betts' "Stemming with Snowball" session, which is the stemmer used also in PostgreSQL. Text search is one of the areas in PostgreSQL that I never really looked closely at, including the integration into the postgresql-common package, so it was nice to get more information about that.
In preparation for the conference, a few of us Ham radio operators in Debian had decided to bring some radio gear to DebConf this year in order to perhaps spark more interest for our hobby among the fellow geeks. In the afternoon after the talks, I found a quieter spot just outside of the main hall and set up a shortwave antenna by attaching a 10m mast to one of the park benches there. The 40m band was still pretty much closed, but I could work a few stations from England, just across the channel from Bretagne, answering questions from interested passing-by Debian people between the contacts. Over time, the band opened and more European stations got into the log.
F/DF7CB in Brest (photo: Evangelos Ribeiro Tzaras)
Tuesday, July 15th
Tuesday started with Helmut Grohne's session about "Reviving (un)schroot". The schroot program has been Debian's standard way of managing build chroots for a long time, but it is more and more being regarded as obsolete with all kinds of newer containerization and virtualization technologies taking over. Since many bits of Debian infrastructure depend on schroot, and its user interface is still very useful, Helmut reimplemented it using Linux namespaces and the "unshare" systemcall. I had already worked with him at the Hamburg Minidebconf to replace the apt.postgresql.org buildd machinery with the new system, but we were not quite there yet (network isolation is nice, but we still sometimes need proper networking), so it was nice to see the effort is still progressing and I will give his new scripts a try when I'm back home.
Next, Stefano Rivera and Colin Watson presented Debusine, a new package repository and workflow management system. It looks very promising for anyone running their own repository, so perhaps yet another bit of apt.postgresql.org infrastructure to replace in the future. After that, I went to the Debian LTS BoF session by Santiago Ruano Rinc n and Bastien Roucari s - Debian releases plus LTS is what we are covering with apt.postgresql.org. Then there were bits from the DPL (Debian Project Leader), and a session moderated by Stefano Rivera interesting to me as a member of the Debian Technical Committee on the future structure of the packages required for cross-building in Debian, a topic which had been brought to TC a while ago. I am happy that we could resolve the issue without having to issue a formal TC ruling as the involved parties (kernel, glibc, gcc and the cross-build people) found a promising way forward themselves. DebConf is really a good way to get such issues unstuck.
Ten years ago at the 2015 Heidelberg DebConf, Enrico had given a seminal "Semi-serious stand-up comedy" talk, drawing parallels between the Debian Open Source community and the BDSM community - "People doing things consensually together". (Back then, the talk was announced as "probably unsuitable for people of all ages".) With his unique presentation style and witty insights, the session made a lasting impression on everyone attending. Now, ten years later (and he and many in the audience being ten years older), he gave an updated version of it. We are now looking forward to the sequel in 2035. The evening closed with the famous DebConf tradition of the Cheese & Wine party in a old fort next to the coast, just below the conference venue. Even when he's a fellow Debian Developer, Ham and also TC member, I had never met Paul Tagliamonte in person before, but we spent most of the evening together geeking out on all things Debian and Ham radio.
The northern coast of Ushant (photo: Christoph Berg)
Wednesday, July 16th
Wednesday already marked the end of the first half of the week, the day of the day trips. I had chosen to go to Ouessant island (Ushant in English) which marks the Western end of French mainland and hosts one of the lighthouses yielding the way into the English channel. The ferry trip included surprisingly big waves which left some participants seasick, but everyone recovered fast. After around one and a half hours we arrived, picked up the bicycles, and spent the rest of the day roaming the island. The weather forecast was originally very cloudy and 18 C, but over noon this turned into sunny and warm, so many got an unplanned sunburn. I enjoyed the trip very much - it made up for not having time visiting the city during the week. After returning, we spent the rest of the evening playing DebConf's standard game, Mao (spoiler alert: don't follow the link if you ever intend to play).
Having a nice day (photo: Christoph Berg)
Thursday, July 17th
The next day started with the traditional "Meet the Technical Committee" session. This year, we trimmed the usual slide deck down to remove the boring boilerplate parts, so after a very short introduction to the work of the committee by our chairman Matthew Vernon, we opened up the discussion with the audience, with seven (out of 8) TC members on stage. I think the format worked very well, with good input from attendees. Next up was "Don't fear the TPM" by Jonathan McDowell. A common misconception in the Free Software community is that the TPM is evil DRM hardware working against the user, but while it could be used in theory that way, the necessary TPM attestations seem to impossible to attain in practice, so that wouldn't happen anyway. Instead, it is a crypto coprocessor present in almost all modern computers that can be used to hold keys, for example to be used for SSH. It will also be interesting to research if we can make use of it for holding the Transparent Data Encryption keys for CYBERTEC's PostgreSQL Enterprise Edition.
Aigars Mahinovs then directed everyone in place for the DebConf group picture, and Lucas Nussbaum started a discussion about archive-wide QA tasks in Debian, an area where I did a lot of work in the past and that still interests me. Antonio Terceiro and Paul Gevers followed up with techniques to track archive-wide rebuilding and testing of packages and in turn filing a lot of bugs to track the problems. The evening ended with the conference dinner, again in the fort close by the coast. DebConf is good for meeting new people, and I incidentally ran into another Chris, who happened to be one of the original maintainers of pgaccess, the pre-predecessor of today's pgadmin. I admit still missing this PostgreSQL frontend for its simplicity and ability to easily edit table data, but it disappeared around 2004.
Friday, July 18th
On Friday, I participated in discussion sessions around contributors.debian.org (PostgreSQL is planning to set up something similar) and the New Member process which I had helped to run and reform a decade or two ago. Agathe Porte (also a Ham radio operator, like so many others at the conference I had no idea of) then shared her work on rust-rewriting the slower parts of Lintian, the Debian package linter. Craig Small talked about "Free as in Bytes", the evolution of the Linux procps free command. Over the time and many kernel versions, the summary numbers printed became better and better, but there will probably never be a version that suits all use cases alike. Later over dinner, Craig (who is also a TC member) and I shared our experiences with these numbers and customers (not) understanding them. He pointed out that for PostgreSQL and looking at used memory in the presence of large shared memory buffers, USS (unique set size) and PSS (proportional set size) should be more realistic numbers than the standard RSS (resident set size) that the top utility is showing by default.
Antonio Terceiro and Paul Gevers again joined to lead a session, now on ci.debian.net and autopkgtest, the test driver used for running tests on packages after then have been installed on a system. The PostgreSQL packages are heavily using this to make sure no regressions creep in even after builds have successfully completed and test re-runs are rescheduled periodically. The day ended with Bdale Garbee's electronics team BoF and Paul Tagliamonte and me setting up the radio station in the courtyard, again answering countless questions about ionospheric conditions and operating practice.
Saturday, July 19th
Saturday was the last conference day. In the first session, Nikos Tsipinakis and Federico Vaga from CERN announced that the LHC will be moving to Debian for the accelerator's frontend computers in their next "long shutdown" maintenance period in the next year. CentOS broke compatibility too often, and Debian trixie together with the extended LTS support will cover the time until the next long shutdown window in 2035, until when the computers should have all been replaced with newer processors covering higher x86_64 baseline versions. The audience was very delighted to hear that Debian is now also being used in this prestige project.
Ben Hutchings then presented new Linux kernel features. Particularly interesting for me was the support for atomic writes spanning more than one filesystem block. When configured correctly, this would mean PostgreSQL didn't have to record full-page images in the WAL anymore, increasing throughput and performance. After that, the Debian ftp team discussed ways to improve review of new packages in the archive, and which of their processes could be relaxed with new US laws around Open Source and cryptography algorithms export. Emmanuel Arias led a session on Salsa CI, Debian's Gitlab instance and standard CI pipeline. (I think it's too slow, but the runners are not under their control.) Julian Klode then presented new features in APT, Debian's package manager. I like the new display format (and a tiny bit of that is also from me sending in wishlist bugs).
In the last round of sessions this week, I then led the Ham radio BoF with an introduction into the hobby and how Debian can be used. Bdale mentioned that the sBitx family of SDR radios is natively running Debian, so stock packages can be used from the radio's touch display. We also briefly discussed his involvement in ARDC and the possibility to get grants from them for Ham radio projects. Finally, DebConf wrapped up with everyone gathering in the main auditorium and cheering the organizers for making the conference possible and passing Pollito, the DebConf mascot, to the next organizer team.
Pollito on stage (photo: Christoph Berg)
Sunday, July 20th
Zoom back to the train: I made it through the Paris metro and I'm now on the Eurostar back to Germany. It has been an intense week with all the conference sessions and meeting all the people I had not seen so long. There are a lot of new ideas to follow up on both for my Debian and PostgreSQL work. Next year's DebConf will take place in Santa Fe, Argentina. I haven't yet decided if I will be going, but I can recommend the experience to everyone!
The post The Debian Conference 2025 in Brest appeared first on CYBERTEC PostgreSQL Services & Support.
In May 2021 I bought a ML110 Gen9 to use as a deskside workstation [1]. I started writing this post in April 2022 when it had been my main workstation for almost a year. While this post was in a draft state in Feb 2023 I upgraded it to an 18 core E5-2696 v3 CPU [2]. It s now March 2025 and I have replaced it.
Hardware Issues
My previous state with this was not having adequate cooling to allow it to boot and not having a PCIe power cable for a video card. As an experiment I connected the CPU fan to the PCIe fan power and discovered that all power and monitoring wires for the CPU and PCIe fans are identical. This allowed me to buy a CPU fan which was cheaper ($26.09 including postage) and easier to obtain than a PCIe fan (presumably due to CPU fans being more commonly used and manufactured in larger quantities). I had to be creative in attaching the CPU fan as it s cable wasn t long enough to reach the usual location for a PCIe fan. The PCIe fan also required a baffle to direct the air to the right place which annoyingly HP apparently doesn t ship with the low end servers, so I made one from a Corn Flakes packet and duct tape.
The Wikipedia page listing AMD GPUs lists many newer ones that draw less than 80W and don t need a PCIe power cable. I ordered a Radeon RX560 4G video card which cost $246.75. It only uses 8 lanes of PCIe but that s enough for me, the only 3D game I play is Warzone 2100 which works well at 4K resolution on that card. It would be really annoying if I had to just spend $246.75 to get the system working, but I had another system in need of a better video card which had a PCIe power cable so the effective cost was small. I think of it as upgrading 2 systems for $123 each.
The operation of the PCIe video card was a little different than non-server systems. The built in VGA card displayed the hardware status at the start and then kept displaying that after the system had transitioned to PCIe video. This could be handy in some situations if you know what it s doing but was confusing initially.
Booting
One insidious problem is that when booting in legacy mode the boot process takes an unreasonably long time and often hangs, the UEFI implementation on this system seems much more reliable and also supports booting from NVMe.
Even with UEFI the boot process on this system was slow. Also the early stage of the power on process involves fans being off and the power light flickering which leads you to think that it s not booting and needs to have the power button pressed again which turns it off. The Dell power on sequence of turning most LEDs on and instantly running the fans at high speed leaves no room for misunderstanding. This is also something that companies making electric cars could address. When turning on a machine you should never be left wondering if it is actually on.
Noise
This was always a noisy system. When I upgraded the CPU from an 8 core with 85W typical TDP to an 18 core with 145W typical TDP it became even louder. Then over time as dust accumulated inside the machine it became louder still until it was annoyingly loud outside the room when all 18 cores were busy.
Replacement
I recently blogged about options for getting 8K video to work on Linux [3]. This requires PCIe power which the z640s have (all the ones I have seen have it I don t know if all that HP made have it) and which the cheaper models in the ML-110 line don t have. Since then I have ordered an Intel Arc card which apparently has 190W TDP. There are adaptors to provide PCIe power from SATA or SAS power which I could have used, but having a E5-2696 v3 CPU that draws 145W [4] and a GPU that draws 190W [4] in a system with a 350W PSU doesn t seem viable.
I replaced it with one of the HP z640 workstations I got in 2023 [5].
The current configuration of the z640 has 3*32G RDIMMs compared to the ML110 having 8*32G, going from 256G to 96G is a significant decrease but most tasks run well enough like that. A limitation of the z640 is that when run with a single CPU it only has 4 DIMM slots which gives a maximum of 512G if you get 128G LRDIMMs, but as all DDR4 DIMMs larger than 32G are unreasonably expensive at this time the practical limit is 128G (which costs about $120AU). In this case I have 96G because the system I m using has a motherboard problem which makes the fourth DIMM slot unusable. Currently my desire to get more than 96G of RAM is less than my desire to avoid swapping CPUs.
At this time I m not certain that I will make my main workstation the one that talks to an 8K display. But I really want to keep my options open and there are other benefits.
The z640 boots faster. It supports PCIe bifurcation (with a recent BIOS) so I now have 4 NVMe devices in a single PCIe slot. It is very quiet, the difference is shocking. I initially found it disconcertingly quiet.
The biggest problem with the z640 is having only 4 DIMM sockets and the particular one I m using has a problem limiting it to 3. Another problem with the z640 when compared to the ML110 Gen9 is that it runs the RAM at 2133 while the ML110 runs it at 2400, that s a significant performance reduction. But the benefits outweigh the disadvantages.
Conclusion
I have no regrets about buying the ML-110. It was the only DDR4 ECC system that was in the price range I wanted at the time. If I knew that the z640 systems would run so quietly then I might have replaced it earlier. But it was only late last year that 32G DIMMs became affordable, before then I had 8*16G DIMMs to give 128G because I had some issues of programs running out of memory when I had less.
I can t remember exactly the joke I was making at the time in my
work s slack instance (I m sure it wasn t particularly
funny, though; and not even worth re-reading the thread to work out), but it
wound up with me writing a UEFI binary for the punchline. Not to spoil the
ending but it worked - no pesky kernel, no messing around with userland . I
guess the only part of this you really need to know for the setup here is that
it was a Severance joke,
which is some fantastic TV. If you haven t seen it, this post will seem perhaps
weirder than it actually is. I promise I haven t joined any new cults. For
those who have seen it, the payoff to my joke is that I wanted my machine to
boot directly to an image of
Kier Eagan.
As for how to do it I figured I d give the uefi
crate a shot, and see how it is to use,
since this is a low stakes way of trying it out. In general, this isn t the
sort of thing I d usually post about except this wound up being easier and
way cleaner than I thought it would be. That alone is worth sharing, in the
hopes someome comes across this in the future and feels like they, too, can
write something fun targeting the UEFI.
First thing s first gotta create a rust project (I ll leave that part to you
depending on your life choices), and to add the uefi crate to your
Cargo.toml. You can either use cargo add or add a line like this by hand:
uefi = version = "0.33", features = ["panic_handler", "alloc", "global_allocator"]
We also need to teach cargo about how to go about building for the UEFI target,
so we need to create a rust-toolchain.toml with one (or both) of the UEFI
targets we re interested in:
Unfortunately, I wasn t able to use the
image crate,
since it won t build against the uefi target. This looks like it s
because rustc had no way to compile the required floating point operations
within the image crate without hardware floating point instructions
specifically. Rust tends to punt a lot of that to libm usually, so this isnt
entirely shocking given we re nostd for a non-hardfloat target.
So-called softening requires a software floating point implementation that
the compiler can use to polyfill (feels weird to use the term polyfill here,
but I guess it s spiritually right?) the lack of hardware floating point
operations, which rust hasn t implemented for this target yet. As a result, I
changed tactics, and figured I d use ImageMagick to pre-compute the pixels
from a jpg, rather than doing it at runtime. A bit of a bummer, since I need
to do more out of band pre-processing and hardcoding, and updating the image
kinda sucks as a result but it s entirely manageable.
This will take our input file (kier.jpg), resize it to get as close to the
desired resolution as possible while maintaining aspect ration, then convert it
from a jpg to a flat array of 4 byte RGBA pixels. Critically, it s also
important to remember that the size of the kier.full.jpg file may not actually
be the requested size it will not change the aspect ratio, so be sure to
make a careful note of the resulting size of the kier.full.jpg file.
Last step with the image is to compile it into our Rust bianary, since we
don t want to struggle with trying to read this off disk, which is thankfully
real easy to do.
Remember to use the width and height from the final kier.full.jpg file as the
values for KIER_WIDTH and KIER_HEIGHT. KIER_PIXEL_SIZE is 4, since we
have 4 byte wide values for each pixel as a result of our conversion step into
RGBA. We ll only use RGB, and if we ever drop the alpha channel, we can drop
that down to 3. I don t entirely know why I kept alpha around, but I figured it
was fine. My kier.full.jpg image winds up shorter than the requested height
(which is also qemu s default resolution for me) which means we ll get a
semi-annoying black band under the image when we go to run it but it ll
work.
Anyway, now that we have our image as bytes, we can get down to work, and
write the rest of the code to handle moving bytes around from in-memory
as a flat block if pixels, and request that they be displayed using the
UEFI GOP. We ll just need to hack up a container
for the image pixels and teach it how to blit to the display.
/// RGB Image to move around. This isn't the same as an
/// image::RgbImage , but we can associate the size of
/// the image along with the flat buffer of pixels.
structRgbImage/// Size of the image as a tuple, as the
/// (width, height)
size: (usize, usize),
/// raw pixels we'll send to the display.
inner: Vec<BltPixel>,
impl RgbImage
/// Create a new RgbImage .
fnnew(width: usize, height: usize) -> Self
RgbImage
size: (width, height),
inner: vec![BltPixel::new(0, 0, 0); width * height],
/// Take our pixels and request that the UEFI GOP
/// display them for us.
fnwrite(&self, gop: &mut GraphicsOutput) -> Result
gop.blt(BltOp::BufferToVideo
buffer: &self.inner,
src: BltRegion::Full,
dest: (0, 0),
dims: self.size,
)
impl Index<(usize, usize)>for RgbImage
typeOutput= BltPixel;
fnindex(&self, idx: (usize, usize)) -> &BltPixellet (x, y) = idx;
&self.inner[y * self.size.0+ x]
impl IndexMut<(usize, usize)>for RgbImage
fnindex_mut(&mut self, idx: (usize, usize)) -> &mut BltPixel
let (x, y) = idx;
&mut self.inner[y * self.size.0+ x]
We also need to do some basic setup to get a handle to the UEFI
GOP via the UEFI crate (using
uefi::boot::get_handle_for_protocol
and
uefi::boot::open_protocol_exclusive
for the GraphicsOutput
protocol), so that we have the object we need to pass to RgbImage in order
for it to write the pixels to the display. The only trick here is that the
display on the booted system can really be any resolution so we need to do
some capping to ensure that we don t write more pixels than the display can
handle. Writing fewer than the display s maximum seems fine, though.
fnpraise() -> Result
let gop_handle = boot::get_handle_for_protocol::<GraphicsOutput>()?;
letmut gop = boot::open_protocol_exclusive::<GraphicsOutput>(gop_handle)?;
// Get the (width, height) that is the minimum of
// our image and the display we're using.
let (width, height) = gop.current_mode_info().resolution();
let (width, height) = (width.min(KIER_WIDTH), height.min(KIER_HEIGHT));
letmut buffer = RgbImage::new(width, height);
for y in0..height
for x in0..width
let idx_r = ((y * KIER_WIDTH) + x) * KIER_PIXEL_SIZE;
let pixel =&mut buffer[(x, y)];
pixel.red = KIER[idx_r];
pixel.green = KIER[idx_r +1];
pixel.blue = KIER[idx_r +2];
buffer.write(&mut gop)?;
Ok(())
Not so bad! A bit tedious we could solve some of this by turning
KIER into an RgbImage at compile-time using some clever Cow and
const tricks and implement blitting a sub-image of the image but this
will do for now. This is a joke, after all, let s not go nuts. All that s
left with our code is for us to write our main function and try and boot
the thing!
#[entry]fnmain() -> Status
uefi::helpers::init().unwrap();
praise().unwrap();
boot::stall(100_000_000);
Status::SUCCESS
If you re following along at home and so interested, the final source is over at
gist.github.com.
We can go ahead and build it using cargo (as is our tradition) by targeting
the UEFI platform.
Testing the UEFI Blob
While I can definitely get my machine to boot these blobs to test, I figured
I d save myself some time by using QEMU to test without a full boot.
If you ve not done this sort of thing before, we ll need two packages,
qemu and ovmf. It s a bit different than most invocations of qemu you
may see out there so I figured it d be worth writing this down, too.
$ doas apt install qemu-system-x86 ovmf
qemu has a nice feature where it ll create us an EFI partition as a drive and
attach it to the VM off a local directory so let s construct an EFI
partition file structure, and drop our binary into the conventional location.
If you haven t done this before, and are only interested in running this in a
VM, don t worry too much about it, a lot of it is convention and this layout
should work for you.
With all this in place, we can kick off qemu, booting it in UEFI mode using
the ovmf firmware, attaching our EFI partition directory as a drive to
our VM to boot off of.
If all goes well, soon you ll be met with the all knowing gaze of
Chosen One, Kier Eagan. The thing that really impressed me about all
this is this program worked first try it all went so boringly
normal. Truly, kudos to the uefi crate maintainers, it s incredibly
well done.
Booting a live system
Sure, we could stop here, but anyone can open up an app window and see a
picture of Kier Eagan, so I knew I needed to finish the job and boot a real
machine up with this. In order to do that, we need to format a USB stick.
BE SURE /dev/sda IS CORRECT IF YOU RE COPY AND PASTING. All my drives
are NVMe, so BE CAREFUL if you use SATA, it may very well be your
hard drive! Please do not destroy your computer over this.
$ doas fdisk /dev/sda
Welcome to fdisk (util-linux 2.40.4).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Command (m for help): n
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1):
First sector (2048-4014079, default 2048):
Last sector, +/-sectors or +/-size K,M,G,T,P (2048-4014079, default 4014079):
Created a new partition 1 of type 'Linux' and of size 1.9 GiB.
Command (m for help): t
Selected partition 1
Hex code or alias (type L to list all): ef
Changed type of partition 'Linux' to 'EFI (FAT-12/16/32)'.
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
Once that looks good (depending on your flavor of udev you may or
may not need to unplug and replug your USB stick), we can go ahead
and format our new EFI partition (BE CAREFUL THAT /dev/sda IS YOUR
USB STICK) and write our EFI directory to it.
$ doas mkfs.fat /dev/sda1
$ doas mount /dev/sda1 /mnt
$ cp -r esp/efi /mnt
$ find /mnt
/mnt
/mnt/efi
/mnt/efi/boot
/mnt/efi/boot/bootx64.efi
Of course, naturally, devotion to Kier shouldn t mean backdooring your system.
Disabling Secure Boot runs counter to the Core Principals, such as Probity, and
not doing this would surely run counter to Verve, Wit and Vision. This bit does
require that you ve taken the step to enroll a
MOK and know how
to use it, right about now is when we can use sbsign to sign our UEFI binary
we want to boot from to continue enforcing Secure Boot. The details for how
this command should be run specifically is likely something you ll need to work
out depending on how you ve decided to manage your MOK.
I figured I d leave a signed copy of boot2kier at
/boot/efi/EFI/BOOT/KIER.efi on my Dell XPS 13, with Secure Boot enabled
and enforcing, just took a matter of going into my BIOS to add the right
boot option, which was no sweat. I m sure there is a way to do it using
efibootmgr, but I wasn t smart enough to do that quickly. I let er rip,
and it booted up and worked great!
It was a bit hard to get a video of my laptop, though but lucky for me, I
have a Minisforum Z83-F sitting around (which, until a few weeks ago was running
the annual http server to control my christmas tree
) so I grabbed it out of the christmas bin, wired it up to a video capture
card I have sitting around, and figured I d grab a video of me booting a
physical device off the boot2kier USB stick.
Attentive readers will notice the image of Kier is smaller then the qemu booted
system which just means our real machine has a larger GOP display
resolution than qemu, which makes sense! We could write some fancy resize code
(sounds annoying), center the image (can t be assed but should be the easy way
out here) or resize the original image (pretty hardware specific workaround).
Additionally, you can make out the image being written to the display before us
(the Minisforum logo) behind Kier, which is really cool stuff. If we were real
fancy we could write blank pixels to the display before blitting Kier, but,
again, I don t think I care to do that much work.
But now I must away
If I wanted to keep this joke going, I d likely try and find a copy of the
original
video when Helly 100%s her file
and boot into that or maybe play a terrible midi PC speaker rendition of
Kier, Chosen One, Kier after
rendering the image. I, unfortunately, don t have any friends involved with
production (yet?), so I reckon all that s out for now. I ll likely stop playing
with this the joke was done and I m only writing this post because of how
great everything was along the way.
All in all, this reminds me so much of building a homebrew kernel to boot a
system into but like, good, though, and it s a nice reminder of both how
fun this stuff can be, and how far we ve come. UEFI protocols are light-years
better than how we did it in the dark ages, and the tooling for this is SO
much more mature. Booting a custom UEFI binary is miles ahead of trying to
boot your own kernel, and I can t believe how good the uefi crate is
specifically.
Praise Kier! Kudos, to everyone involved in making this so delightful .
Vienna - the capital of Austria - is one of the most visited cities in the world, popular for its rich history, gardens, and cafes, along with well-known artists like Beethoven, Mozart, G del, and Freud. It has also been consistently ranked as the most livable city in the world.
For these reasons, I was elated when my friend Snehal invited me last year to visit Vienna for a few days. We included Christmas and New Year s Eve in my itinerary due to the city s popular Christmas markets and lively events. The festive season also ensured that Snehal had some days off for sightseeing.
Indians require a visa to visit Austria. Since the travel dates were near, I rushed to book an appointment online with VFS Global in Delhi, and quickly arranged the required documents. However, at VFS, I found out that I had applied in the wrong appointment category (tourist), which depends on the purpose of the visit, and that my travel dates do not allow enough time for visa authorities to make a decision. Apparently, even if you plan to stay only for a part of the trip with the host, you need to apply under the category Visiting Friends and Family .
Thus, I had to book another appointment under this category, and took the opportunity to shift my travel dates to allow at least 15 business days for the visa application to be processed, removing Christmas and New Year s Eve from my itinerary.
The process went smoothly, and my visa application was submitted by VFS. For reference, here s a list of documents I submitted -
VFS appointment letter
Duly-filled visa application form
Original passport
Copy of passport
1 photograph
My 6 months bank account statement
Cover letter
Consent form (that visa processing will take up to 15 business days)
Snehal s job contract
My work contract
Rent contract of Snehal
Residence permit of Snehal
A copy of Snehal s passport
Invitation letter from Snehal
Return flight ticket reservations
Travel insurance for the intended travel dates
The following charges were collected from me.
Service Description
Amount (Indian Rupees)
Cash Handling Charge - SAC Code: (SAC:998599)
0
VFS Fee - India - SAC Code: (SAC:998599)
1,820
VISA Fee - India - SAC Code:
7,280
Convenience Fee - SAC Code: (SAC:998599)
182
Courier Service - SAC Code: (SAC:998599)
728
Courier Assurance - SAC Code: (SAC:998599)
182
Total
10,192
I later learned that the courier charges (728 INR) and the courier assurance charges (182 INR) mentioned above were optional. However, VFS didn t ask whether I wanted to include them. When the emabssy is done processing your application, it will send your passport back to VFS, from where you can either collect it yourself or get it couriered back home, which requires you to pay courier charges. However, courier assurance charges do not add any value as VFS cannot assure anything about courier and I suggest you get them removed.
My visa application was submitted on the 21st of December 2023. A few days later, on the 29th of December 2023, I received an email from the Austrian embassy asking me to submit an additional document -
Subject: AUSTRIAN VISA APPLICATION - AMENDMENT REQUEST: Ravi Dwivedi VIS 4331
Dear Applicant,
On 22.12.2023 your application for Visa C was registered at the Embassy. You are requested to kindly send the scanned copies of the following documents via email to the Embassy or submit the documents at the nearest VFS centre, for further processing of your application:
Kindly submit Electronic letter of guarantee EVE- Elektronische Verpflichtungserkl rung obtained from the Fremdenpolizeibeh rde of the sponsor s district in Austria. Once your host company/inviting company has obtained the EVE, please share the reference number (starting from DEL_____) received from the authorities, with the Embassy.
Kindly Note:
It is in your own interest to fulfil the requirements as indicated above and submit the missing documents within 14 days of the receipt of this email. Otherwise a decision will be taken based on the documentation available.
Sie werden in Ihrem Interesse ersucht, die gekennzeichneten M ngel so schnell wie m glich zu beheben bzw. fehlende Unterlagen umgehend nachzureichen, um die weitere Bearbeitung des Antrages zu erm glichen. Sollten Sie innerhalb 14 Tagen die gekennzeichneten M ngel nicht beheben bzw. die fehlenden Unterlagen nicht nachreichen, wird ber den vorliegenden Antrag ohne diese Unterlagen bzw. M ngelbehebung entschieden.
Austrian Embassy New Delhi
R.J/ Consular Section
+91 11 2419 2700
EP-13, Chandragupta Marg, Chanakyapuri, New Delhi 110 021, India
bmeia.gv.at/botschaft/new-delhi
facebook.at/AustrianEmbassyNewDelhihttp://www.facebook.at/AustrianEmbassyNewDelhi twitter.com/MFA_Austriahttp://www.twitter.com/MFA_Austria
[refocus1][Signatur_V+30]https://www.bmeia.gv.at/en/european-foreign-policy/foreign-trade/refocus-austria/[Logo_AT_IN_22px]
I misunderstood the required document (the EVE) to be a scanned copy of the letter of guarantee form signed by Snehal, and responded by attaching it.
Upon researching, Snehal determined that the document is an electronic letter of guarantee, and is supposed to be obtained at a local police station in Vienna. He visited a police station the next day and had a hard time conversing due to the language barrier (German is the common language in Austria, whereas Snehal speaks English). That day was a weekend, so he took an appointment for Monday, but in the meantime the embassy had finished processing my visa.
My visa was denied, and the refusal letter stated:
The Austrian embassy in Delhi examined your application; the visa has been refused.
The decision is based on the following reason(s):
The information submitted regarding the justification for the purpose and conditions of the intended stay was not reliable.
There are reasonable doubts as to your intention to leave the territory of the Member States before the expiry of the visa.
Other remarks:
You have been given an amendment request, which you have failed to fulfil, or have only fulfilled inadequately, within the deadline set.
You are a first-time traveller. The social and economic roots with the home country are not evident. The return from Schengen territory does therefore not seem to be certain.
I could have reapplied after obtaining the EVE, but I didn t because I found the following line
The social and economic roots with the home country are not evident.
offensive for someone who was born and raised in India, got the impression that the absence of electronic guarantee letter was not the only reason behind the refusal, had already wasted 12,000 INR on this application, and my friend s stay in Austria was uncertain after January. In fact, my friend soon returned to India.
To summarize -
If you are visiting a host, then the category of appointment at VFS must be Visiting Friends and Family rather than Tourist .
VFS charged me for courier assurance, which is an optional service. Make sure to get these removed from your bill.
Neither my travel agent nor the VFS application center mentioned the EVE.
Snehal informed me that a mere two months ago, his wife s visa was approved without an EVE. This hints at inconsistency in processing of applications, even those under identical categories.
Such incidents are a waste of time and money for applicants, and an embarrassment to VFS and the Austrian visa authorities. I suggest that the Austrian visa authorities fix that URL, and provide instructions for hosts to obtain the EVE.
Credits to Snehal and Contrapunctus for editing, Badri for proofreading.
Last week marked a major milestone for me:
the AMD driver-specific color management properties
reached the upstream linux-next!
And to celebrate, I m happy to share the
slides
notes from my 2023 XDC talk, The Rainbow Treasure Map along with the
individual recording that just
dropped last week on youtube talk about happy coincidences!
Steam Deck Rainbow: Treasure Map & Magic Frogs
While I may be bubbly and chatty in everyday life, the stage isn t exactly my
comfort zone (hallway talks are more my speed). But the journey of developing
the AMD color management properties was so full of discoveries that I simply
had to share the experience. Witnessing the fantastic work of Jeremy and Joshua
bring it all to life on the Steam Deck OLED was like uncovering magical
ingredients and whipping up something truly enchanting.
For XDC 2023, we split our Rainbow journey into two talks. My focus, The
Rainbow Treasure Map, explored the new color features we added to the Linux
kernel driver, diving deep into the hardware capabilities of AMD/Steam Deck.
Joshua then followed with The Rainbow Frogs and showed the breathtaking color
magic released on Gamescope thanks to the power unlocked by the kernel driver s
Steam Deck color properties.
Packing a Rainbow into 15 Minutes
I had so much to tell, but a half-slot talk meant crafting a concise
presentation. To squeeze everything into 15 minutes (and calm my pre-talk
jitters a bit!), I drafted and practiced those slides and notes countless
times.
So grab your map, and let s embark on the Rainbow journey together!
Intro: Hi, I m Melissa from Igalia and welcome to the Rainbow Treasure Map, a
talk about advanced color management on Linux with AMD/SteamDeck.
Useful links: First of all, if you are not used to the topic, you may find
these links useful.
Context: When we talk about colors in the graphics chain, we should keep in
mind that we have a wide variety of source content colorimetry, a variety of
output display devices and also the internal processing. Users expect
consistent color reproduction across all these devices.
The userspace can use GPU-accelerated color management to get it. But this also
requires an interface with display kernel drivers that is currently missing
from the DRM/KMS framework.
Since April, I ve been bothering the DRM community by sending patchsets from
the work of me and Joshua to add driver-specific color properties to the AMD
display driver. In parallel, discussions on defining a generic color management
interface are still ongoing in the community. Moreover, we are still not clear
about the diversity of color capabilities among hardware vendors.
To bridge this gap, we defined a color pipeline for Gamescope that fits the
latest versions of AMD hardware. It delivers advanced color management features
for gamut mapping, HDR rendering, SDR on HDR, and HDR on SDR.
AMD/Steam Deck hardware: AMD frequently releases new GPU and APU generations.
Each generation comes with a DCN version with display hardware improvements.
Therefore, keep in mind that this work uses the AMD Steam Deck hardware and its
kernel driver. The Steam Deck is an APU with a DCN3.01 display driver, a DCN3
family.
It s important to have this information since newer AMD DCN drivers inherit
implementations from previous families but aldo each generation of AMD hardware
may introduce new color capabilities. Therefore I recommend you to familiarize
yourself with the hardware you are working on.
The AMD display driver in the kernel space: It consists of three layers, (1)
the DRM/KMS framework, (2) the AMD Display Manager, and (3) the AMD Display
Core. We extended the color interface exposed to userspace by leveraging
existing DRM resources and connecting them using driver-specific functions for
color property management.
Bridging DC color capabilities and the DRM API required significant changes in
the color management of AMD Display Manager - the Linux-dependent part that
connects the AMD DC interface to the DRM/KMS framework.
The AMD DC is the OS-agnostic layer. Its code is shared between platforms and
DCN versions. Examining this part helps us understand the AMD color pipeline
and hardware capabilities, since the machinery for hardware settings and
resource management are already there.
The newest architecture for AMD display hardware is the AMD Display Core Next.
In this architecture, two blocks have the capability to manage colors:
Display Pipe and Plane (DPP) - for pre-blending adjustments;
Multiple Pipe/Plane Combined (MPC) - for post-blending color transformations.
Let s see what we have in the DRM API for pre-blending color management.
DRM plane color properties:
This is the DRM color management API before blending.
Nothing!
Except two basic DRM plane properties: color_encoding and color_range for
the input colorspace conversion, that is not covered by this work.
In case you re not familiar with AMD shared code, what we need to do is
basically draw a map and navigate there!
We have some DRM color properties after blending, but nothing before blending
yet. But much of the hardware programming was already implemented in the AMD DC
layer, thanks to the shared code.
Still both the DRM interface and its connection to the shared code were
missing. That s when the search begins!
AMD driver-specific color pipeline:
Looking at the color capabilities of the hardware, we arrive at this initial
set of properties. The path wasn t exactly like that. We had many iterations
and discoveries until reached to this pipeline.
The Plane Degamma is our first driver-specific property before blending. It s
used to linearize the color space from encoded values to light linear values.
We can use a pre-defined transfer function or a user lookup table (in short,
LUT) to linearize the color space.
Pre-defined transfer functions for plane degamma are hardcoded curves that go
to a specific hardware block called DPP Degamma ROM. It supports the following
transfer functions: sRGB EOTF, BT.709 inverse OETF, PQ EOTF, and pure power
curves Gamma 2.2, Gamma 2.4 and Gamma 2.6.
We also have a one-dimensional LUT. This 1D LUT has four thousand ninety six
(4096) entries, the usual 1D LUT size in the DRM/KMS. It s an array of
drm_color_lut that goes to the DPP Gamma Correction block.
We also have now a color transformation matrix (CTM) for color space
conversion.
It s a 3x4 matrix of fixed points that goes to the DPP Gamut Remap Block.
Both pre- and post-blending matrices were previously gone to the same color
block. We worked on detaching them to clear both paths.
Now each CTM goes on its own way.
Next, the HDR Multiplier. HDR Multiplier is a factor applied to the color
values of an image to increase their overall brightness.
This is useful for converting images from a standard dynamic range (SDR) to a
high dynamic range (HDR). As it can range beyond [0.0, 1.0] subsequent
transforms need to use the PQ(HDR) transfer functions.
And we need a 3D LUT. But 3D LUT has a limited number of entries in each
dimension, so we want to use it in a colorspace that is optimized for human
vision. It means in a non-linear space. To deliver it, userspace may need one
1D LUT before 3D LUT to delinearize content and another one after to linearize
content again for blending.
The pre-3D-LUT curve is called Shaper curve. Unlike Degamma TF, there are no
hardcoded curves for shaper TF, but we can use the AMD color module in the
driver to build the following shaper curves from pre-defined coefficients. The
color module combines the TF and the user LUT values into the LUT that goes to
the DPP Shaper RAM block.
Finally, our rockstar, the 3D LUT. 3D LUT is perfect for complex color
transformations and adjustments between color channels.
3D LUT is also more complex to manage and requires more computational
resources, as a consequence, its number of entries is usually limited. To
overcome this restriction, the array contains samples from the approximated
function and values between samples are estimated by tetrahedral interpolation.
AMD supports 17 and 9 as the size of a single-dimension. Blue is the outermost
dimension, red the innermost.
As mentioned, we need a post-3D-LUT curve to linearize the color space before
blending. This is done by Blend TF and LUT.
Similar to shaper TF, there are no hardcoded curves for Blend TF. The
pre-defined curves are the same as the Degamma block, but calculated by the
color module. The resulting LUT goes to the DPP Blend RAM block.
Now we have everything connected before blending. As a conflict between plane
and CRTC Degamma was inevitable, our approach doesn t accept that both are set
at the same time.
We also optimized the conversion of the framebuffer to wire encoding by adding
support to pre-defined CRTC Gamma TF.
Again, there are no hardcoded curves and TF and LUT are combined by the AMD
color module. The same types of shaper curves are supported. The resulting LUT
goes to the MPC Gamma RAM block.
Finally, we arrived in the final version of DRM/AMD driver-specific color
management pipeline. With this knowledge, you re ready to better enjoy the
rainbow treasure of AMD display hardware and the world of graphics computing.
With this work, Gamescope/Steam Deck embraces the color capabilities of the AMD
GPU. We highlight here how we map the Gamescope color pipeline to each AMD
color block.
Future works:
The search for the rainbow treasure is not over! The Linux DRM subsystem
contains many hidden treasures from different vendors. We want more complex
color transformations and adjustments available on Linux. We also want to
expose all GPU color capabilities from all hardware vendors to the Linux
userspace.
Thanks Joshua and Harry for this joint work and the Linux DRI community for all feedback and reviews.
The amazing part of this work comes in the next talk with Joshua and The Rainbow Frogs!
Any questions?
References:
This is part 2 of our series entitled "ROS people don't know how to use
computers". This is about ROS1. ROS2 is presumably broken in some completely
different way, but I don't know.
Unlike normal people, the ROS people don't "run" applications. They "launch"
"nodes" from "packages" (these are "ROS" packages; obviously). You run
roslaunch PACKAGE THING.launch
Then it tries to find this PACKAGE (using some rules that nobody understands),
and tries to find the file THING.launch within this package. The .launch
file contains inscrutable xml, which includes other inscrutable xml. And
if you dig, you eventually find stuff like
This defines the thing that runs. Unexpectedly, the executable that ends up
running is called TYPE.
I know that my particular program is broken, and needs an LD_PRELOAD (exciting
details described in another rant in the near future). But the above definition
doesn't have a clear way to add that. Adding it to the type fails (with a very
mysterious error message). Reading the docs tells you about launch-prefix,
which sounds exactly like what I want. But when I add
LD_PRELOAD=/tmp/whatever.so I get
RLException: Roslaunch got a 'No such file or directory' error while attempting to run:
LD_PRELOAD=/tmp/whatever.so ..../TYPE .....
But this is how you're supposed to be attaching gdb and such! Presumably it
looks at the first token, and makes sure it's a file, instead of simply
prepending it to the string it passes to the shell. So your options are:
Do only approved ROS things in the docs (which are limited, since the docs
were written by people who don't know how to use computers)
Freexian Meetup, by Stefano Rivera, Utkarsh Gupta, et al.
During DebConf, Freexian organized a
meetup for its
collaborators and those interested in learning more about Freexian and its
services. It was well received and many people interested in Freexian showed up.
Some developers who were interested in contributing to LTS came to get more
details about joining the project. And some prospective customers came to get to
know us and ask questions.
Sadly, the tragic loss of Abraham
shook DebConf, both individually and structurally. The meetup got rescheduled to
a small room without video coverage. With that, we still had a wholesome
interaction and here s a quick picture from the meetup taken by Utkarsh (which
is also why he s missing!).
Debusine, by Rapha l Hertzog, et al.
Freexian has been investing into
debusine for a while, but
development speed is about to increase dramatically thanks to funding from
SovereignTechFund.de. Rapha l laid out the
5 milestones of
the funding contract, and filed the
issues for the first milestone.
Together with Enrico and Stefano, they established a
workflow
for the expanded team.
Among the first steps of this milestone, Enrico started to work on a
developer-friendly description of debusine
that we can use when we reach out to the many Debian contributors that we will
have to interact with. And Rapha l started the design work of the autopkgtest
and lintian tasks,
i.e. what s the interface to schedule such tasks, what behavior and what
associated options do we support?
At this point you might wonder what debusine is supposed to be let us try to
answer this: Debusine manages scheduling and distribution of Debian-related
build and QA tasks to a network of worker machines. It also manages the
resulting artifacts and provides the results in an easy to consume way.
We want to make it easy for Debian contributors to leverage all the great QA
tools that Debian provides. We want to build the next generation of Debian s
build infrastructure, one that will continue to reliably do what it already
does, but that will also enable distribution-wide experiments, custom package
repositories and custom workflows with advanced package reviews.
If this all sounds interesting to you, don t hesitate to
watch the project on salsa.debian.org
and to contribute.
lpr/lpd in Debian, by Thorsten Alteholz
During Debconf23, Till Kamppeter presented CPDB (Common Print Dialog Backend),
a new way to handle print queues. After this talk it was discussed whether the
old lpr/lpd based printing system could be abandoned in Debian or whether there
is still demand for it.
So Thorsten asked on the
debian-devel email list
whether anybody uses it. Oddly enough, these old packages are still useful:
Within a small network it is easier to distribute a printcap file, than to
properly configure cups clients.
One of the biggest manufacturers of WLAN router and DSL boxes only supports
raw queues when attaching an USB printer to their hardware. Admittedly the
CPDB still has problems with such raw queues.
The Pharos printing system at MIT is still lpd-based.
As a result, the lpr/lpd stuff is not yet ready to be abandoned and Thorsten
will adopt the relevant packages (or rather move them under the umbrella of the
debian-printing team). Though it is not planned to develop new features, those
packages should at least have a maintainer. This month Thorsten adopted rlpr,
an utility for lpd printing without using /etc/printcap. The next one he is
working on is lprng, a lpr/lpd printer spooling system. If you know of any
other package that is also needed and still maintained by the QA team, please
tell Thorsten.
/usr-merge, by Helmut Grohne
Discussion about lifting the file move moratorium has been initiated with the
CTTE and the release team. A formal lift is
dependent on updating debootstrap in older suites though. A significant number
of packages can automatically move their systemd unit files if
dh_installsystemd and systemd.pc change their installation targets.
Unfortunately, doing so makes some packages FTBFS and therefore
patches have been filed.
The analysis tool, dumat, has been enhanced to better understand
which upgrade scenarios are considered supported
to reduce false positive bug filings and gained a mode for
local operation on a .changes file
meant for inclusion in salsa-ci. The filing of bugs from dumat is still
manual to improve the quality of reports.
Since September, the moratorium
has been lifted.
Miscellaneous contributions
Rapha l updated Django s backport in bullseye-backports to match the latest
security release that was published in bookworm. Tracker.debian.org is still
using that backport.
Helmut Grohne sent 13 patches for cross build failures.
Helmut Grohne performed a maintenance upload of debvm enabling its
use in autopkgtests.
Helmut Grohne wrote an API-compatible reimplementation of
autopkgtest-build-qemu. It is powered by mmdebstrap, therefore
unprivileged, EFI-only and will soon be
included in mmdebstrap.
Santiago continued the work regarding how to make it easier to
(automatically) test reverse dependencies.
An example
of the ongoing work was presented during the Salsa CI BoF at DebConf 23.
In fact, omniorb-dfsg test pipelines as the above were used for the
omniorb-dfsg 4.3.0 transition,
verifying how the reverse dependencies (tango, pytango and omnievents) were
built and how their autopkgtest jobs run with the to-be-uploaded omniorb-dfsg
new release.
Utkarsh and Stefano attended and helped run DebConf 23. Also continued
winding up DebConf 22 accounting.
If you are an email system administrator, you are probably using DKIM to sign your outgoing emails. You should be rotating the key regularly and automatically, and publishing old private keys. I have just released dkim-rotate 1.0; dkim-rotate is a tool to do this key rotation and publication.
If you are an email user, your email provider ought to be doing this. If this is not done, your emails are non-repudiable , meaning that if they are leaked, anyone (eg, journalists, haters) can verify that they are authentic, and prove that to others. This is not desirable (for you).
Non-repudiation of emails is undesirable
This problem was described at some length in Matthew Green s article Ok Google: please publish your DKIM secret keys.
Avoiding non-repudiation sounds a bit like lying. After all, I m advising creating a situation where some people can t verify that something is true, even though it is. So I m advocating casting doubt. Crucially, though, it s doubt about facts that ought to be private. When you send an email, that s between you and the recipient. Normally you don t intend for anyone, anywhere, who happens to get a copy, to be able to verify that it was really you that sent it.
In practical terms, this verifiability has already been used by journalists to verify stolen emails. Associated Press provide a verification tool.
Advice for all email users
As a user, you probably don t want your emails to be non-repudiable. (Other people might want to be able to prove you sent some email, but your email system ought to serve your interests, not theirs.)
So, your email provider ought to be rotating their DKIM keys, and publishing their old ones. At a rough guess, your provider probably isn t :-(.
How to tell by looking at email headers
A quick and dirty way to guess is to have a friend look at the email headers of a message you sent. (It is important that the friend uses a different email provider, since often DKIM signatures are not applied within a single email system.)
If your friend sees a DKIM-Signature header then the message is DKIM signed. If they don t, then it wasn t. Most email traversing the public internet is DKIM signed nowadays; so if they don t see the header probably they re not looking using the right tools, or they re actually on the same email system as you.
In messages signed by a system running dkim-rotate, there will also be a header about the key rotation, to notify potential verifiers of the situation. Other systems that avoid non-repudiation-through-DKIM might do something similar. dkim-rotate s header looks like this:
But an email system might do half of the job of dkim-rotate: regularly rotating the key would cause the signatures of old emails to fail to verify, which is a good start. In that case there probably won t be such a header.
Testing verification of new and old messages
You can also try verifying the signatures. This isn t entirely straightforward, especially if you don t have access to low-level mail tooling. Your friend will need to be able to save emails as raw whole headers and body, un-decoded, un-rendered.
If your friend is using a traditional Unix mail program, they should save the message as an mbox file. Otherwise, ProPublica have instructions for attaching and transferring and obtaining the raw email. (Scroll down to How to Check DKIM and ARC .)
Checking that recent emails are verifiable
Firstly, have your friend test that they can in fact verify a DKIM signature. This will demonstrate that the next test, where the verification is supposed to fail, is working properly and fails for the right reasons.
Send your friend a test email now, and have them do this on a Linux system:
# save the message as test-email.mbox
apt install libmail-dkim-perl # or equivalent on another distro
dkimproxy-verify <test-email.mbox
You should see output containing something like this:
If the output ontains verify result: fail (body has been altered) then probably your friend didn t manage to faithfully save the unalterered raw message.
Checking old emails cannot be verified
When you both have that working, have your friend find an older email of yours, from (say) month ago. Perform the same steps.
Hopefully they will see something like this:
verify result: invalid (public key: not available)
This indicates that this old email can no longer be verified. That s good: it means that anyone who steals a copy, can t verify it either. If it s leaked, the journalist who receives it won t know it s genuine and unmodified; they should then be suspicious.
If your friend sees verify result: pass, then they have verified that that old email of yours is genuine. Anyone who had a copy of the mail can do that. This is good for email thieves, but not for you.
For email admins: announcing dkim-rotate 1.0
I have been running dkim-rotate 0.4 on my infrastructure, since last August. and I had entirely forgotten about it: it has run flawlessly for a year. I was reminded of the topic by seeing DKIM in other blog posts. Obviously, it is time to decreee that dkim-rotate is 1.0.
If you re a mail system administrator, your users are best served if you use something like dkim-rotate. The package is available in Debian stable, and supports Exim out of the box, but other MTAs should be easy to support too, via some simple ad-hoc scripting.
Limitation of this approach
Even with this key rotation approach, emails remain nonrepudiable for a short period after they re sent - typically, a few days.
Someone who obtains a leaked email very promptly, and shows it to the journalist (for example) right away, can still convince the journalist. This is not great, but at least it doesn t apply to the vast bulk of your email archive.
There are possible email protocol improvements which might help, but they re quite out of scope for this article.
Edited 2023-10-01 00:20 +01:00 to fix some grammar
TPMs contain a set of registers ("Platform Configuration Registers", or PCRs) that are used to track what a system boots. Each time a new event is measured, a cryptographic hash representing that event is passed to the TPM. The TPM appends that hash to the existing value in the PCR, hashes that, and stores the final result in the PCR. This means that while the PCR's value depends on the precise sequence and value of the hashes presented to it, the PCR value alone doesn't tell you what those individual events were. Different PCRs are used to store different event types, but there are still more events than there are PCRs so we can't avoid this problem by simply storing each event separately.
This is solved using the event log. The event log is simply a record of each event, stored in RAM. The algorithm the TPM uses to calculate the PCR values is known, so we can reproduce that by simply taking the events from the event log and replaying the series of events that were passed to the TPM. If the final calculated value is the same as the value in the PCR, we know that the event log is accurate, which means we now know the value of each individual event and can make an appropriate judgement regarding its security.
If any value in the event log is invalid, we'll calculate a different PCR value and it won't match. This isn't terribly helpful - we know that at least one entry in the event log doesn't match what was passed to the TPM, but we don't know which entry. That means we can't trust any of the events associated with that PCR. If you're trying to make a security determination based on this, that's going to be a problem.
PCR 7 is used to track information about the secure boot policy on the system. It contains measurements of whether or not secure boot is enabled, and which keys are trusted and untrusted on the system in question. This is extremely helpful if you want to verify that a system booted with secure boot enabled before allowing it to do something security or safety critical. Unfortunately, if the device gives you an event log that doesn't replay correctly for PCR 7, you now have no idea what the security state of the system is.
We ran into that this week. Examination of the event log revealed an additional event other than the expected ones - a measurement accompanied by the string "Boot Guard Measured S-CRTM". Boot Guard is an Intel feature where the CPU verifies the firmware is signed with a trusted key before executing it, and measures information about the firmware in the process. Previously I'd only encountered this as a measurement into PCR 0, which is the PCR used to track information about the firmware itself. But it turns out that at least some versions of Boot Guard also measure information about the Boot Guard policy into PCR 7. The argument for this is that this is effectively part of the secure boot policy - having a measurement of the Boot Guard state tells you whether Boot Guard was enabled, which tells you whether or not the CPU verified a signature on your firmware before running it (as I wrote before, I think Boot Guard has user-hostile default behaviour, and that enforcing this on consumer devices is a bad idea).
But there's a problem here. The event log is created by the firmware, and the Boot Guard measurements occur before the firmware is executed. So how do we get a log that represents them? That one's fairly simple - the firmware simply re-calculates the same measurements that Boot Guard did and creates a log entry after the fact[1]. All good.
Except. What if the firmware screws up the calculation and comes up with a different answer? The entry in the event log will now not match what was sent to the TPM, and replaying will fail. And without knowing what the actual value should be, there's no way to fix this, which means there's no way to verify the contents of PCR 7 and determine whether or not secure boot was enabled.
But there's still a fundamental source of truth - the measurement that was sent to the TPM in the first place. Inspired by Henri Nurmi's work on sniffing Bitlocker encryption keys, I asked a coworker if we could sniff the TPM traffic during boot. The TPM on the board in question uses SPI, a simple bus that can have multiple devices connected to it. In this case the system flash and the TPM are on the same SPI bus, which made things easier. The board had a flash header for external reprogramming of the firmware in the event of failure, and all SPI traffic was visible through that header. Attaching a logic analyser to this header made it simple to generate a record of that. The only problem was that the chip select line on the header was attached to the firmware flash chip, not the TPM. This was worked around by simply telling the analysis software that it should invert the sense of the chip select line, ignoring all traffic that was bound for the flash and paying attention to all other traffic. This worked in this case since the only other device on the bus was the TPM, but would cause problems in the event of multiple devices on the bus all communicating.
With the aid of this analyser plugin, I was able to dump all the TPM traffic and could then search for writes that included the "0182" sequence that corresponds to the command code for a measurement event. This gave me a couple of accesses to the locality 3 registers, which was a strong indication that they were coming from the CPU rather than from the firmware. One was for PCR 0, and one was for PCR 7. This corresponded to the two Boot Guard events that we expected from the event log. The hash in the PCR 0 measurement was the same as the hash in the event log, but the hash in the PCR 7 measurement differed from the hash in the event log. Replacing the event log value with the value actually sent to the TPM resulted in the event log now replaying correctly, supporting the hypothesis that the firmware was failing to correctly reconstruct the event.
What now? The simple thing to do is for us to simply hard code this fixup, but longer term we'd like to figure out how to reconstruct the event so we can calculate the expected value ourselves. Unfortunately there doesn't seem to be any public documentation on this. Sigh.
[1] What stops firmware on a system with no Boot Guard faking those measurements? TPMs have a concept of "localities", effectively different privilege levels. When Boot Guard performs its initial measurement into PCR 0, it does so at locality 3, a locality that's only available to the CPU. This causes PCR 0 to be initialised to a different initial value, affecting the final PCR value. The firmware can't access locality 3, so can't perform an equivalent measurement, so can't fake the value.
This post serves as a report from my attendance to Kubecon and CloudNativeCon 2023 Europe that took place in
Amsterdam in April 2023. It was my second time physically attending this conference, the first one was in
Austin, Texas (USA) in 2017. I also attended once in a virtual fashion.
The content here is mostly generated for the sake of my own recollection and learnings, and is written from
the notes I took during the event.
The very first session was the opening keynote, which reunited the whole crowd to bootstrap the event and
share the excitement about the days ahead. Some astonishing numbers were announced: there were more than
10.000 people attending, and apparently it could confidently be said that it was the largest open source
technology conference taking place in Europe in recent times.
It was also communicated that the next couple iteration of the event will be run in China in September 2023
and Paris in March 2024.
More numbers, the CNCF was hosting about 159 projects, involving 1300 maintainers and about 200.000
contributors. The cloud-native community is ever-increasing, and there seems to be a strong trend in the
industry for cloud-native technology adoption and all-things related to PaaS and IaaS.
The event program had different tracks, and in each one there was an interesting mix of low-level and higher
level talks for a variety of audience. On many occasions I found that reading the talk title alone was not
enough to know in advance if a talk was a 101 kind of thing or for experienced engineers. But unlike in
previous editions, I didn t have the feeling that the purpose of the conference was to try selling me
anything. Obviously, speakers would make sure to mention, or highlight in a subtle way, the involvement of a
given company in a given solution or piece of the ecosystem. But it was non-invasive and fair enough for me.
On a different note, I found the breakout rooms to be often small. I think there were only a couple of rooms
that could accommodate more than 500 people, which is a fairly small allowance for 10k attendees. I realized
with frustration that the more interesting talks were immediately fully booked, with people waiting in line
some 45 minutes before the session time. Because of this, I missed a few important sessions that I ll
hopefully watch online later.
Finally, on a more technical side, I ve learned many things, that instead of grouping by session I ll group
by topic, given how some subjects were mentioned in several talks.
On gitops and CI/CD pipelines
Most of the mentions went to FluxCD and ArgoCD. At
that point there were no doubts that gitops was a mature approach and both flux and argoCD could do an
excellent job. ArgoCD seemed a bit more over-engineered to be a more general purpose CD pipeline, and flux
felt a bit more tailored for simpler gitops setups. I discovered that both have nice web user interfaces that
I wasn t previously familiar with.
However, in two different talks I got the impression that the initial setup of them was simple, but migrating
your current workflow to gitops could result in a bumpy ride. This is, the challenge is not deploying
flux/argo itself, but moving everything into a state that both humans and flux/argo can understand. I also
saw some curious mentions to the config drifts that can happen in some cases, even if the goal of gitops is
precisely for that to never happen. Such mentions were usually accompanied by some hints on how to operate
the situation by hand.
Worth mentioning, I missed any practical information about one of the key pieces to this whole gitops story:
building container images. Most of the showcased scenarios were using pre-built container images, so in that
sense they were simple. Building and pushing to an image registry is one of the two key points we would need
to solve in Toolforge Kubernetes if adopting gitops.
In general, even if gitops were already in our radar for
Toolforge Kubernetes,
I think it climbed a few steps in my priority list after the conference.
Another learning was this site: https://opengitops.dev/.
On etcd, performance and resource management
I attended a talk focused on etcd performance tuning that was very encouraging. They were basically talking
about the exactsameproblems we
have had in Toolforge Kubernetes, like api-server and etcd failure modes, and how sensitive etcd is to disk
latency, IO pressure and network throughput. Even though
Toolforge Kubernetes scale is small compared to other Kubernetes deployments out there, I found it very
interesting to see other s approaches to the same set of challenges.
I learned how most Kubernetes components and apps can overload the api-server. Because even the api-server
talks to itself. Simple things like kubectl may have a completely different impact on the API depending on
usage, for example when listing the whole list of objects (very expensive) vs a single object.
The conclusion was to try avoiding hitting the api-server with LIST calls, and use ResourceVersion which
avoids full-dumps from etcd (which, by the way, is the default when using bare kubectl get calls). I
already knew some of this, and for example the jobs-framework-emailer was already making use of this
ResourceVersion functionality.
There have been a lot of improvements in the performance side of Kubernetes in recent times, or more
specifically, in how resources are managed and used by the system. I saw a review of resource management from
the perspective of the container runtime and kubelet, and plans to support fancy things like topology-aware
scheduling decisions and dynamic resource claims (changing the pod resource claims without
re-defining/re-starting the pods).
On cluster management, bootstrapping and multi-tenancy
I attended a couple of talks that mentioned kubeadm, and one in particular was from the maintainers
themselves. This was of interest to me because as of today we use it for
Toolforge. They shared all
the latest developments and improvements, and the plans and roadmap for the future, with a special mention to
something they called kubeadm operator , apparently capable of auto-upgrading the cluster, auto-renewing
certificates and such.
I also saw a comparison between the different cluster bootstrappers, which to me confirmed that kubeadm was
the best, from the point of view of being a well established and well-known workflow, plus having a very
active contributor base. The kubeadm developers invited the audience to submit feature requests,
so I did.
The different talks confirmed that the basic unit for multi-tenancy in kubernetes is the namespace. Any
serious multi-tenant usage should leverage this. There were some ongoing conversations, in official sessions
and in the hallway, about the right tool to implement K8s-whitin-K8s, and vcluster
was mentioned enough times for me to be convinced it was the right candidate. This was despite of my impression
that multiclusters / multicloud are regarded as hard topics in the general community. I definitely would like to play
with it sometime down the road.
On networking
I attended a couple of basic sessions that served really well to understand how Kubernetes instrumented the
network to achieve its goal. The conference program had sessions to cover topics ranging from network
debugging recommendations, CNI implementations, to IPv6 support. Also, one of the keynote sessions had a
reference to how kube-proxy is not able to perform NAT for SIP connections, which is interesting because I
believe Netfilter Conntrack could do it if properly configured. One of the conclusions on the CNI front was
that Calico has a massive community adoption (in Netfilter mode), which is reassuring, especially considering
it is the one we use for Toolforge Kubernetes.
On jobs
I attended a couple of talks that were related to HPC/grid-like usages of Kubernetes. I was truly impressed
by some folks out there who were using Kubernetes Jobs on massive scales, such as to train machine learning
models and other fancy AI projects.
It is acknowledged in the community that the early implementation of things like Jobs and CronJobs had some
limitations that are now gone, or at least greatly improved. Some new functionalities have been added as
well. Indexed Jobs, for example, enables each Job to have a number (index) and process a chunk of a larger
batch of data based on that index. It would allow for full grid-like features like sequential (or again,
indexed) processing, coordination between Job and more graceful Job restarts. My first reaction was: Is that
something we would like to enable in Toolforge Jobs Framework?
On policy and security
A surprisingly good amount of sessions covered interesting topics related to policy and security. It was nice
to learn two realities:
kubernetes is capable of doing pretty much anything security-wise and create
greatly secured environments.
it does not by default. The defaults are not security-strict on purpose.
It kind of made sense to me: Kubernetes was used for a wide range of use cases, and developers didn t know
beforehand to which particular setup they should accommodate the default security levels.
One session in particular covered the most basic security features that should be enabled for any Kubernetes
system that would get exposed to random end users. In my opinion, the Toolforge Kubernetes setup was already
doing a good job in that regard. To my joy, some sessions referred to the Pod Security Admission mechanism,
which is one of the key security features we re about to adopt (when migrating away from
Pod Security Policy).
I also learned a bit more about Secret resources, their current implementation and how to leverage a
combo of CSI and RBAC for a more secure usage of external secrets.
Finally, one of the major takeaways from the conference was learning about kyverno and
kubeaudit. I was previously aware of the
OPA Gatekeeper. From the several demos I saw, it
was to me that kyverno should help us make Toolforge Kubernetes more sustainable by replacing all of our
custom admission controllers
with it. I already opened a ticket to track this idea, which I ll be
proposing to my team soon.
Final notes
In general, I believe I learned many things, and perhaps even more importantly I re-learned some stuff I had
forgotten because of lack of daily exposure. I m really happy that the cloud native way of thinking was
reinforced in me, which I still need because most of my muscle memory to approach systems architecture and
engineering is from the old pre-cloud days.
List of sessions I attended on the first day:
For over 15 years, I've hardly made any updates to my website, and it remains
low on my priority list. So I made a radical decision to replace it entirely
with my blog. The content of the website has been reduced to just two
additionalpages.
But nothing has been lost: nowadays, Wikipedia is a much better platform for
sharing knowledge than random websites. And it happens that they already cover
all that was on my website about
subaquatic diving in French.
They also offer a multitude of resources in electronics, including the topics that
were on my website:
LCD displays,
I C bus,
barcodes,
parallel ports,
serial ports, and
DCF77 reception.
Finally if you're in need of Debian QEMU images for various architectures, I
recommend the
Debian Quick Image Baker pre-baked images
page instead.
Posted on March 16, 2023
A few years ago a friend told me that her usual fabric shop was closing down and had a sale on all remaining stock.
While being sad for yet another brick and mortar shop that was going to be missed (at least it was because the owners were retiring, not because it wasn t sustainable anymore), of course I couldn t miss the opportunity.
So we drove a few hundred km, had some nice time with a friend that (because of said few hundred km) we rarely see, and spent a few hours looting the corps er helping the shop owner getting rid of stock before their retirement.
Among other things there was a cut of lightweight swiss embroidery cotton in blue which may or may not have been enthusiastically grabbed with plans of victorian underwear.
It was too nice to be buried under layers and layers of fabric (and I suspect that the embroidery wouldn t feel great directly on the skin under a corset), so the natural fit was something at the corset cover layer, and the fabric was enough for a combination garment of the kind often worn in the later Victorian age to prevent the accumulation of bulk at the waist.
It also has the nice advantage that in this time of corrupted morals it is perfectly suitable as outerwear as a nice summer dress.
Then life happened, the fabric remained in my stash for a long while, but finally this year I have a good late victorian block that I can adapt, and with spring coming it was a good time to start working on the summer wardrobe.
The block I ve used comes from The Cutters Practical Guide to the Cutting of Ladies Garments and is for a jacket, rather than a bodice, but the bodice block from the same book had a 4 part back, which was too much for this garment. I reduced the ease around the bust a bit, which I believe worked just fine.
The main pattern was easy enough to prepare, I just had to add skirt panels with a straight side towards the front and flaring out towards the back, and I did a quick mockup from an old sheet to check the fit (good) and the swish and volume of the skirt (just right at the first attempt!).
The mockup was also used to get an idea of a few possible necklines, and I opted for a relatively deep V, and a front opening with a partial placket down to halfway between the waist and the hips. I also opted for a self-fabric ruffle at the hem and armscyes.
The only design choice left was the pocket situation: I wanted to wear this garment both as underwear (where pockets aren t needed, and add unwanted bulk) and outerwear (where no pockets is not an option), and the fabric felt too thin to support the weight of the contents of a full pocket. So I decided to add slits into the seams, with just a modesty placket, and wear pockets under the dress as needed.
I decided to put the slits between the side and side back panels for two reasons: one is that this way the pockets can sit towards the back, where the fullness of the skirt is supposed to be, rather than under the flat front, and the other one is to keep the seams around the front panel clean, since they are the first ones to be changed when altering a garment for fit.
For the same reason, I didn t trim the excess allowance from that seam: it means that it is a bit more bulky, but the fabric is thin enought that it s not really noticeable, and it gives an additional cm for future alterations.
Then, as the garment was getting close to being finished I was measuring and storing some old cotton lace I had received as a gift, and there was a length of relatively small lace, and the finish on the neckline was pretty simple and called for embellishment, and who am I to deny embellishment to victorian inspired clothing?
First I had to finish attaching the ruffles, however, and this is when I cursed myself for not using the ruffler foot I have (it would have meant not having selvedges on all seams of the ruffle), and for pleating the ruffle rather than gathering it (I prefer the look of handsewn gathers, but here I m sewing everything by machine, and that s faster, right? (it probably wasn t)).
Also, this is where I started to get low on pins, and I had to use the ones from the vintage1 box I ve been keeping as decoration in the sewing room.
A few long sessions of pinning later, the ruffle was sewn and I could add the lace; I used white thread so that it would be hidden on the right side, but easily visible inside the garment in case I ll decide to remove or change it later.
A few buttons and buttonholes later, the garment was ready, and the only thing left was to edit the step-by-step pictures and publish the pattern: it s now available as #FreeSoftWear on my patterns website.
And Of course, I had to do a proper swish test of the finished dress with the ruffle, and I m happy to announce that it was fully passed.
Except, maybe I shouldn t carry heavy items in my pockets when doing it? Oh, well.
I have other plans for the same pattern, but they involve making some crochet lace, so I expect I can aim at making them wearable in summer 2024.
Now I just have to wait for the weather to be a bit warmer, and then I can start enjoing this one.
ok, even more vintage, since my usual pins come from a plastic box that has been probably bought in the 1980s.
I am old enough to remember when BPF meant the traditional Berkeley Packet Filter, and was confined to filtering network packets. It s grown into much, much, more as eBPF and getting familiar with it so that I can add it to the suite of tips and tricks I can call upon has been on my to-do list for a while. To this end I was lucky enough to attend a live walk through of bpftrace last year. bpftrace is a high level tool that allows the easy creation and execution of eBPF tracers under Linux.
Recently I ve been working on updating the RetroArch packages in Debian and as I was doing so I realised there was a need to update the quite outdated retroarch-assets package, which contains various icons and images used for the user interface. I wanted to try and re-generate as many of the artefacts as I could, to ensure the proper source was available. However it wasn t always clear which files were actually needed and which were either source or legacy. So I wanted to trace file opens by retroarch and see when it was failing to find files. Traditionally this is something I d have used strace for, but it seemed like a great opportunity to try out bpftrace.
It turns out bpftrace ships with an example, opensnoop.bt which provided details of hooking the open syscall entry + exit and providing details of all files opened on the system. I only wanted to track opens by the retroarch binary that failed, so I made a couple of modifications:
retro-failed-open-snoop.bt
#!/usr/bin/env bpftrace
/** retro-failed-open-snoop - snoop failed opens by RetroArch
** Based on:
* opensnoop Trace open() syscalls.
* For Linux, uses bpftrace and eBPF.
** Copyright 2018 Netflix, Inc.
* Licensed under the Apache License, Version 2.0 (the "License")** 08-Sep-2018 Brendan Gregg Created this.
*/
BEGIN
printf("Tracing open syscalls... Hit Ctrl-C to end.\n");printf("%-6s %-16s %3s %s\n", "PID", "COMM", "ERR", "PATH");
tracepoint:syscalls:sys_enter_open,
tracepoint:syscalls:sys_enter_openat
@filename[tid] = args->filename;
tracepoint:syscalls:sys_exit_open,
tracepoint:syscalls:sys_exit_openat
/@filename[tid]/
$ret= args->ret;$errno=$ret> 0 ? 0 : - $ret;if(($ret <= 0)&&(strncmp("retroarch", comm, 9)== 0))printf("%-6d %-16s %3d %s\n", pid, comm, $errno,
str(@filename[tid]));
delete(@filename[tid]);
END
clear(@filename);
I had to install bpftrace (apt install bpftrace) and then I ran bpftrace -o retro.log retro-failed-open-snoop.bt as root and fired up retroarch as a normal user.
bpftrace failed open log for retroarch
This was incredibly useful - the only theme image I was missing is disc.png from XMB Monochrome (which fails to have SVG source). I also discovered the runtime optional loading of GameMode. This is available in Debian so it was a simple matter to add libgamemode0 to the binary package Recommends.
So, a very basic example of using bpftrace, but a remarkably useful intro to it from my point of view!
This is a complex tale I will attempt to make simple(ish). I ve (re)learned more than I cared to about the details of pipes, signals, and certain system calls and the solution is still elusive.
For some time now, I have been using NNCP to back up my files. These backups are sent to my backup system, which effectively does this to process them (each ZFS send is piped to a shell script that winds up running this):
This processes tens of thousands of zfs sends per week. Recently, having written Filespooler, I switched to sending the backups using Filespooler over NNCP. Now fspl (the Filespooler executable) opens the file for each stream and then connects it to what amounts to this pipeline:
Actually, to be more precise, it spins up the bash part of it, reads a few bytes from it, and then connects it to the zfs receive.
And this works well almost always. In something like 1/1000 of the cases, it deadlocks, and I still don t know why. But I can talk about the journey of trying to figure it out (and maybe some of you will have some ideas).
Filespooler is written in Rust, and uses Rust s Command system. Effectively what happens is this:
The fspl process has a File handle, which after forking but before invoking bash, it dup2 s to stdin.
The connection between bash and zfs receive is a standard Unix pipe.
I cannot get the problem to duplicate when I run the entire thing under strace -f. So I am left trying to peek at it from the outside. What happens if I try to attach to each component with strace -p?
bash is blocking in wait4(), which is expected.
gpg is blocking in write().
If I attach to zstdcat with strace -p, then all of a sudden the deadlock is cleared and everything resumes and completes normally.
Attaching to zfs receive with strace -p causes no output at all from strace for a few seconds, then zfs just writes cannot receive incremental stream: incomplete stream and exits with error code 1.
So the plot thickens! Why would connecting to zstdcat and zfs receive cause them to actually change behavior? strace works by using the ptrace system call, and ptrace in a number of cases requires sending SIGSTOP to a process. In a complicated set of circumstances, a system call may return EINTR when a SIGSTOP is received, with the idea that the system call should be retried. I can t see, from either zstdcat or zfs, if this is happening, though.
So I thought, how about having Filespooler manually copy data from bash to zfs receive in a read/write loop instead of having them connected directly via a pipe? That is, there would be two pipes going there: one where Filespooler reads from the bash command, and one where it writes to zfs. If nothing else, I could instrument it with debugging.
And so I did, and I found that when it deadlocked, it was deadlocking on write but with no discernible pattern as to where or when. So I went back to directly connected.
In analyzing straces, I found a Rust bug which I reported in which it is failing to close the read end of a pipe in the parent post-fork. However, having implemented a workaround for this, it doesn t prevent the deadlock so this is orthogonal to the issue at hand.
Among the two strange things here are things returning to normal when I attach strace to zstdcat, and things crashing when I attach strace to zfs. I decided to investigate the latter.
It turns out that the ZFS code that is reading from stdin during zfs receive is in the kernel module, not userland. Here is the part that is triggering the imcomplete stream error:
int err = zfs_file_read(fp, (char *)buf + done,
len - done, &resid);
if (resid == len - done)
/*
* Note: ECKSUM or ZFS_ERR_STREAM_TRUNCATED indicates
* that the receive was interrupted and can
* potentially be resumed.
*/
err = SET_ERROR(ZFS_ERR_STREAM_TRUNCATED);
resid is an output parameter with the number of bytes remaining from a short read, so in this case, if the read produced zero bytes, then it sets that error. What s zfs_file_read then?
It boils down to a thin wrapper around kernel_read(). This winds up calling __kernel_read(), which calls read_iter on the pipe, which is pipe_read(). That s where I don t have the knowledge to get into the weeds right now.
So it seems likely to me that the problem has something to do with zfs receive. But, what, and why does it only not work in this one very specific situation, and only so rarely? And why does attaching strace to zstdcat make it all work again? I m indeed puzzled!
Update 2022-06-20: See the followup post which identifies this as likely a kernel bug and explains why this particular use of Filespooler made it easier to trigger.
Shell? Rust!
Not the first shell script I took and made a rust version of, but
probably my largest yet. This time I took my little tm (tmux
helper) tool which is (well, was) a
bit more than 600 lines of shell, and converted it to
Rust.
I got most of the functionality done now, only one major part is
missing.
What s tm?
tm started as a tiny shell script to make handling
tmux easier. The first commit in
git was in July 2013, but I started writing and using it in 2011. It
started out as a kind-of wrapper around ssh, opening tmux windows with
an ssh session on some other hosts. It quickly gained support to open
multiple ssh sessions in one window, telling tmux to synchronize input
(send input to all targets at once), which is great when you have a
set of machines that ought to get the same commands.
tm vs clusterssh / mussh
In spirit it is similar to clusterssh or mussh, allowing to run the
same command on many hosts at the same time. clusterssh sets out to
open new terminals (xterm) per host and gives you an input line, that
it sends everywhere. mussh appears to take your command and then send
it to all the hosts. Both have disadvantages in my opinion: clusterssh
opens lots of xterm windows, and you can not easily switch between
multiple sessions, mussh just seems to send things over ssh and be
done.
tm instead just creates a tmux session, telling it to ssh to the
targets, possibly setting the tmux option to send input to all panes.
And leaves all the rest of the handling to tmux. So you can
detach a session and reattach later easily,
use tmux great builtin support for copy/paste,
see all output, modify things even for one machine only,
zoom in to one machine that needs just ONE bit different (cssh can
do this too),
let colleagues also connect to your tmux session, when needed,
easily add more machines to the mix, if needed,
and all the other extra features tmux brings.
More tm
tm also supports just attaching to existing sessions as well as
killing sessions, mostly for lazyness (less to type than using tmux
directly).
At some point tm gained support for setting up sessions according to
some session file . It knows two formats now, one is simple and
mostly a list of hostnames to open synchronized sessions for. This may
contain LIST commands, which let tm execute that command, expected
output is list of hostnames (or more LIST commands) for the session.
That, combined with the replacement part, lets us have one config file
that opens a set of VMs based on tags our
Ganeti runs, based on tags. It is simply a LIST
command asking for VMs tagged with the replacement arg and up. Very
handy. Or also all VMs on host X .
The second format is basically free form tmux commands . Mostly
commandline tmux call, just drop the tmux in front collection.
Both of them supporting a crude variable replacement.
Conversion to Rust
Some while ago I started playing with Rust and it somehow clicked , I
do like it. My local git tells me, that I tried starting off with
go in 2017, but that appearently did not work out.
Fun, everywhere I can read says that Rust ought to be harder to learn.
So by now I have most of the functionality implemented in the Rust
version, even if I am sure that the code isn t a good Rust example.
I m learning, after all, and already have adjusted big parts of it,
multiple times, whenever I learn (and understand) something more - and
am also sure that this will happen again
Compatibility with old tm
It turns out that my goal of staying compatible with the behaviour of
the old shell script does make some things rather complicated. For
example, the LIST commands in session config files - in shell I just
execute them commands, and shell deals with variable/parameter
expansion, I just set IFS to newline only and read in what I get
back. Simple. Because shell is doing a lot of things for me.
Now, in Rust, it is a different thing at all:
Properly splitting the line into shell words, taking care of quoting
(can t simply take whitespace) (there is shlex)
Expanding specials like ~ and $HOME (there is
home_dir).
Supporting environment variables in general, tm has some that adjust
behaviour of it. Which shell can use globally. Used
lazy_static for a
similar effect - they aren t going to change at runtime ever,
anyways.
Properly supporting the commandline arguments also turned out to be a
bit more work. Rust appearently has multiple crates supporting this, I
settled on clap, but as tm
supports getopts -style as well as free-form arguments (subcommands
in clap), it takes a bit to get that interpreted right.
Speed
Most of the time entirely unimportant in the tool that tm is (open a
tmux with one to some ssh connections to some places is not exactly
hard or time consuming), there are situations, where one can notice
that it s calling out to tmux over and over again, for every single
bit to do, and that just takes time: Configurations that open sessions
to 20 and more hosts at the same time especially lag in setup time.
(My largest setup goes to 443 panes in one window). The compiled Rust
version is so much faster there, it s just great. Nice side effect,
that is. And yes, in the end it is also only driving tmux, still, it
takes less than half the time to do so.
Code, Fun parts
As this is still me learning to write Rust, I am sure the code has
lots to improve. Some of which I will sure find on my own, but if you
have time, I love PRs (or just mails with hints).
Github
Also the first time I used Github Actions to see how it goes. Letting
it build, test, run
clippy and also run a code
coverage tool (Yay, more than
50% covered ) on it. Unsure my tests are good, I am not used to
writing tests for code, but hey, coverage!
Up next
I do have to implement the last missing feature, which is reading the
other config file format. A little scared, as that means somehow
translating those lines into correct calls within the
tmux_interface
I am using, not sure that is easy. I could be bad and just shell
out to tmux on it all the time, but somehow I don t like the thought
of doing that. Maybe (ab)using the control mode, but then, why would I
use tmux_interface, so trying to handle it with that first.
Afterwards I want to gain a new command, to save existing sessions and
be able to recreate them easily. Shouldn t be too hard, tmux has a way
to get at that info, somewhere.
If your workstation is using full-disk encryption, you may want to
jump directly to your desktop environment after entering the
passphrase to decrypt the disk. Many display managers like GDM and
LightDM have an autologin feature. However, only GDM can run
Xorg with standard user privileges.
Here is an alternative using startx and a systemd service:
The unit starts after systemd-user-sessions.service, which enables
user logins after boot by removing the /run/nologin file.
With User=bernat, the unit is started with the identity of the
specified user. This implies that Xorg does not run with elevated
privileges.
With PAMName=login, the executed process is registered as a PAM
session for the login service, which includes pam_systemd.
This module registers the session to the systemd login manager.
To be effective, we also need to allocate a TTY with
TTYPath=/dev/tty8. When the TTY is active, the user is granted
additional access to local devices notably display, sound, keyboard,
mouse. These additional rights are needed to get Xorg working
rootless.1 The TERM environment variable is unset because
it would be set to linux by systemd as a result of attaching the
standard input to the TTY. Moreover, we inform pam_systemd we want
an X11 session with Environment=XDG_SESSION_TYPE=x11. Otherwise,
logind considers the session idle unless it receives input on
the TTY. Software relying on the idle hint from logind would be
ineffective.2
The UtmpIdentifier=tty8 and UtmpMode=user directives are just
a nice addition to register the session in /var/run/utmp.
The last step is to execute Xorg through startx. For logind to
allow Xorg to take control of the local devices, chvt 8 switches
to the allocated TTY.3StandardOutput=journal, combined
with the -verbose 3 -logfile /dev/null flags for Xorg, puts the
logs from the X server into the journal instead of using a file.
While equal to the default value, the Restart=no directive
highlights we do not want this unit to be restarted. This ensures
the loginless session is only available on boot. By default,
startx runs xinitrc. If you want to run Kodi instead, add
/usr/bin/kodi-standalone between startx and --.
Drop this unit in /etc/systemd/system/x11-autologin.service and
enable it with systemctl enable x11-autologin.service. Xorg is now
running rootless and logging into the journal. After using it for a
few months, I didn t notice any regression compared to LightDM with
autologin.
For more information on how logind provides access to
devices, see this blog post. The method names do not match the
current implementation, but the concepts are still correct. Xorg
takes control of the session when the TTY is active.
Xorg could change the type of the session itself after
taking control of it, but it does not.
There is some code in Xorg to do that, but it is
executed too late and fails with: xf86OpenConsole: VT_ACTIVATE
failed: Operation not permitted.