From: Zhao Liu <zhao1.liu@intel.com>
To: Paolo Bonzini <pbonzini@redhat.com>
Cc: qemu-devel@nongnu.org, qemu-rust@nongnu.org,
Dapeng Mi <dapeng1.mi@intel.com>
Subject: Re: [PATCH 2/9] rust/vmstate: Support varray's num field wrapped in BqlCell
Date: Wed, 16 Apr 2025 17:43:32 +0800 [thread overview]
Message-ID: <Z/97xG5VONqmlK+7@intel.com> (raw)
In-Reply-To: <c44eebb9-1252-447e-9262-e2946f90f01c@redhat.com>
On Tue, Apr 15, 2025 at 12:54:51PM +0200, Paolo Bonzini wrote:
> Date: Tue, 15 Apr 2025 12:54:51 +0200
> From: Paolo Bonzini <pbonzini@redhat.com>
> Subject: Re: [PATCH 2/9] rust/vmstate: Support varray's num field wrapped
> in BqlCell
>
> On 4/14/25 16:49, Zhao Liu wrote:
> > Currently, if the `num` field of a varray is not a numeric type, such as
> > being placed in a wrapper, the array variant of assert_field_type will
> > fail the check.
> >
> > HPET currently wraps num_timers in BqlCell<>. Although BqlCell<> is not
> > necessary from strictly speaking, it makes sense for vmstate to respect
> > BqlCell.
>
> Dropping BqlCell<> from num_timers is indeed possible.
I can move the num_timers adjustment from realize() into init().
> But I agree that getting BqlCell<> varrays to work is a good thing anyway;
While num_timers can get out of BqlCell<>, num_timers_save is still
needed to stay in BqlCell<>, since I understand pre_save - as a callback
of the vmstate - still needs the bql protection.
So this patch is still necessary to support migration for HPET.
> then you can separately decide whether to drop BqlCell<> from num_timers.
Yes. In the next version, I can drop BqlCell<> and adjust the C version
as well. But then I can't update the document at the same time, because
the document needs to list the synchronized commit ID. I can update the
document after the HPET migration is able to be merged.
> > The failure of assert_field_type is because it cannot convert BqlCell<T>
> > into usize for use as the index.
> >
> > Therefore, first, implement `From` trait for common numeric types on
> > BqlCell<>. Then, abstract the wrapper and non-wrapper cases uniformly
> > into a `IntoUsize` trait and make assert_field_type to get usize type
> > index via `IntoUsize` trait.
> >
> > Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
> > ---
> > rust/qemu-api/src/assertions.rs | 30 +++++++++++++++++++++++++++++-
> > rust/qemu-api/src/cell.rs | 23 +++++++++++++++++++++++
> > 2 files changed, 52 insertions(+), 1 deletion(-)
>
> I think you can drop the "num=" case of assert_field_type!, and use
> something like this macro:
>
> /// Drop everything up to the colon, with the intention that
> /// `if_present!` is called inside an optional macro substitution
> /// (such as `$(... $arg ...)?` or `$(... $arg ...)*`). This allows
> /// expanding `$result` depending on the presence of an argument,
> /// even if the argument itself is not included in `$result`.
> ///
> /// # Examples
> ///
> /// ```
> /// # use qemu_api::if_present;
> /// macro_rules! is_present {
I understand this is_present could have another name to avoid confusion
with our real is_present macro.
> /// ($($cond:expr)?) => {
> /// loop {
> /// $(if_present!([$cond]: break true;);)?
> /// #[allow(unreachable_code)]
> /// break false;
> /// }
> /// }
> /// }
> ///
> /// assert!(!is_present!());
> /// assert!(is_present!("abc"));
> /// ```
> #[macro_export]
> macro_rules! if_present {
> ([$($cond:tt)*]: $($result:tt)*) => { $($result)* };
> }
>
> to expand the array part of the access:
>
> assert_field_type!(...
> $($crate::if_present!([$num]: [0]))?;
This example remind me that I introduced a bug into array part:
let index: usize = v.$num.try_into().unwrap();
types_must_be_equal::<_, &$ti>(&v.$i[index]);
In the current code, actually it accesses v[num], but when num
stores the length of the whole array, it will cause index out of bounds.
So for current code, at least it should access `v.i[num - 1]`:
let index: usize = v.$num.try_into().unwrap() - 1; // access the last element.
types_must_be_equal::<_, &$ti>(&v.$i[index]);
> );
>
> With this change, assert_field_type! is nicer and at least the trait you're
> introducing in assertions.rs goes away...
Yes! Great idea.
Then with your help, we could integrate the array part like:
#[macro_export]
macro_rules! if_present {
([$($cond:tt)*]: $($result:tt)*) => { $($result)* };
}
...
#[macro_export]
macro_rules! assert_field_type {
($t:ty, $i:tt, $ti:ty $(, $num:ident)?) => {
const _: () = {
#[allow(unused)]
fn assert_field_type(v: $t) {
fn types_must_be_equal<T, U>(_: T)
where
T: $crate::assertions::EqType<Itself = U>,
{
}
let access = v.$i$($crate::if_present!([$num]: [v.$num - 1])])?;
types_must_be_equal::<_, $ti>(access);
}
};
};
}
> > +// Orphan rules don't like something like `impl<T> From<BqlCell<T>> for T`.
> > +// It's enough to just implement Into for common types.
> > +macro_rules! impl_into_inner {
> > + ($type:ty) => {
> > + impl From<BqlCell<$type>> for $type {
> > + fn from(c: BqlCell<$type>) -> $type {
> > + c.get()
> > + }
> > + }
> > + };
> > +}
>
> ... and it's not clear to me whether this is needed with the change above?
> Would impl_vmstate_transparent!'s definition of VARRAY_FLAG be enough?
If I change the array part like (the change is needed because: cannot
subtract `{integer}` from `BqlCell<u8>`):
- let access = v.$i$([$crate::if_present!([$num]: v.$num) - 1])?;
+ let access = v.$i$([$crate::if_present!([$num]: v.$num).into() - 1])?;
Then there'll be an error:
85 | macro_rules! assert_field_type {
| ------------------------------ in this expansion of `$crate::assert_field_type!` (#2)
...
96 | let access = v.$i$([$crate::if_present!([$num]: v.$num).into() - 1])?;
| ^^^^ cannot infer type
This is because I want to also check whether "num" would cause index out
of bounds. If we just check the [0] element, then everything is OK...
> If not, I *think* you can do a blanket implementation of Into<T> for
> BqlCell<T>. Maybe that's nicer, you can decide.
I tired this way, but there's 2 difficulities:
* Into<T> for BqlCell<T> will violate coherence rules:
error[E0119]: conflicting implementations of trait `Into<_>` for type `cell::BqlCell<_>`
--> qemu-api/src/cell.rs:312:1
|
312 | impl<T> Into<T> for BqlCell<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<T, U> Into<U> for T
where U: From<T>;
* As index, we need to convert BqlCell<T> into T and then convert T
into usize. :-(
Do you think there is a better way to check array[num -1]? (array's
len() method also returns usize).
Or do you think whether it's necessary to check array[num -1]?
(referring to C version, for example, VMSTATE_STRUCT_VARRAY_UINT8, it
doesn't check the array's out of bounds case.)
Thanks,
Zhao
next prev parent reply other threads:[~2025-04-16 9:22 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-14 14:49 [PATCH 0/9] rust/hpet: Initial support for migration Zhao Liu
2025-04-14 14:49 ` [PATCH 1/9] rust/vmstate: Support field_exists check in vmstate_struct macro Zhao Liu
2025-04-16 14:54 ` Paolo Bonzini
2025-04-14 14:49 ` [PATCH 2/9] rust/vmstate: Support varray's num field wrapped in BqlCell Zhao Liu
2025-04-15 10:54 ` Paolo Bonzini
2025-04-16 9:43 ` Zhao Liu [this message]
2025-04-16 12:34 ` Zhao Liu
2025-04-16 14:24 ` Paolo Bonzini
2025-05-16 8:25 ` Zhao Liu
2025-04-14 14:49 ` [PATCH 3/9] rust/vmstate_test: Test varray with " Zhao Liu
2025-04-14 14:49 ` [PATCH 4/9] rust/vmstate_test: Fix typo in test_vmstate_macro_array_of_pointer_wrapped() Zhao Liu
2025-04-14 14:49 ` [PATCH 5/9] rust/timer: Define NANOSECONDS_PER_SECOND binding as u64 Zhao Liu
2025-04-14 14:49 ` [PATCH 6/9] rust/hpet: convert num_timers to u8 type Zhao Liu
2025-04-14 14:49 ` [PATCH 7/9] rust/hpet: convert HPETTimer index " Zhao Liu
2025-04-14 14:49 ` [PATCH 8/9] rust/hpet: Support migration Zhao Liu
2025-04-15 12:01 ` Zhao Liu
2025-04-15 14:21 ` Paolo Bonzini
2025-04-15 17:43 ` Paolo Bonzini
2025-04-16 10:20 ` Zhao Liu
2025-04-16 14:40 ` Paolo Bonzini
2025-04-16 10:33 ` Zhao Liu
2025-04-14 14:49 ` [PATCH 9/9] rust/hpet: Fix a clippy error Zhao Liu
2025-04-15 10:24 ` [PATCH 0/9] rust/hpet: Initial support for migration Paolo Bonzini
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Z/97xG5VONqmlK+7@intel.com \
--to=zhao1.liu@intel.com \
--cc=dapeng1.mi@intel.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-rust@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.