Hi all,
After merging the kvm-x86 tree, today's linux-next build (x86_64
allmodconfig) failed like this:
arch/x86/kvm/../../../virt/kvm/guest_memfd.c: In function 'kvm_gmem_get_file':
arch/x86/kvm/../../../virt/kvm/guest_memfd.c:280:35: error: passing argument 1 of 'get_file_rcu' from incompatible pointer type [-Werror=incompatible-pointer-types]
280 | if (file && !get_file_rcu(file))
| ^~~~
| |
| struct file *
In file included from include/linux/backing-dev.h:13,
from arch/x86/kvm/../../../virt/kvm/guest_memfd.c:2:
include/linux/fs.h:1046:47: note: expected 'struct file **' but argument is of type 'struct file *'
1046 | struct file *get_file_rcu(struct file __rcu **f);
| ~~~~~~~~~~~~~~~~~~~~^
Caused by commit
fcbef1e5e5d2 ("KVM: Add KVM_CREATE_GUEST_MEMFD ioctl() for guest-specific backing memory")
interacting with commit
0ede61d8589c ("file: convert to SLAB_TYPESAFE_BY_RCU")
from the vfs-brauner tree.
I have applied the following merg resolution patch:
From: Stephen Rothwell <[email protected]>
Date: Mon, 30 Oct 2023 13:35:38 +1100
Subject: [PATCH] fix up for "KVM: Add KVM_CREATE_GUEST_MEMFD ioctl() for
guest-specific backing memory"
interacting with "file: convert to SLAB_TYPESAFE_BY_RCU"
Signed-off-by: Stephen Rothwell <[email protected]>
---
virt/kvm/guest_memfd.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index 94bc478c26f3..7f62abe3df9e 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -276,9 +276,7 @@ static struct file *kvm_gmem_get_file(struct kvm_memory_slot *slot)
rcu_read_lock();
- file = rcu_dereference(slot->gmem.file);
- if (file && !get_file_rcu(file))
- file = NULL;
+ file = get_file_rcu(&slot->gmem.file);
rcu_read_unlock();
--
2.40.1
--
Cheers,
Stephen Rothwell
On Mon, Oct 30, 2023 at 01:48:06PM +1100, Stephen Rothwell wrote:
> Hi all,
>
> After merging the kvm-x86 tree, today's linux-next build (x86_64
> allmodconfig) failed like this:
>
> arch/x86/kvm/../../../virt/kvm/guest_memfd.c: In function 'kvm_gmem_get_file':
> arch/x86/kvm/../../../virt/kvm/guest_memfd.c:280:35: error: passing argument 1 of 'get_file_rcu' from incompatible pointer type [-Werror=incompatible-pointer-types]
> 280 | if (file && !get_file_rcu(file))
> | ^~~~
> | |
> | struct file *
> In file included from include/linux/backing-dev.h:13,
> from arch/x86/kvm/../../../virt/kvm/guest_memfd.c:2:
> include/linux/fs.h:1046:47: note: expected 'struct file **' but argument is of type 'struct file *'
> 1046 | struct file *get_file_rcu(struct file __rcu **f);
> | ~~~~~~~~~~~~~~~~~~~~^
>
> Caused by commit
>
> fcbef1e5e5d2 ("KVM: Add KVM_CREATE_GUEST_MEMFD ioctl() for guest-specific backing memory")
>
> interacting with commit
>
> 0ede61d8589c ("file: convert to SLAB_TYPESAFE_BY_RCU")
>
> from the vfs-brauner tree.
>
> I have applied the following merg resolution patch:
>
> From: Stephen Rothwell <[email protected]>
> Date: Mon, 30 Oct 2023 13:35:38 +1100
> Subject: [PATCH] fix up for "KVM: Add KVM_CREATE_GUEST_MEMFD ioctl() for
> guest-specific backing memory"
>
> interacting with "file: convert to SLAB_TYPESAFE_BY_RCU"
>
> Signed-off-by: Stephen Rothwell <[email protected]>
> ---
> virt/kvm/guest_memfd.c | 4 +---
> 1 file changed, 1 insertion(+), 3 deletions(-)
>
> diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
> index 94bc478c26f3..7f62abe3df9e 100644
> --- a/virt/kvm/guest_memfd.c
> +++ b/virt/kvm/guest_memfd.c
> @@ -276,9 +276,7 @@ static struct file *kvm_gmem_get_file(struct kvm_memory_slot *slot)
>
> rcu_read_lock();
>
> - file = rcu_dereference(slot->gmem.file);
> - if (file && !get_file_rcu(file))
> - file = NULL;
> + file = get_file_rcu(&slot->gmem.file);
>
> rcu_read_unlock();
Stephen, thanks for the suggested fixup.
Afaict, the guest_memfds pin the kvm instance. If a guest_memfd is
closed and last fput() is called the file pointer remains stashed in all
relevant gmem->file slots until guest_memfd->release::kvm_gmem_release()
is called. And kvm_gmem_release() sets all relevant gmem->file instances
to NULL via rcu_assign_pointer().
So afaict, the gmem->file pointer isn't part of the reference counting
but rather it just caches the result of the reference counting. And it's
then cleared when that reference goes down to zero.
Basically, I think this is akin to commit 61d4fb0b349e ("file, i915: fix
file reference for mmap_singleton()") which is in -next and the
discussion we had in
https://lore.kernel.org/r/20231025-formfrage-watscheln-84526cd3bd7d@brauner
So that means we can't to loop here which is what get_file_rcu() would
do. Otherwise you might end up spinning. Because last close of
guest_memfd fput() puts the last reference. Now all concurrent
gmem->file kvm_gmem_get_file() callers will see f_count at zero. And it
might well take a while until the kernel calls
guest_memfd->release::kvm_gmem_release() and NULLs the pointer. So
get_file_rcu() would retry and loop because it thinks that the pointer
is part of the reference counting.
So iiuc you want get_file_active() here which also takes the
rcu_read_lock() for you.
@Paolo and @Sean, does that make sense and is the series for v6.7 or
just already in -next for v6.8?
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index 94bc478c26f3..a4c194b0b22c 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -272,17 +272,7 @@ static int kvm_gmem_release(struct inode *inode, struct file *file)
static struct file *kvm_gmem_get_file(struct kvm_memory_slot *slot)
{
- struct file *file;
-
- rcu_read_lock();
-
- file = rcu_dereference(slot->gmem.file);
- if (file && !get_file_rcu(file))
- file = NULL;
-
- rcu_read_unlock();
-
- return file;
+ return get_file_active(&slot->gmem.file);
}
static struct file_operations kvm_gmem_fops = {
On 10/30/23 11:05, Christian Brauner wrote:
>
> @Paolo and @Sean, does that make sense and is the series for v6.7 or
> just already in -next for v6.8?
It's for 6.8. Thanks for the fixup!
Paolo
> diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
> index 94bc478c26f3..a4c194b0b22c 100644
> --- a/virt/kvm/guest_memfd.c
> +++ b/virt/kvm/guest_memfd.c
> @@ -272,17 +272,7 @@ static int kvm_gmem_release(struct inode *inode, struct file *file)
>
> static struct file *kvm_gmem_get_file(struct kvm_memory_slot *slot)
> {
> - struct file *file;
> -
> - rcu_read_lock();
> -
> - file = rcu_dereference(slot->gmem.file);
> - if (file && !get_file_rcu(file))
> - file = NULL;
> -
> - rcu_read_unlock();
> -
> - return file;
> + return get_file_active(&slot->gmem.file);
> }
>
> static struct file_operations kvm_gmem_fops = {
>
Hi Paolo,
On Mon, 30 Oct 2023 12:27:07 +0100 Paolo Bonzini <[email protected]> wrote:
>
> On 10/30/23 11:05, Christian Brauner wrote:
> >
> > @Paolo and @Sean, does that make sense and is the series for v6.7 or
> > just already in -next for v6.8?
>
> It's for 6.8.
Then it should not be in linux-next yet. :-(
--
Cheers,
Stephen Rothwell
On Tue, Oct 31, 2023, Stephen Rothwell wrote:
> Hi Paolo,
>
> On Mon, 30 Oct 2023 12:27:07 +0100 Paolo Bonzini <[email protected]> wrote:
> >
> > On 10/30/23 11:05, Christian Brauner wrote:
> > >
> > > @Paolo and @Sean, does that make sense and is the series for v6.7 or
> > > just already in -next for v6.8?
> >
> > It's for 6.8.
>
> Then it should not be in linux-next yet. :-(
That's my bad, I wanted to get the guest_memfd code exposure asap and jumped the
gun. I'll yank the branch out kvm-x86/next.
I assume -rc1 is when the floodgates "officially" open again?
Hi Sean,
On Mon, 30 Oct 2023 14:05:12 -0700 Sean Christopherson <[email protected]> wrote:
>
> That's my bad, I wanted to get the guest_memfd code exposure asap and jumped the
> gun. I'll yank the branch out kvm-x86/next.
Thanks.
> I assume -rc1 is when the floodgates "officially" open again?
Yes, indeed.
--
Cheers,
Stephen Rothwell
On Mon, Oct 30, 2023 at 10:10 PM Stephen Rothwell <[email protected]> wrote:
>
> Hi Sean,
>
> On Mon, 30 Oct 2023 14:05:12 -0700 Sean Christopherson <[email protected]> wrote:
> >
> > That's my bad, I wanted to get the guest_memfd code exposure asap and jumped the
> > gun. I'll yank the branch out kvm-x86/next.
>
> Thanks.
In all fairness, it was only recently pushed back from 6.7 to 6.8 so
it probably would have made sense to include it _even earlier_. But I
agree that at this point it's better if we wait for 6.7-rc1 before it
makes it back into linux-next. At that point I'll include the conflict
resolution myself.
Paolo