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 <sfr@xxxxxxxxxxxxxxxx> > 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 <sfr@xxxxxxxxxxxxxxxx> > --- > 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 = {