[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CA+CK2bBxVNRkJ-8Qv1AzfHEwpxnc4fSxdzKCL_7ku0TMd6Rjow@mail.gmail.com>
Date: Mon, 17 Nov 2025 22:54:29 -0500
From: Pasha Tatashin <pasha.tatashin@...een.com>
To: Mike Rapoport <rppt@...nel.org>
Cc: pratyush@...nel.org, jasonmiu@...gle.com, graf@...zon.com,
dmatlack@...gle.com, rientjes@...gle.com, corbet@....net,
rdunlap@...radead.org, ilpo.jarvinen@...ux.intel.com, kanie@...ux.alibaba.com,
ojeda@...nel.org, aliceryhl@...gle.com, masahiroy@...nel.org,
akpm@...ux-foundation.org, tj@...nel.org, yoann.congal@...le.fr,
mmaurer@...gle.com, roman.gushchin@...ux.dev, chenridong@...wei.com,
axboe@...nel.dk, mark.rutland@....com, jannh@...gle.com,
vincent.guittot@...aro.org, hannes@...xchg.org, dan.j.williams@...el.com,
david@...hat.com, joel.granados@...nel.org, rostedt@...dmis.org,
anna.schumaker@...cle.com, song@...nel.org, linux@...ssschuh.net,
linux-kernel@...r.kernel.org, linux-doc@...r.kernel.org, linux-mm@...ck.org,
gregkh@...uxfoundation.org, tglx@...utronix.de, mingo@...hat.com,
bp@...en8.de, dave.hansen@...ux.intel.com, x86@...nel.org, hpa@...or.com,
rafael@...nel.org, dakr@...nel.org, bartosz.golaszewski@...aro.org,
cw00.choi@...sung.com, myungjoo.ham@...sung.com, yesanishhere@...il.com,
Jonathan.Cameron@...wei.com, quic_zijuhu@...cinc.com,
aleksander.lobakin@...el.com, ira.weiny@...el.com,
andriy.shevchenko@...ux.intel.com, leon@...nel.org, lukas@...ner.de,
bhelgaas@...gle.com, wagi@...nel.org, djeffery@...hat.com,
stuart.w.hayes@...il.com, ptyadav@...zon.de, lennart@...ttering.net,
brauner@...nel.org, linux-api@...r.kernel.org, linux-fsdevel@...r.kernel.org,
saeedm@...dia.com, ajayachandra@...dia.com, jgg@...dia.com, parav@...dia.com,
leonro@...dia.com, witu@...dia.com, hughd@...gle.com, skhawaja@...gle.com,
chrisl@...nel.org
Subject: Re: [PATCH v6 08/20] liveupdate: luo_flb: Introduce
File-Lifecycle-Bound global state
>
> The concept makes sense to me, but it's hard to review the implementation
> without an actual user.
There are three users: we will have HugeTLB support that is going to
be posted as RFC in a few weeks. Also, in two weeks we are going to
have an updated VFIO and IOMMU series posted both using FLBs. In the
mean time, this series provides an FLB in-kernel test that verifies
that multiple FLBs can be attached to File-Handlers, and the basic
interfaces are working.
> > +struct liveupdate_flb {
> > + const struct liveupdate_flb_ops *ops;
> > + const char compatible[LIVEUPDATE_FLB_COMPAT_LENGTH];
> > + struct list_head list;
> > + void *internal;
>
> Can't list be a part of internal?
Yes, I moved it inside internal, and also, I removed
liveupdate_init_flb function (do that automatically now), and use the
__private as you suggested earlier, and also removed the kmalloc() for
the internal data, so FLBs can be safely used early in boot.
> And don't we usually call this .private rather than .internal?
Renamed.
>
> > };
> >
> > #ifdef CONFIG_LIVEUPDATE
> > @@ -111,6 +187,17 @@ int liveupdate_get_file_incoming(struct liveupdate_session *s, u64 token,
> > int liveupdate_get_token_outgoing(struct liveupdate_session *s,
> > struct file *file, u64 *tokenp);
> >
> > +/* Before using FLB for the first time it should be initialized */
> > +int liveupdate_init_flb(struct liveupdate_flb *flb);
> > +
> > +int liveupdate_register_flb(struct liveupdate_file_handler *h,
> > + struct liveupdate_flb *flb);
>
> While these are obvious ...
>
> > +
> > +int liveupdate_flb_incoming_locked(struct liveupdate_flb *flb, void **objp);
> > +void liveupdate_flb_incoming_unlock(struct liveupdate_flb *flb, void *obj);
> > +int liveupdate_flb_outgoing_locked(struct liveupdate_flb *flb, void **objp);
> > +void liveupdate_flb_outgoing_unlock(struct liveupdate_flb *flb, void *obj);
> > +
>
> ... it's not very clear what these APIs are for and how they are going to be
> used.
Global resource that is accessible either while a file is getting
preserved or anytime during boot.
>
> > #else /* CONFIG_LIVEUPDATE */
>
> ...
>
> > +int liveupdate_register_flb(struct liveupdate_file_handler *h,
> > + struct liveupdate_flb *flb)
> > +{
> > + struct luo_flb_internal *internal = flb->internal;
> > + struct luo_flb_link *link __free(kfree) = NULL;
> > + static DEFINE_MUTEX(register_flb_lock);
> > + struct liveupdate_flb *gflb;
> > + struct luo_flb_link *iter;
> > +
> > + if (!liveupdate_enabled())
> > + return -EOPNOTSUPP;
> > +
> > + if (WARN_ON(!h || !flb || !internal))
> > + return -EINVAL;
> > +
> > + if (WARN_ON(!flb->ops->preserve || !flb->ops->unpreserve ||
> > + !flb->ops->retrieve || !flb->ops->finish)) {
> > + return -EINVAL;
> > + }
> > +
> > + /*
> > + * Once session/files have been deserialized, FLBs cannot be registered,
> > + * it is too late. Deserialization uses file handlers, and FLB registers
> > + * to file handlers.
> > + */
> > + if (WARN_ON(luo_session_is_deserialized()))
> > + return -EBUSY;
> > +
> > + /*
> > + * File handler must already be registered, as it is initializes the
> > + * flb_list
> > + */
> > + if (WARN_ON(list_empty(&h->list)))
> > + return -EINVAL;
> > +
> > + link = kzalloc(sizeof(*link), GFP_KERNEL);
> > + if (!link)
> > + return -ENOMEM;
> > +
> > + guard(mutex)(®ister_flb_lock);
> > +
> > + /* Check that this FLB is not already linked to this file handler */
> > + list_for_each_entry(iter, &h->flb_list, list) {
> > + if (iter->flb == flb)
> > + return -EEXIST;
> > + }
> > +
> > + /* Is this FLB linked to global list ? */
>
> Maybe:
>
> /*
> * If this FLB is not linked to global list it's first time the FLB
> * is registered
> */
Done
> > +/**
> > + * liveupdate_flb_incoming_unlock - Unlock an incoming FLB object.
> > + * @flb: The FLB definition.
> > + * @obj: The object that was returned by the _locked call (used for validation).
> > + *
> > + * Releases the internal lock acquired by liveupdate_flb_incoming_locked().
> > + */
> > +void liveupdate_flb_incoming_unlock(struct liveupdate_flb *flb, void *obj)
> > +{
> > + struct luo_flb_internal *internal = flb->internal;
> > +
> > + lockdep_assert_held(&internal->incoming.lock);
> > + internal->incoming.obj = obj;
>
> The comment says obj is for validation and here it's assigned to flb.
> Something is off here :)
Thank you for catching stale comment, fixed.
> > + mutex_unlock(&internal->incoming.lock);
> > +}
> > +
> > +/**
> > + * liveupdate_flb_outgoing_locked - Lock and retrieve the outgoing FLB object.
> > + * @flb: The FLB definition.
> > + * @objp: Output parameter; will be populated with the live shared object.
> > + *
> > + * Acquires the FLB's internal lock and returns a pointer to its shared live
> > + * object for the outgoing (pre-reboot) path.
> > + *
> > + * This function assumes the object has already been created by the FLB's
> > + * .preserve() callback, which is triggered when the first dependent file
> > + * is preserved.
> > + *
> > + * The caller MUST call liveupdate_flb_outgoing_unlock() to release the lock.
> > + *
> > + * Return: 0 on success, or a negative errno on failure.
> > + */
> > +int liveupdate_flb_outgoing_locked(struct liveupdate_flb *flb, void **objp)
> > +{
> > + struct luo_flb_internal *internal = flb->internal;
> > +
> > + if (!liveupdate_enabled())
> > + return -EOPNOTSUPP;
> > +
> > + if (WARN_ON(!internal))
> > + return -EINVAL;
> > +
> > + mutex_lock(&internal->outgoing.lock);
> > +
> > + /* The object must exist if any file is being preserved */
> > + if (WARN_ON_ONCE(!internal->outgoing.obj)) {
> > + mutex_unlock(&internal->outgoing.lock);
> > + return -ENOENT;
> > + }
>
> _incoming_locked() and outgoing_locked() are nearly identical, it seems we
> can have the common part in a
> static liveupdate_flb_locked(struct luo_flb_state *state).
>
> liveupdate_flb_incoming_locked() will be oneline wrapper and
> liveupdate_flb_outgoing_locked() will have this WARN_ON if obj is NULL.
Done
Powered by blists - more mailing lists