[packages/kernel/LINUX_6_12] Up to 6.12.69; update aufs patch

arekm arekm at pld-linux.org
Sun Feb 8 14:10:10 CET 2026


commit 9e85a475bb6ea6ba1c99fe66ccba217af82aeca7
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date:   Sun Feb 8 14:09:52 2026 +0100

    Up to 6.12.69; update aufs patch

 kernel-aufs.patch | 1526 ++++++++++++++++++++++-------------------------------
 kernel.spec       |    4 +-
 2 files changed, 632 insertions(+), 898 deletions(-)
---
diff --git a/kernel.spec b/kernel.spec
index 36227f74..36cd09b2 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -53,7 +53,7 @@
 
 %define		rel		1
 %define		basever		6.12
-%define		postver		.68
+%define		postver		.69
 
 # define this to '-%{basever}' for longterm branch
 %define		versuffix	-%{basever}
@@ -107,7 +107,7 @@ Source0:	https://www.kernel.org/pub/linux/kernel/v6.x/linux-%{basever}.tar.xz
 # Source0-md5:	844fae6a58c7f43af44d8cea8484b4a1
 %if "%{postver}" != ".0"
 Patch0:		https://www.kernel.org/pub/linux/kernel/v6.x/patch-%{version}.xz
-# Patch0-md5:	ec1a4ee9f0490c1823d2eb2e993855be
+# Patch0-md5:	39f708bfd0db1a49b4f7635403b88ece
 %endif
 Source1:	kernel.sysconfig
 
diff --git a/kernel-aufs.patch b/kernel-aufs.patch
index a3eed527..87080f8a 100644
--- a/kernel-aufs.patch
+++ b/kernel-aufs.patch
@@ -245,455 +245,177 @@ index 53c76dc71f3f5..35e5be967209e 100644
 SPDX-License-Identifier: GPL-2.0
 aufs6.12.29 mmap patch
 
+diff --git a/fs/Makefile b/fs/Makefile
+index b2539712b80d0..8260694bb133a 100644
+--- a/fs/Makefile
++++ b/fs/Makefile
+@@ -16,6 +16,9 @@ obj-y :=	open.o read_write.o file_table.o super.o \
+ 		stack.o fs_struct.o statfs.o fs_pin.o nsfs.o \
+ 		fs_types.o fs_context.o fs_parser.o fsopen.o init.o \
+ 		kernel_read_file.o mnt_idmapping.o remap_range.o pidfs.o
++ifeq (${CONFIG_AUFS_FS},m)
++obj-y += au_mf.o
++endif
+ 
+ obj-$(CONFIG_BUFFER_HEAD)	+= buffer.o mpage.o
+ obj-$(CONFIG_PROC_FS)		+= proc_namespace.o
+diff --git a/fs/au_mf.c b/fs/au_mf.c
+new file mode 100644
+index 0000000000000..ee1ff03778b98
+--- /dev/null
++++ b/fs/au_mf.c
+@@ -0,0 +1,60 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2025 Junjiro R. Okajima
++ */
++
++#include <linux/fs.h>
++#include <linux/module.h>
++
++#if IS_MODULE(CONFIG_AUFS_FS)
++/*
++ * This au_mf.c (aufs mmapped files) is for external AUFS module only,
++ * and statically linked to kernel.
++ * See also $srctree/fs/Makefile.
++ * This linking may seem to be tricky. It is due to support the case when AUFS
++ * is configured as an external module, eg. VFS calls a function defined in the
++ * dynamic module.
++ */
++#else
++BUILD_BUG_ON_MSG(1, "CONFIG_AUFS_FS is disabled.");
++#endif
++
++const struct path *au_file_user_path(struct file *f)
++{
++	const struct path *path,
++		*(*func)(struct file *f),
++		*au_do_file_user_path(struct file *f);
++
++	path = NULL;
++	func = symbol_get(au_do_file_user_path);
++	if (unlikely(!func))
++		/* "aufs" module is not loaded */
++		goto out;
++
++	path = func(f);
++	symbol_put(au_do_file_user_path);
++
++out:
++	return path;
++}
++EXPORT_SYMBOL_GPL(au_file_user_path);
++
++const struct inode *au_file_user_inode(struct file *f)
++{
++	const struct inode *inode,
++		*(*func)(struct file *f),
++		*au_do_file_user_inode(struct file *f);
++
++	inode = NULL;
++	func = symbol_get(au_do_file_user_inode);
++	if (unlikely(!func))
++		/* "aufs" module is not loaded */
++		goto out;
++
++	inode = func(f);
++	symbol_put(au_do_file_user_inode);
++
++out:
++	return inode;
++}
++EXPORT_SYMBOL_GPL(au_file_user_inode);
 diff --git a/fs/proc/base.c b/fs/proc/base.c
-index a2541f5204af0..51ccdf1869a9a 100644
+index a2541f5204af0..4fca8eee56e14 100644
 --- a/fs/proc/base.c
 +++ b/fs/proc/base.c
-@@ -2270,7 +2270,7 @@ static int map_files_get_link(struct dentry *dentry, struct path *path)
- 	rc = -ENOENT;
- 	vma = find_exact_vma(mm, vm_start, vm_end);
- 	if (vma && vma->vm_file) {
--		*path = *file_user_path(vma->vm_file);
-+		*path = vma_pr_or_file(vma)->f_path;
- 		path_get(path);
- 		rc = 0;
- 	}
+@@ -1784,7 +1784,7 @@ static int proc_exe_link(struct dentry *dentry, struct path *exe_path)
+ 	exe_file = get_task_exe_file(task);
+ 	put_task_struct(task);
+ 	if (exe_file) {
+-		*exe_path = exe_file->f_path;
++		*exe_path = *file_user_path(exe_file);
+ 		path_get(&exe_file->f_path);
+ 		fput(exe_file);
+ 		return 0;
 diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c
-index c6e7ebc637562..d7ccfd9097646 100644
+index c6e7ebc637562..12c340dcdec3d 100644
 --- a/fs/proc/nommu.c
 +++ b/fs/proc/nommu.c
-@@ -39,7 +39,10 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region)
+@@ -39,7 +39,7 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region)
  	file = region->vm_file;
  
  	if (file) {
 -		struct inode *inode = file_inode(region->vm_file);
-+		struct inode *inode;
-+
-+		file = vmr_pr_or_file(region);
-+		inode = file_inode(file);
++		struct inode *inode = file_user_inode(region->vm_file);
  		dev = inode->i_sb->s_dev;
  		ino = inode->i_ino;
  	}
-diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
-index 536b7dc453818..9827adb224d75 100644
---- a/fs/proc/task_mmu.c
-+++ b/fs/proc/task_mmu.c
-@@ -264,7 +264,8 @@ static void get_vma_name(struct vm_area_struct *vma,
- 			*name_fmt = "[anon_shmem:%s]";
- 			*name = anon_name->name;
- 		} else {
--			*path = file_user_path(vma->vm_file);
-+			struct file *f = vma_pr_or_file(vma);
-+			*path = file_user_path(f);
- 		}
- 		return;
- 	}
-@@ -333,7 +334,8 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
- 	dev_t dev = 0;
- 
- 	if (vma->vm_file) {
--		const struct inode *inode = file_user_inode(vma->vm_file);
-+		const struct inode *inode
-+			= file_inode(vma_pr_or_file(vma));
- 
- 		dev = inode->i_sb->s_dev;
- 		ino = inode->i_ino;
-@@ -3008,7 +3010,7 @@ static int show_numa_map(struct seq_file *m, void *v)
- 	struct proc_maps_private *proc_priv = &numa_priv->proc_maps;
- 	struct vm_area_struct *vma = v;
- 	struct numa_maps *md = &numa_priv->md;
--	struct file *file = vma->vm_file;
-+	struct file *file = vma_pr_or_file(vma);
- 	struct mm_struct *mm = vma->vm_mm;
- 	char buffer[64];
- 	struct mempolicy *pol;
 diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
-index bce6745330003..b12b5a75c799c 100644
+index bce6745330003..dac36cc7a3880 100644
 --- a/fs/proc/task_nommu.c
 +++ b/fs/proc/task_nommu.c
-@@ -137,7 +137,10 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma)
+@@ -137,7 +137,7 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma)
  	file = vma->vm_file;
  
  	if (file) {
 -		struct inode *inode = file_inode(vma->vm_file);
-+		struct inode *inode;
-+
-+		file = vma_pr_or_file(vma);
-+		inode = file_inode(file);
++		struct inode *inode = file_user_inode(vma->vm_file);
  		dev = inode->i_sb->s_dev;
  		ino = inode->i_ino;
  		pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT;
-diff --git a/include/linux/mm.h b/include/linux/mm.h
-index 8617adc6becd1..50df19d8bcc0a 100644
---- a/include/linux/mm.h
-+++ b/include/linux/mm.h
-@@ -2469,6 +2469,43 @@ static inline void unmap_shared_mapping_range(struct address_space *mapping,
- static inline struct vm_area_struct *vma_lookup(struct mm_struct *mm,
- 						unsigned long addr);
+diff --git a/include/linux/fs.h b/include/linux/fs.h
+index cb9f98b540e31..44805e9a38604 100644
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -2734,6 +2734,21 @@ struct file *dentry_create(const struct path *path, int flags, umode_t mode,
+ 			   const struct cred *cred);
+ struct path *backing_file_user_path(struct file *f);
  
-+#if 1 /* IS_ENABLED(CONFIG_AUFS_FS) */
-+extern void vma_do_file_update_time(struct vm_area_struct *, const char[], int);
-+extern struct file *vma_do_pr_or_file(struct vm_area_struct *, const char[],
-+				      int);
-+extern void vma_do_get_file(struct vm_area_struct *, const char[], int);
-+extern void vma_do_fput(struct vm_area_struct *, const char[], int);
-+
-+#define vma_file_update_time(vma)	vma_do_file_update_time(vma, __func__, \
-+								__LINE__)
-+#define vma_pr_or_file(vma)		vma_do_pr_or_file(vma, __func__, \
-+							  __LINE__)
-+#define vma_get_file(vma)		vma_do_get_file(vma, __func__, __LINE__)
-+#define vma_fput(vma)			vma_do_fput(vma, __func__, __LINE__)
-+
-+#ifndef CONFIG_MMU
-+extern struct file *vmr_do_pr_or_file(struct vm_region *, const char[], int);
-+extern void vmr_do_fput(struct vm_region *, const char[], int);
-+
-+#define vmr_pr_or_file(region)		vmr_do_pr_or_file(region, __func__, \
-+							  __LINE__)
-+#define vmr_fput(region)		vmr_do_fput(region, __func__, __LINE__)
-+#endif /* !CONFIG_MMU */
-+
++#if IS_MODULE(CONFIG_AUFS_FS)
++/* fs/au_mf.c */
++const struct path *au_file_user_path(struct file *f);
++const struct inode *au_file_user_inode(struct file *f);
++#elif IS_BUILTIN(CONFIG_AUFS_FS)
++/* fs/aufs/mf.c */
++const struct path *au_do_file_user_path(struct file *f);
++const struct inode *au_do_file_user_inode(struct file *f);
++#define au_file_user_path(f)	au_do_file_user_path(f)
++#define au_file_user_inode(f)	au_do_file_user_inode(f)
 +#else
-+
-+#define vma_file_update_time(vma)	file_update_time((vma)->vm_file)
-+#define vma_pr_or_file(vma)		(vma)->vm_file
-+#define vma_get_file(vma)		get_file((vma)->vm_file)
-+#define vma_fput(vma)			fput((vma)->vm_file)
-+
-+#ifndef CONFIG_MMU
-+#define vmr_pr_or_file(region)		(region)->vm_file
-+#define vmr_fput(region)		fput((region)->vm_file)
-+#endif /* !CONFIG_MMU */
-+
-+#endif /* CONFIG_AUFS_FS */
-+
- extern int access_process_vm(struct task_struct *tsk, unsigned long addr,
- 		void *buf, int len, unsigned int gup_flags);
- extern int access_remote_vm(struct mm_struct *mm, unsigned long addr,
-diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
-index 6894de506b364..5595422990d7b 100644
---- a/include/linux/mm_types.h
-+++ b/include/linux/mm_types.h
-@@ -602,6 +602,9 @@ struct vm_region {
- 	unsigned long	vm_top;		/* region allocated to here */
- 	unsigned long	vm_pgoff;	/* the offset in vm_file corresponding to vm_start */
- 	struct file	*vm_file;	/* the backing file or NULL */
-+#if 1 /* IS_ENABLED(CONFIG_AUFS_FS) */
-+	struct file	*vm_prfile;	/* the virtual backing file or NULL */
-+#endif
- 
- 	int		vm_usage;	/* region usage count (access under nommu_region_sem) */
- 	bool		vm_icache_flushed : 1; /* true if the icache has been flushed for
-@@ -777,6 +780,9 @@ struct vm_area_struct {
- 	unsigned long vm_pgoff;		/* Offset (within vm_file) in PAGE_SIZE
- 					   units */
- 	struct file * vm_file;		/* File we map to (can be NULL). */
-+#if 1 /* IS_ENABLED(CONFIG_AUFS_FS) */
-+	struct file *vm_prfile;		/* shadow of vm_file */
-+#endif
- 	void * vm_private_data;		/* was vm_pte (shared mem) */
- 
- #ifdef CONFIG_ANON_VMA_NAME
-diff --git a/kernel/fork.c b/kernel/fork.c
-index 12decadff468f..74f5a6eb055eb 100644
---- a/kernel/fork.c
-+++ b/kernel/fork.c
-@@ -737,7 +737,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
- 		if (file) {
- 			struct address_space *mapping = file->f_mapping;
- 
--			get_file(file);
-+			vma_get_file(tmp);
- 			i_mmap_lock_write(mapping);
- 			if (vma_is_shared_maywrite(tmp))
- 				mapping_allow_writable(mapping);
-diff --git a/mm/Makefile b/mm/Makefile
-index d5639b0361663..bb57f616f0325 100644
---- a/mm/Makefile
-+++ b/mm/Makefile
-@@ -145,3 +145,4 @@ obj-$(CONFIG_GENERIC_IOREMAP) += ioremap.o
- obj-$(CONFIG_SHRINKER_DEBUG) += shrinker_debug.o
- obj-$(CONFIG_EXECMEM) += execmem.o
- obj-$(CONFIG_TMPFS_QUOTA) += shmem_quota.o
-+obj-y += prfile.o
-diff --git a/mm/filemap.c b/mm/filemap.c
-index fa18e71f9c889..20a5773f7e7c8 100644
---- a/mm/filemap.c
-+++ b/mm/filemap.c
-@@ -3719,7 +3719,7 @@ vm_fault_t filemap_page_mkwrite(struct vm_fault *vmf)
- 	vm_fault_t ret = VM_FAULT_LOCKED;
- 
- 	sb_start_pagefault(mapping->host->i_sb);
--	file_update_time(vmf->vma->vm_file);
-+	vma_file_update_time(vmf->vma);
- 	folio_lock(folio);
- 	if (folio->mapping != mapping) {
- 		folio_unlock(folio);
-diff --git a/mm/mmap.c b/mm/mmap.c
-index 6183805f6f9e6..dd11c528dd557 100644
---- a/mm/mmap.c
-+++ b/mm/mmap.c
-@@ -1489,7 +1489,7 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr,
- 				 * and cause general protection fault
- 				 * ultimately.
- 				 */
--				fput(vma->vm_file);
-+				vma_fput(vma);
- 				vm_area_free(vma);
- 				vma = merge;
- 				/* Update vm_flags to pick up the change. */
-@@ -1670,6 +1670,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
- 	unsigned long ret = -EINVAL;
- 	struct file *file;
- 	vm_flags_t vm_flags;
-+	struct file *prfile = NULL; /* aufs */
- 
- 	pr_warn_once("%s (%d) uses deprecated remap_file_pages() syscall. See Documentation/mm/remap_file_pages.rst.\n",
- 		     current->comm, current->pid);
-@@ -1712,14 +1713,18 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
- 
- 	/* Save vm_flags used to calculate prot and flags, and recheck later. */
- 	vm_flags = vma->vm_flags;
--	file = get_file(vma->vm_file);
-+	vma_get_file(vma);
-+	file = vma->vm_file;
-+#if 1 /* IS_ENABLED(CONFIG_AUFS_FS) */
-+	prfile = vma->vm_prfile;
-+#endif
- 
- 	mmap_read_unlock(mm);
- 
- 	/* Call outside mmap_lock to be consistent with other callers. */
- 	ret = security_mmap_file(file, prot, flags);
- 	if (ret) {
--		fput(file);
-+		vma_fput(vma);
- 		return ret;
- 	}
- 
-@@ -1727,7 +1732,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
- 
- 	/* OK security check passed, take write lock + let it rip. */
- 	if (mmap_write_lock_killable(mm)) {
--		fput(file);
-+		vma_fput(vma);
- 		return -EINTR;
- 	}
- 
-@@ -1769,9 +1774,27 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
- 
- 	ret = do_mmap(vma->vm_file, start, size,
- 			prot, flags, 0, pgoff, &populate, NULL);
-+#if 1 /* IS_ENABLED(CONFIG_AUFS_FS) */
-+	if (!IS_ERR_VALUE(ret) && file && prfile) {
-+		struct vm_area_struct *new_vma;
-+
-+		new_vma = find_vma(mm, ret);
-+		if (!new_vma->vm_prfile)
-+			new_vma->vm_prfile = prfile;
-+		if (prfile)
-+			get_file(prfile);
-+	}
++#define au_file_user_path(f)	NULL
++#define au_file_user_inode(f)	NULL
 +#endif
 +
- out:
- 	mmap_write_unlock(mm);
-+	/*
-+	 * two fput()s instead of vma_fput(vma),
-+	 * coz vma may not be available anymore.
-+	 */
- 	fput(file);
-+	if (prfile)
-+		fput(prfile);
- 	if (populate)
- 		mm_populate(ret, populate);
- 	if (!IS_ERR_VALUE(ret))
-diff --git a/mm/nommu.c b/mm/nommu.c
-index 9cb6e99215e2b..5add36afa9786 100644
---- a/mm/nommu.c
-+++ b/mm/nommu.c
-@@ -512,7 +512,7 @@ static void __put_nommu_region(struct vm_region *region)
- 		up_write(&nommu_region_sem);
- 
- 		if (region->vm_file)
--			fput(region->vm_file);
-+			vmr_fput(region);
- 
- 		/* IO memory and memory shared directly out of the pagecache
- 		 * from ramfs/tmpfs mustn't be released here */
-@@ -591,7 +591,7 @@ static void delete_vma(struct mm_struct *mm, struct vm_area_struct *vma)
+ /*
+  * When mmapping a file on a stackable filesystem (e.g., overlayfs), the file
+  * stored in ->vm_file is a backing file whose f_inode is on the underlying
+@@ -2746,15 +2761,25 @@ struct path *backing_file_user_path(struct file *f);
+ /* Get the path to display in /proc/<pid>/maps */
+ static inline const struct path *file_user_path(struct file *f)
  {
- 	vma_close(vma);
- 	if (vma->vm_file)
--		fput(vma->vm_file);
-+		vma_fput(vma);
- 	put_nommu_region(vma->vm_region);
- 	vm_area_free(vma);
++	const struct path *path;
++
+ 	if (unlikely(f->f_mode & FMODE_BACKING))
+ 		return backing_file_user_path(f);
++	path = au_file_user_path(f);
++	if (path)
++		return path;
+ 	return &f->f_path;
  }
-@@ -1123,7 +1123,7 @@ unsigned long do_mmap(struct file *file,
- 					goto error_just_free;
- 				}
- 			}
--			fput(region->vm_file);
-+			vmr_fput(region);
- 			kmem_cache_free(vm_region_jar, region);
- 			region = pregion;
- 			result = start;
-@@ -1209,10 +1209,10 @@ unsigned long do_mmap(struct file *file,
- error:
- 	vma_iter_free(&vmi);
- 	if (region->vm_file)
--		fput(region->vm_file);
-+		vmr_fput(region);
- 	kmem_cache_free(vm_region_jar, region);
- 	if (vma->vm_file)
--		fput(vma->vm_file);
-+		vma_fput(vma);
- 	vm_area_free(vma);
- 	return ret;
- 
-diff --git a/mm/prfile.c b/mm/prfile.c
-new file mode 100644
-index 0000000000000..b034d160a18f4
---- /dev/null
-+++ b/mm/prfile.c
-@@ -0,0 +1,86 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Mainly for aufs which mmap(2) different file and wants to print different
-+ * path in /proc/PID/maps.
-+ * Call these functions via macros defined in linux/mm.h.
-+ *
-+ * See Documentation/filesystems/aufs/design/06mmap.txt
-+ *
-+ * Copyright (c) 2014-2025 Junjro R. Okajima
-+ * Copyright (c) 2014 Ian Campbell
-+ */
-+
-+#include <linux/mm.h>
-+#include <linux/file.h>
-+#include <linux/fs.h>
-+
-+/* #define PRFILE_TRACE */
-+static inline void prfile_trace(struct file *f, struct file *pr,
-+			      const char func[], int line, const char func2[])
-+{
-+#ifdef PRFILE_TRACE
-+	if (pr)
-+		pr_info("%s:%d: %s, %pD2\n", func, line, func2, f);
-+#endif
-+}
-+
-+void vma_do_file_update_time(struct vm_area_struct *vma, const char func[],
-+			     int line)
-+{
-+	struct file *f = vma->vm_file, *pr = vma->vm_prfile;
-+
-+	prfile_trace(f, pr, func, line, __func__);
-+	file_update_time(f);
-+	if (f && pr)
-+		file_update_time(pr);
-+}
-+
-+struct file *vma_do_pr_or_file(struct vm_area_struct *vma, const char func[],
-+			       int line)
-+{
-+	struct file *f = vma->vm_file, *pr = vma->vm_prfile;
-+
-+	prfile_trace(f, pr, func, line, __func__);
-+	return (f && pr) ? pr : f;
-+}
-+
-+void vma_do_get_file(struct vm_area_struct *vma, const char func[], int line)
-+{
-+	struct file *f = vma->vm_file, *pr = vma->vm_prfile;
-+
-+	prfile_trace(f, pr, func, line, __func__);
-+	get_file(f);
-+	if (f && pr)
-+		get_file(pr);
-+}
-+
-+void vma_do_fput(struct vm_area_struct *vma, const char func[], int line)
-+{
-+	struct file *f = vma->vm_file, *pr = vma->vm_prfile;
-+
-+	prfile_trace(f, pr, func, line, __func__);
-+	fput(f);
-+	if (f && pr)
-+		fput(pr);
-+}
-+
-+#ifndef CONFIG_MMU
-+struct file *vmr_do_pr_or_file(struct vm_region *region, const char func[],
-+			       int line)
-+{
-+	struct file *f = region->vm_file, *pr = region->vm_prfile;
-+
-+	prfile_trace(f, pr, func, line, __func__);
-+	return (f && pr) ? pr : f;
-+}
-+
-+void vmr_do_fput(struct vm_region *region, const char func[], int line)
-+{
-+	struct file *f = region->vm_file, *pr = region->vm_prfile;
+ /* Get the inode whose inode number to display in /proc/<pid>/maps */
+ static inline const struct inode *file_user_inode(struct file *f)
+ {
++	const struct inode *inode;
 +
-+	prfile_trace(f, pr, func, line, __func__);
-+	fput(f);
-+	if (f && pr)
-+		fput(pr);
-+}
-+#endif /* !CONFIG_MMU */
-diff --git a/mm/vma.c b/mm/vma.c
-index 9b4517944901d..429454b496b61 100644
---- a/mm/vma.c
-+++ b/mm/vma.c
-@@ -248,7 +248,7 @@ static void vma_complete(struct vma_prepare *vp, struct vma_iterator *vmi,
- 		if (vp->file) {
- 			uprobe_munmap(vp->remove, vp->remove->vm_start,
- 				      vp->remove->vm_end);
--			fput(vp->file);
-+			vma_fput(vp->vma);
- 		}
- 		if (vp->remove->anon_vma)
- 			anon_vma_merge(vp->vma, vp->remove);
-@@ -328,7 +328,7 @@ void remove_vma(struct vm_area_struct *vma, bool unreachable)
- 	might_sleep();
- 	vma_close(vma);
- 	if (vma->vm_file)
--		fput(vma->vm_file);
-+		vma_fput(vma);
- 	mpol_put(vma_policy(vma));
- 	if (unreachable)
- 		__vm_area_free(vma);
-@@ -405,7 +405,7 @@ static int __split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma,
- 		goto out_free_mpol;
- 
- 	if (new->vm_file)
--		get_file(new->vm_file);
-+		vma_get_file(new);
- 
- 	if (new->vm_ops && new->vm_ops->open)
- 		new->vm_ops->open(new);
-@@ -1705,7 +1705,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
- 		if (anon_vma_clone(new_vma, vma))
- 			goto out_free_mempol;
- 		if (new_vma->vm_file)
--			get_file(new_vma->vm_file);
-+			vma_get_file(new_vma);
- 		if (new_vma->vm_ops && new_vma->vm_ops->open)
- 			new_vma->vm_ops->open(new_vma);
- 		if (vma_link(mm, new_vma))
-@@ -1718,7 +1718,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
- 	vma_close(new_vma);
- 
- 	if (new_vma->vm_file)
--		fput(new_vma->vm_file);
-+		vma_fput(new_vma);
+ 	if (unlikely(f->f_mode & FMODE_BACKING))
+ 		return d_inode(backing_file_user_path(f)->dentry);
++	inode = au_file_user_inode(f);
++	if (inode)
++		return inode;
+ 	return file_inode(f);
+ }
  
- 	unlink_anon_vmas(new_vma);
- out_free_mempol:
 SPDX-License-Identifier: GPL-2.0
 aufs6.12.29 standalone patch
 
@@ -774,12 +496,12 @@ index 3a8f55b2225d4..a6f32c184d5c5 100644
  static void free_mnt_ns(struct mnt_namespace *);
  static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *, bool);
 @@ -2236,6 +2238,7 @@ void drop_collected_mounts(struct vfsmount *mnt)
- 	unlock_mount_hash();
- 	namespace_unlock();
+ 	}
+ 	return false;
  }
 +EXPORT_SYMBOL_GPL(drop_collected_mounts);
  
- static bool __has_locked_children(struct mount *mnt, struct dentry *dentry)
+ bool has_locked_children(struct mount *mnt, struct dentry *dentry)
  {
 @@ -2307,6 +2310,7 @@ int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg,
  	}
@@ -879,10 +601,18 @@ index c969f1f26be58..68eb672f425d9 100644
  }
 +EXPORT_SYMBOL_GPL(task_work_run);
 diff --git a/security/security.c b/security/security.c
-index c5981e558bc26..045dd716e3400 100644
+index c5981e558bc26..bf24ac08acb64 100644
 --- a/security/security.c
 +++ b/security/security.c
-@@ -1944,6 +1944,7 @@ int security_path_rmdir(const struct path *dir, struct dentry *dentry)
+@@ -1909,6 +1909,7 @@ void security_path_post_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
+ 		return;
+ 	call_void_hook(path_post_mknod, idmap, dentry);
+ }
++EXPORT_SYMBOL_GPL(security_path_post_mknod);
+ 
+ /**
+  * security_path_mkdir() - Check if creating a new directory is allowed
+@@ -1944,6 +1945,7 @@ int security_path_rmdir(const struct path *dir, struct dentry *dentry)
  		return 0;
  	return call_int_hook(path_rmdir, dir, dentry);
  }
@@ -890,7 +620,7 @@ index c5981e558bc26..045dd716e3400 100644
  
  /**
   * security_path_unlink() - Check if removing a hard link is allowed
-@@ -1979,6 +1980,7 @@ int security_path_symlink(const struct path *dir, struct dentry *dentry,
+@@ -1979,6 +1981,7 @@ int security_path_symlink(const struct path *dir, struct dentry *dentry,
  		return 0;
  	return call_int_hook(path_symlink, dir, dentry, old_name);
  }
@@ -898,7 +628,7 @@ index c5981e558bc26..045dd716e3400 100644
  
  /**
   * security_path_link - Check if creating a hard link is allowed
-@@ -1997,6 +1999,7 @@ int security_path_link(struct dentry *old_dentry, const struct path *new_dir,
+@@ -1997,6 +2000,7 @@ int security_path_link(struct dentry *old_dentry, const struct path *new_dir,
  		return 0;
  	return call_int_hook(path_link, old_dentry, new_dir, new_dentry);
  }
@@ -906,7 +636,7 @@ index c5981e558bc26..045dd716e3400 100644
  
  /**
   * security_path_rename() - Check if renaming a file is allowed
-@@ -2058,6 +2061,7 @@ int security_path_chmod(const struct path *path, umode_t mode)
+@@ -2058,6 +2062,7 @@ int security_path_chmod(const struct path *path, umode_t mode)
  		return 0;
  	return call_int_hook(path_chmod, path, mode);
  }
@@ -914,7 +644,7 @@ index c5981e558bc26..045dd716e3400 100644
  
  /**
   * security_path_chown() - Check if changing the file's owner/group is allowed
-@@ -2075,6 +2079,7 @@ int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid)
+@@ -2075,6 +2080,7 @@ int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid)
  		return 0;
  	return call_int_hook(path_chown, path, uid, gid);
  }
@@ -922,7 +652,7 @@ index c5981e558bc26..045dd716e3400 100644
  
  /**
   * security_path_chroot() - Check if changing the root directory is allowed
-@@ -2319,6 +2324,7 @@ int security_inode_permission(struct inode *inode, int mask)
+@@ -2319,6 +2325,7 @@ int security_inode_permission(struct inode *inode, int mask)
  		return 0;
  	return call_int_hook(inode_permission, inode, mask);
  }
@@ -930,7 +660,7 @@ index c5981e558bc26..045dd716e3400 100644
  
  /**
   * security_inode_setattr() - Check if setting file attributes is allowed
-@@ -2840,6 +2846,7 @@ int security_file_permission(struct file *file, int mask)
+@@ -2840,6 +2847,7 @@ int security_file_permission(struct file *file, int mask)
  {
  	return call_int_hook(file_permission, file, mask);
  }
@@ -938,7 +668,7 @@ index c5981e558bc26..045dd716e3400 100644
  
  /**
   * security_file_alloc() - Allocate and init a file's LSM blob
-@@ -3144,6 +3151,7 @@ int security_file_truncate(struct file *file)
+@@ -3144,6 +3152,7 @@ int security_file_truncate(struct file *file)
  {
  	return call_int_hook(file_truncate, file);
  }
@@ -2107,8 +1837,8 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/06fhsm.txt linu
 +should restore the original file state after an error happens.
 diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/06mmap.txt linux/Documentation/filesystems/aufs/design/06mmap.txt
 --- /usr/share/empty/Documentation/filesystems/aufs/design/06mmap.txt	1970-01-01 01:00:00.000000000 +0100
-+++ linux/Documentation/filesystems/aufs/design/06mmap.txt	2025-02-04 20:03:40.673271838 +0100
-@@ -0,0 +1,72 @@
++++ linux/Documentation/filesystems/aufs/design/06mmap.txt	2025-12-01 15:04:47.556666712 +0100
+@@ -0,0 +1,40 @@
 +
 +# Copyright (C) 2005-2025 Junjiro R. Okajima
 +#
@@ -2134,53 +1864,21 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/06mmap.txt linu
 +Under /proc, several entries show the mmapped files by its path (with
 +device and inode number), and the printed path will be the path on the
 +branch fs's instead of virtual aufs's.
-+This is not a problem in most cases, but some utilities lsof(1) (and its
-+user) may expect the path on aufs.
-+
-+To address this issue, aufs adds a new member called vm_prfile in struct
-+vm_area_struct (and struct vm_region). The original vm_file points to
-+the file on the branch fs in order to handle everything correctly as
-+usual. The new vm_prfile points to a virtual file in aufs, and the
-+show-functions in procfs refers to vm_prfile if it is set.
-+Also we need to maintain several other places where touching vm_file
-+such like
-+- fork()/clone() copies vma and the reference count of vm_file is
-+  incremented.
-+- merging vma maintains the ref count too.
-+
-+This is not a good approach. It just fakes the printed path. But it
-+leaves all behaviour around f_mapping unchanged. This is surely an
-+advantage.
-+Actually aufs had adopted another complicated approach which calls
-+generic_file_mmap() and handles struct vm_operations_struct. In this
-+approach, aufs met a hard problem and I could not solve it without
-+switching the approach.
-+
-+There may be one more another approach which is
-+- bind-mount the branch-root onto the aufs-root internally
-+- grab the new vfsmount (ie. struct mount)
-+- lazy-umount the branch-root internally
-+- in open(2) the aufs-file, open the branch-file with the hidden
-+  vfsmount (instead of the original branch's vfsmount)
-+- ideally this "bind-mount and lazy-umount" should be done atomically,
-+  but it may be possible from userspace by the mount helper.
-+
-+Adding the internal hidden vfsmount and using it in opening a file, the
-+file path under /proc will be printed correctly. This approach looks
-+smarter, but is not possible I am afraid.
-+- aufs-root may be bind-mount later. when it happens, another hidden
-+  vfsmount will be required.
-+- it is hard to get the chance to bind-mount and lazy-umount
-+  + in kernel-space, FS can have vfsmount in open(2) via
-+    file->f_path, and aufs can know its vfsmount. But several locks are
-+    already acquired, and if aufs tries to bind-mount and lazy-umount
-+    here, then it may cause a deadlock.
-+  + in user-space, bind-mount doesn't invoke the mount helper.
-+- since /proc shows dev and ino, aufs has to give vma these info. it
-+  means a new member vm_prinode will be necessary. this is essentially
-+  equivalent to vm_prfile described above.
-+
-+I have to give up this "looks-smater" approach.
++This is not a problem in most cases, but some utilities such like
++lsof(1) (and its user) may expect the path on aufs.
++
++To address this issue, aufs used to take an approach to add a new
++member 'vm_prfile' into struct vm_area_struct (and struct
++vm_region). It was not an ideal solution but worked well for a long
++time. One big disadvantage is that it requires to follow every changes
++around 'vm_file' in every mainline releases.
++
++In linux-v6.7 (and v6.8), VFS internal functions file_user_path() and
++file_user_inode() were introduced for FMODE_BACKING and Overlayfs.
++They are good customization points and aufs gave up 'vm_prfile'
++approach and switched to modifiying file_user_{path,inode}() since
++aufs6.12. It also requires to changes to 'vm_file' in mainline, but it
++will be much smaller than the approach aufs used to take.
 diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/06xattr.txt linux/Documentation/filesystems/aufs/design/06xattr.txt
 --- /usr/share/empty/Documentation/filesystems/aufs/design/06xattr.txt	1970-01-01 01:00:00.000000000 +0100
 +++ linux/Documentation/filesystems/aufs/design/06xattr.txt	2025-02-04 20:03:40.673271838 +0100
@@ -2450,7 +2148,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/10dynop.txt lin
 +regular files only.
 diff -urN /usr/share/empty/Documentation/filesystems/aufs/README linux/Documentation/filesystems/aufs/README
 --- /usr/share/empty/Documentation/filesystems/aufs/README	1970-01-01 01:00:00.000000000 +0100
-+++ linux/Documentation/filesystems/aufs/README	2024-11-18 12:46:45.633029891 +0100
++++ linux/Documentation/filesystems/aufs/README	2025-12-01 15:04:47.556666712 +0100
 @@ -0,0 +1,409 @@
 +
 +Aufs6 -- advanced multi layered unification filesystem version 6.x
@@ -2834,7 +2532,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/README linux/Documenta
 +The Parted Magic Project made a donation (2013/9 and 11).
 +Pavel Barta made a donation (2013/10).
 +Nikolay Pertsev made a donation (2014/5).
-+James B made a donation (2014/7, 2015/7, and 2021/12).
++James B made a donation (2014/7, 2015/7, 2021/12, and 2025/9).
 +Stefano Di Biase made a donation (2014/8).
 +Daniel Epellei made a donation (2015/1).
 +OmegaPhil made a donation (2016/1, 2018/4).
@@ -4360,7 +4058,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c
 +}
 diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h
 --- /usr/share/empty/fs/aufs/branch.h	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/branch.h	2025-02-04 20:03:40.676605172 +0100
++++ linux/fs/aufs/branch.h	2025-12-01 15:04:46.893333378 +0100
 @@ -0,0 +1,375 @@
 +/* SPDX-License-Identifier: GPL-2.0 */
 +/*
@@ -4783,8 +4481,8 @@ diff -urN /usr/share/empty/fs/aufs/conf.mk linux/fs/aufs/conf.mk
 +-include ${srctree}/${src}/conf_priv.mk
 diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 --- /usr/share/empty/fs/aufs/cpup.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/cpup.c	2025-07-24 19:31:57.789847457 +0200
-@@ -0,0 +1,1458 @@
++++ linux/fs/aufs/cpup.c	2026-02-08 10:11:28.889988407 +0100
+@@ -0,0 +1,1446 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Copyright (C) 2005-2025 Junjiro R. Okajima
@@ -4934,8 +4632,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +	attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET
 +		| ATTR_ATIME | ATTR_ATIME_SET;
 +
-+	/* no delegation since this is a directory */
-+	err = vfsub_notify_change(&dt->dt_h_path, &attr, /*delegated*/NULL);
++	err = vfsub_notify_change(&dt->dt_h_path, &attr);
 +	if (unlikely(err))
 +		pr_warn("restoring timestamps failed(%d). ignored\n", err);
 +}
@@ -4996,14 +4693,13 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +		sbits = !!(h_isrc->i_mode & (S_ISUID | S_ISGID));
 +		au_cpup_attr_flags(h_idst, h_isrc->i_flags);
 +	}
-+	/* no delegation since it is just created */
-+	err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL);
++	err = vfsub_notify_change(&h_path, &ia);
 +
 +	/* is this nfs only? */
 +	if (!err && sbits && au_test_nfs(h_path.dentry->d_sb)) {
 +		ia.ia_valid = ATTR_FORCE | ATTR_MODE;
 +		ia.ia_mode = h_isrc->i_mode;
-+		err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL);
++		err = vfsub_notify_change(&h_path, &ia);
 +	}
 +
 +	icex = br->br_perm & AuBrAttr_ICEX;
@@ -5107,9 +4803,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +			ia->ia_file = dst;
 +			h_inode = file_inode(dst);
 +			inode_lock_nested(h_inode, AuLsc_I_CHILD2);
-+			/* no delegation since it is just created */
-+			err = vfsub_notify_change(&dst->f_path, ia,
-+						  /*delegated*/NULL);
++			err = vfsub_notify_change(&dst->f_path, ia);
 +			inode_unlock(h_inode);
 +		}
 +	}
@@ -5302,7 +4996,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +	int err, rerr;
 +	loff_t l;
 +	struct path h_path;
-+	struct inode *h_src_inode, *h_dst_inode;
++	struct inode *h_src_inode;
 +
 +	err = 0;
 +	h_src_inode = au_h_iptr(d_inode(cpg->dentry), cpg->bsrc);
@@ -5340,13 +5034,6 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +		if (!err && rerr)
 +			err = rerr;
 +	}
-+	if (!err && (h_src_inode->i_state & I_LINKABLE)) {
-+		h_path.dentry = au_h_dptr(cpg->dentry, cpg->bdst);
-+		h_dst_inode = d_inode(h_path.dentry);
-+		spin_lock(&h_dst_inode->i_lock);
-+		h_dst_inode->i_state |= I_LINKABLE;
-+		spin_unlock(&h_dst_inode->i_lock);
-+	}
 +
 +out:
 +	return err;
@@ -5504,7 +5191,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +	    && !isdir
 +	    && au_opt_test(mnt_flags, XINO)
 +	    && (vfsub_inode_nlink(h_inode, AU_I_BRANCH) == 1
-+		|| (h_inode->i_state & I_LINKABLE))
++		|| au_ii(d_inode(cpg->dentry))->ii_tmpfile)
 +	    /* todo: unnecessary? */
 +	    /* && d_inode(cpg->dentry)->i_nlink == 1 */
 +	    && cpg->bdst < cpg->bsrc
@@ -5562,9 +5249,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +	h_dir = d_inode(h_parent);
 +	IMustLock(h_dir);
 +	AuDbg("%pd %pd\n", h_dentry, h_path->dentry);
-+	/* no delegation since it is just created */
-+	err = vfsub_rename(h_dir, h_dentry, h_dir, h_path, /*delegated*/NULL,
-+			   /*flags*/0);
++	err = vfsub_rename(h_dir, h_dentry, h_dir, h_path, /*flags*/0);
 +	dput(h_path->dentry);
 +
 +out:
@@ -5586,7 +5271,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +	aufs_bindex_t old_ibtop;
 +	unsigned char isdir, plink;
 +	struct dentry *h_src, *h_dst, *h_parent;
-+	struct inode *dst_inode, *h_dir, *inode, *delegated, *src_inode;
++	struct inode *dst_inode, *h_dir, *inode, *src_inode;
 +	struct super_block *sb;
 +	struct au_branch *br;
 +	struct path h_src_path;
@@ -5619,6 +5304,10 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +	else
 +		dget(dst_parent);
 +
++	err = vfsub_mnt_want_write(a->h_path.mnt);
++	if (unlikely(err))
++		goto out_parent;
++
 +	plink = !!au_opt_test(au_mntflags(sb), PLINK);
 +	dst_inode = au_h_iptr(inode, cpg->bdst);
 +	if (dst_inode) {
@@ -5627,7 +5316,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +			AuIOErr("hi%lu(i%lu) exists on b%d "
 +				"but plink is disabled\n",
 +				dst_inode->i_ino, inode->i_ino, cpg->bdst);
-+			goto out_parent;
++			goto out_mnt_write;
 +		}
 +
 +		if (vfsub_inode_nlink(dst_inode, AU_I_BRANCH)) {
@@ -5636,14 +5325,14 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +			h_src = au_plink_lkup(inode, cpg->bdst);
 +			err = PTR_ERR(h_src);
 +			if (IS_ERR(h_src))
-+				goto out_parent;
++				goto out_mnt_write;
 +			if (unlikely(d_is_negative(h_src))) {
 +				err = -EIO;
 +				AuIOErr("i%lu exists on b%d "
 +					"but not pseudo-linked\n",
 +					inode->i_ino, cpg->bdst);
 +				dput(h_src);
-+				goto out_parent;
++				goto out_mnt_write;
 +			}
 +
 +			if (do_dt) {
@@ -5652,19 +5341,13 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +			}
 +
 +			a->h_path.dentry = h_dst;
-+			delegated = NULL;
-+			err = vfsub_link(h_src, h_dir, &a->h_path, &delegated);
++			err = vfsub_link(h_src, h_dir, &a->h_path);
 +			if (!err && au_ftest_cpup(cpg->flags, RENAME))
 +				err = au_do_ren_after_cpup(cpg, &a->h_path);
 +			if (do_dt)
 +				au_dtime_revert(&a->dt);
-+			if (unlikely(err == -EWOULDBLOCK)) {
-+				pr_warn("cannot retry for NFSv4 delegation"
-+					" for an internal link\n");
-+				iput(delegated);
-+			}
 +			dput(h_src);
-+			goto out_parent;
++			goto out_mnt_write;
 +		} else
 +			/* todo: cpup_wh_file? */
 +			/* udba work */
@@ -5716,7 +5399,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +	src_inode = d_inode(h_src);
 +	if (!isdir
 +	    && (vfsub_inode_nlink(src_inode, AU_I_BRANCH) > 1
-+		|| src_inode->i_state & I_LINKABLE)
++		|| au_ii(inode)->ii_tmpfile)
 +	    && plink)
 +		au_plink_append(inode, cpg->bdst, h_dst);
 +
@@ -5725,7 +5408,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +		err = au_do_ren_after_cpup(cpg, &a->h_path);
 +	}
 +	if (!err)
-+		goto out_parent; /* success */
++		goto out_mnt_write; /* success */
 +
 +	/* revert */
 +out_rev:
@@ -5735,9 +5418,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +	rerr = 0;
 +	if (d_is_positive(h_dst)) {
 +		if (!isdir) {
-+			/* no delegation since it is just created */
-+			rerr = vfsub_unlink(h_dir, &a->h_path,
-+					    /*delegated*/NULL, /*force*/0);
++			rerr = vfsub_unlink(h_dir, &a->h_path, /*force*/0);
 +		} else
 +			rerr = vfsub_rmdir(h_dir, &a->h_path);
 +	}
@@ -5746,6 +5427,8 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +		AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr);
 +		err = -EIO;
 +	}
++out_mnt_write:
++	vfsub_mnt_drop_write(a->h_path.mnt);
 +out_parent:
 +	dput(dst_parent);
 +	au_kfree_rcu(a);
@@ -6024,12 +5707,14 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +	if (unlikely(err))
 +		goto out_wh;
 +
++	err = vfsub_mnt_want_write(h_path.mnt);
++	if (unlikely(err))
++		goto out_wh;
++
 +	dget(wh_dentry);
 +	h_path.dentry = wh_dentry;
 +	if (!d_is_dir(wh_dentry)) {
-+		/* no delegation since it is just created */
-+		err = vfsub_unlink(d_inode(h_parent), &h_path,
-+				   /*delegated*/NULL, /*force*/0);
++		err = vfsub_unlink(d_inode(h_parent), &h_path, /*force*/0);
 +	} else
 +		err = vfsub_rmdir(d_inode(h_parent), &h_path);
 +	if (unlikely(err)) {
@@ -6038,6 +5723,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c
 +		err = -EIO;
 +	}
 +	au_dtime_revert(&dt);
++	vfsub_mnt_drop_write(h_path.mnt);
 +	au_set_hi_wh(d_inode(dentry), bdst, wh_dentry);
 +
 +out_wh:
@@ -6350,7 +6036,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.h linux/fs/aufs/cpup.h
 +#endif /* __AUFS_CPUP_H__ */
 diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c
 --- /usr/share/empty/fs/aufs/dbgaufs.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dbgaufs.c	2025-06-19 20:53:32.793295933 +0200
++++ linux/fs/aufs/dbgaufs.c	2025-12-01 15:04:46.893333378 +0100
 @@ -0,0 +1,526 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
@@ -7166,7 +6852,7 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.c linux/fs/aufs/dcsub.c
 +}
 diff -urN /usr/share/empty/fs/aufs/dcsub.h linux/fs/aufs/dcsub.h
 --- /usr/share/empty/fs/aufs/dcsub.h	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dcsub.h	2025-02-04 20:03:40.676605172 +0100
++++ linux/fs/aufs/dcsub.h	2025-12-01 15:04:46.893333378 +0100
 @@ -0,0 +1,139 @@
 +/* SPDX-License-Identifier: GPL-2.0 */
 +/*
@@ -7991,8 +7677,8 @@ diff -urN /usr/share/empty/fs/aufs/debug.h linux/fs/aufs/debug.h
 +#endif /* __AUFS_DEBUG_H__ */
 diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c
 --- /usr/share/empty/fs/aufs/dentry.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dentry.c	2025-06-19 20:53:32.793295933 +0200
-@@ -0,0 +1,1176 @@
++++ linux/fs/aufs/dentry.c	2026-02-08 10:11:28.889988407 +0100
+@@ -0,0 +1,1178 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Copyright (C) 2005-2025 Junjiro R. Okajima
@@ -9108,8 +8794,10 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c
 +	err = -EINVAL;
 +	if (!(flags & (LOOKUP_OPEN | LOOKUP_EMPTY))
 +	    && inode
-+	    && !(inode->i_state && I_LINKABLE)
-+	    && (IS_DEADDIR(inode) || !vfsub_inode_nlink(inode, AU_I_AUFS))) {
++	    && (IS_DEADDIR(inode)
++		|| (!vfsub_inode_nlink(inode, AU_I_AUFS)
++		    && !au_ii(inode)->ii_tmpfile))
++		) {
 +		AuTraceErr(err);
 +		goto out_inval;
 +	}
@@ -9171,7 +8859,7 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c
 +};
 diff -urN /usr/share/empty/fs/aufs/dentry.h linux/fs/aufs/dentry.h
 --- /usr/share/empty/fs/aufs/dentry.h	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dentry.h	2025-07-24 19:31:57.789847457 +0200
++++ linux/fs/aufs/dentry.h	2025-12-01 15:04:46.896666712 +0100
 @@ -0,0 +1,270 @@
 +/* SPDX-License-Identifier: GPL-2.0 */
 +/*
@@ -10911,8 +10599,8 @@ diff -urN /usr/share/empty/fs/aufs/dir.h linux/fs/aufs/dir.h
 +#endif /* __AUFS_DIR_H__ */
 diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c
 --- /usr/share/empty/fs/aufs/dirren.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dirren.c	2025-02-04 20:03:40.676605172 +0100
-@@ -0,0 +1,1315 @@
++++ linux/fs/aufs/dirren.c	2026-02-08 10:11:28.889988407 +0100
+@@ -0,0 +1,1308 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Copyright (C) 2017-2025 Junjiro R. Okajima
@@ -11148,7 +10836,7 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c
 +	unsigned char load, suspend;
 +	struct file *hinofile;
 +	struct au_hinode *hdir;
-+	struct inode *dir, *delegated;
++	struct inode *dir;
 +	struct path hinopath;
 +	struct qstr hinoname = QSTR_INIT(AUFS_WH_DR_BRHINO,
 +					 sizeof(AUFS_WH_DR_BRHINO) - 1);
@@ -11190,27 +10878,28 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c
 +		if (d_is_negative(hinopath.dentry))
 +			goto out_dput; /* success */
 +	} else {
++		err = vfsub_mnt_want_write(hinopath.mnt);
++		AuTraceErr(err);
++		if (unlikely(err))
++			goto out_dput;
 +		if (au_dr_hino_test_empty(&br->br_dirren)) {
 +			if (d_is_positive(hinopath.dentry)) {
-+				delegated = NULL;
-+				err = vfsub_unlink(dir, &hinopath, &delegated,
-+						   /*force*/0);
++				err = vfsub_unlink(dir, &hinopath, /*force*/0);
 +				AuTraceErr(err);
 +				if (unlikely(err))
 +					pr_err("ignored err %d, %pd2\n",
 +					       err, hinopath.dentry);
-+				if (unlikely(err == -EWOULDBLOCK))
-+					iput(delegated);
 +				err = 0;
 +			}
-+			goto out_dput;
++			goto out_mnt_write;
 +		} else if (!d_is_positive(hinopath.dentry)) {
 +			err = vfsub_create(dir, &hinopath, 0600,
 +					   /*want_excl*/false);
 +			AuTraceErr(err);
 +			if (unlikely(err))
-+				goto out_dput;
++				goto out_mnt_write;
 +		}
++		vfsub_mnt_drop_write(hinopath.mnt);
 +		flags = O_WRONLY;
 +	}
 +	hinofile = vfsub_dentry_open(&hinopath, flags);
@@ -11232,6 +10921,8 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c
 +	fput(hinofile);
 +	goto out;
 +
++out_mnt_write:
++	vfsub_mnt_drop_write(hinopath.mnt);
 +out_dput:
 +	dput(hinopath.dentry);
 +out_unlock:
@@ -11527,7 +11218,7 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c
 +	struct path infopath = {
 +		.mnt = w->h_ppath.mnt
 +	};
-+	struct inode *h_dir, *h_inode, *delegated;
++	struct inode *h_dir, *h_inode;
 +	struct file *infofile;
 +	struct qstr *qname;
 +
@@ -11574,11 +11265,8 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c
 +	}
 +
 +	if (elm && w->renameback) {
-+		delegated = NULL;
-+		err = vfsub_unlink(h_dir, &infopath, &delegated, /*force*/0);
++		err = vfsub_unlink(h_dir, &infopath, /*force*/0);
 +		AuTraceErr(err);
-+		if (unlikely(err == -EWOULDBLOCK))
-+			iput(delegated);
 +		goto out_fput;
 +	}
 +
@@ -11678,7 +11366,7 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c
 +				struct au_drinfo_store *w)
 +{
 +	struct au_drinfo_rev_elm *elm;
-+	struct inode *h_dir, *delegated;
++	struct inode *h_dir;
 +	int err, nelm;
 +	struct path infopath = {
 +		.mnt = w->h_ppath.mnt
@@ -11693,13 +11381,9 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c
 +		AuDebugOn(elm->created && elm->info_last);
 +		if (elm->created) {
 +			AuDbg("here\n");
-+			delegated = NULL;
 +			infopath.dentry = elm->info_dentry;
-+			err = vfsub_unlink(h_dir, &infopath, &delegated,
-+					   !w->no_sio);
++			err = vfsub_unlink(h_dir, &infopath, !w->no_sio);
 +			AuTraceErr(err);
-+			if (unlikely(err == -EWOULDBLOCK))
-+				iput(delegated);
 +			dput(elm->info_dentry);
 +		} else if (elm->info_last) {
 +			AuDbg("here\n");
@@ -11987,7 +11671,7 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c
 +		= AUFS_WH_DR_INFO_PFX;
 +	struct au_drinfo *drinfo;
 +	struct qstr oldname;
-+	struct inode *h_dir, *delegated;
++	struct inode *h_dir;
 +	struct dentry *info_dentry;
 +	struct path infopath;
 +
@@ -12024,14 +11708,11 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c
 +		infopath.dentry = info_dentry;
 +		infopath.mnt = w->h_ppath.mnt;
 +		h_dir = d_inode(w->h_ppath.dentry);
-+		delegated = NULL;
 +		inode_lock_nested(h_dir, AuLsc_I_PARENT);
-+		e = vfsub_unlink(h_dir, &infopath, &delegated, !w->no_sio);
++		e = vfsub_unlink(h_dir, &infopath, !w->no_sio);
 +		inode_unlock(h_dir);
 +		if (unlikely(e))
 +			AuIOErr("ignored %d, %pd2\n", e, &infopath.dentry);
-+		if (unlikely(e == -EWOULDBLOCK))
-+			iput(delegated);
 +	}
 +	au_kfree_rcu(w->drinfo[bindex]);
 +	w->drinfo[bindex] = drinfo;
@@ -12230,7 +11911,7 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c
 +}
 diff -urN /usr/share/empty/fs/aufs/dirren.h linux/fs/aufs/dirren.h
 --- /usr/share/empty/fs/aufs/dirren.h	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dirren.h	2025-02-04 20:03:40.676605172 +0100
++++ linux/fs/aufs/dirren.h	2025-12-01 15:04:46.896666712 +0100
 @@ -0,0 +1,140 @@
 +/* SPDX-License-Identifier: GPL-2.0 */
 +/*
@@ -12374,7 +12055,7 @@ diff -urN /usr/share/empty/fs/aufs/dirren.h linux/fs/aufs/dirren.h
 +#endif /* __AUFS_DIRREN_H__ */
 diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c
 --- /usr/share/empty/fs/aufs/dynop.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/dynop.c	2025-07-24 19:31:57.789847457 +0200
++++ linux/fs/aufs/dynop.c	2025-12-01 15:04:46.896666712 +0100
 @@ -0,0 +1,365 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
@@ -12824,7 +12505,7 @@ diff -urN /usr/share/empty/fs/aufs/dynop.h linux/fs/aufs/dynop.h
 +#endif /* __AUFS_DYNOP_H__ */
 diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c
 --- /usr/share/empty/fs/aufs/export.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/export.c	2025-07-24 19:31:57.789847457 +0200
++++ linux/fs/aufs/export.c	2025-12-01 15:04:46.896666712 +0100
 @@ -0,0 +1,846 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
@@ -14104,8 +13785,8 @@ diff -urN /usr/share/empty/fs/aufs/fhsm.c linux/fs/aufs/fhsm.c
 +}
 diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
 --- /usr/share/empty/fs/aufs/file.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/file.c	2025-07-24 19:31:57.789847457 +0200
-@@ -0,0 +1,858 @@
++++ linux/fs/aufs/file.c	2026-02-08 10:11:28.889988407 +0100
+@@ -0,0 +1,851 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Copyright (C) 2005-2025 Junjiro R. Okajima
@@ -14226,7 +13907,6 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
 +		.pin	= &pin,
 +		.flags	= AuCpup_DTIME | AuCpup_HOPEN
 +	};
-+	struct inode *delegated;
 +	struct super_block *sb;
 +	struct au_sbinfo *sbinfo;
 +	struct au_fhsm *fhsm;
@@ -14303,15 +13983,9 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
 +	h_path.mnt = au_br_mnt(br);
 +	h_path.dentry = au_h_dptr(dentry, cpg.bsrc);
 +	hdir = au_hi(d_inode(parent), cpg.bsrc);
-+	delegated = NULL;
-+	err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, /*force*/1);
++	err = vfsub_unlink(hdir->hi_inode, &h_path, /*force*/1);
 +	au_unpin(&pin);
 +	/* todo: keep h_dentry or not? */
-+	if (unlikely(err == -EWOULDBLOCK)) {
-+		pr_warn("cannot retry for NFSv4 delegation"
-+			" for an internal unlink\n");
-+		iput(delegated);
-+	}
 +	if (unlikely(err)) {
 +		pr_err("unlink %pd after coo failed (%d), ignored\n",
 +		       dentry, err);
@@ -14507,7 +14181,7 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
 +
 +	if (!err
 +	    && (vfsub_inode_nlink(inode, AU_I_AUFS) > 1
-+		|| (inode->i_state & I_LINKABLE))
++		|| au_ii(inode)->ii_tmpfile)
 +	    && au_opt_test(au_mntflags(cpg.dentry->d_sb), PLINK))
 +		au_plink_append(inode, bcpup, au_h_dptr(cpg.dentry, bcpup));
 +
@@ -14966,8 +14640,8 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c
 +};
 diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h
 --- /usr/share/empty/fs/aufs/file.h	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/file.h	2025-02-04 20:03:40.679938505 +0100
-@@ -0,0 +1,342 @@
++++ linux/fs/aufs/file.h	2025-12-01 15:04:47.560000045 +0100
+@@ -0,0 +1,327 @@
 +/* SPDX-License-Identifier: GPL-2.0 */
 +/*
 + * Copyright (C) 2005-2025 Junjiro R. Okajima
@@ -15031,6 +14705,7 @@ diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h
 +	struct {				/* for non-dir */
 +		struct au_hfile			fi_htop;
 +		atomic_t			fi_mmapped;
++		struct hlist_bl_node		fi_mf;
 +	};
 +	struct au_fidir		*fi_hdir;	/* for dir only */
 +
@@ -15086,6 +14761,16 @@ diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h
 +int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file);
 +struct file *au_read_pre(struct file *file, int keep_fi, unsigned int lsc);
 +
++/* mf.c */
++void au_mf_add(struct file *h_file, struct file *file);
++void au_mf_del(struct file *h_file, struct file *file);
++#if IS_MODULE(CONFIG_AUFS_FS)
++const struct path *au_do_file_user_path(struct file *h_file);
++const struct inode *au_do_file_user_inode(struct file *h_file);
++#elif IS_BUILTIN(CONFIG_AUFS_FS)
++/* declared in include/linux/fs.h */
++#endif
++
 +/* finfo.c */
 +void au_hfput(struct au_hfile *hf, int execed);
 +void au_set_h_fptr(struct file *file, aufs_bindex_t bindex,
@@ -15259,25 +14944,13 @@ diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h
 +}
 +
 +/* customize vma->vm_file */
-+
-+static inline void au_do_vm_file_reset(struct vm_area_struct *vma,
-+				       struct file *file)
-+{
-+	struct file *f;
-+
-+	f = vma->vm_file;
-+	get_file(file);
-+	vma->vm_file = file;
-+	fput(f);
-+}
-+
 +#ifdef CONFIG_MMU
 +AuStubVoid(AuDbgVmRegion, struct file *file, struct vm_area_struct *vma)
 +
 +static inline void au_vm_file_reset(struct vm_area_struct *vma,
 +				    struct file *file)
 +{
-+	au_do_vm_file_reset(vma, file);
++	vma_set_file(vma, file);
 +}
 +#else
 +#define AuDbgVmRegion(file, vma) \
@@ -15286,34 +14959,20 @@ diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h
 +static inline void au_vm_file_reset(struct vm_area_struct *vma,
 +				    struct file *file)
 +{
-+	struct file *f;
++	vma_set_file(vma, file);
 +
-+	au_do_vm_file_reset(vma, file);
-+	f = vma->vm_region->vm_file;
 +	get_file(file);
-+	vma->vm_region->vm_file = file;
-+	fput(f);
++	swap(vma->vm_region->vm_file, file);
++	fput(file);
 +}
 +#endif /* CONFIG_MMU */
 +
-+/* handle vma->vm_prfile */
-+static inline void au_vm_prfile_set(struct vm_area_struct *vma,
-+				    struct file *file)
-+{
-+	get_file(file);
-+	vma->vm_prfile = file;
-+#ifndef CONFIG_MMU
-+	get_file(file);
-+	vma->vm_region->vm_prfile = file;
-+#endif
-+}
-+
 +#endif /* __KERNEL__ */
 +#endif /* __AUFS_FILE_H__ */
 diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c
 --- /usr/share/empty/fs/aufs/finfo.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/finfo.c	2025-07-24 19:31:57.789847457 +0200
-@@ -0,0 +1,147 @@
++++ linux/fs/aufs/finfo.c	2025-12-01 15:04:47.560000045 +0100
+@@ -0,0 +1,148 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Copyright (C) 2005-2025 Junjiro R. Okajima
@@ -15452,6 +15111,7 @@ diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c
 +	au_lcnt_inc(&au_sbi(dentry->d_sb)->si_nfiles);
 +	au_rw_write_lock(&finfo->fi_rwsem);
 +	finfo->fi_btop = -1;
++	INIT_HLIST_BL_NODE(&finfo->fi_mf);
 +	finfo->fi_hdir = fidir;
 +	atomic_set(&finfo->fi_generation, au_digen(dentry));
 +	/* smp_mb(); */ /* atomic_set */
@@ -15463,8 +15123,8 @@ diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c
 +}
 diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 --- /usr/share/empty/fs/aufs/f_op.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/f_op.c	2025-02-04 20:03:40.676605172 +0100
-@@ -0,0 +1,782 @@
++++ linux/fs/aufs/f_op.c	2025-12-01 15:04:47.556666712 +0100
+@@ -0,0 +1,791 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Copyright (C) 2005-2025 Junjiro R. Okajima
@@ -15574,13 +15234,21 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +{
 +	struct au_finfo *finfo;
 +	aufs_bindex_t bindex;
++	struct file *h_file;
 +
 +	finfo = au_fi(file);
 +	au_hbl_del(&finfo->fi_hlist,
 +		   &au_sbi(file->f_path.dentry->d_sb)->si_files);
 +	bindex = finfo->fi_btop;
-+	if (bindex >= 0)
++	if (bindex >= 0) {
++		if (au_test_mmapped(file)) {
++			/* h_file = au_hf_top(file); */
++			h_file = finfo->fi_htop.hf_file;
++			if (h_file)
++				au_mf_del(h_file, file);
++		}
 +		au_set_h_fptr(file, bindex, NULL);
++	}
 +
 +	au_finfo_fin(file);
 +	return 0;
@@ -15691,7 +15359,8 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +	if (do_ready)
 +		au_unpin(&pin);
 +	di_read_unlock(dentry, /*flags*/0);
-+	vfsub_file_start_write(h_file);
++	if (do_ready)
++		vfsub_file_start_write(h_file);
 +
 +out_fi:
 +	fi_write_unlock(file);
@@ -16095,7 +15764,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +	lockdep_off();
 +	si_read_lock(sb, AuLock_NOPLMW);
 +
-+	h_file = au_write_pre(file, wlock, /*wpre*/NULL);
++	h_file = au_write_pre(file, /*do_ready*/wlock, /*wpre*/NULL);
 +	lockdep_on();
 +	err = PTR_ERR(h_file);
 +	if (IS_ERR(h_file))
@@ -16114,7 +15783,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +	if (!err)
 +		err = call_mmap(h_file, vma);
 +	if (!err) {
-+		au_vm_prfile_set(vma, file);
++		au_mf_add(h_file, file);
 +		fsstack_copy_attr_atime(inode, file_inode(h_file));
 +		goto out_fput; /* success */
 +	}
@@ -16249,7 +15918,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c
 +};
 diff -urN /usr/share/empty/fs/aufs/fsctx.c linux/fs/aufs/fsctx.c
 --- /usr/share/empty/fs/aufs/fsctx.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/fsctx.c	2025-07-24 19:31:57.793180791 +0200
++++ linux/fs/aufs/fsctx.c	2025-12-01 15:04:46.896666712 +0100
 @@ -0,0 +1,1244 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
@@ -18347,7 +18016,7 @@ diff -urN /usr/share/empty/fs/aufs/hfsplus.c linux/fs/aufs/hfsplus.c
 +}
 diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c
 --- /usr/share/empty/fs/aufs/hnotify.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/hnotify.c	2025-07-24 19:31:57.793180791 +0200
++++ linux/fs/aufs/hnotify.c	2025-12-01 15:04:46.896666712 +0100
 @@ -0,0 +1,715 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
@@ -19066,8 +18735,8 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c
 +}
 diff -urN /usr/share/empty/fs/aufs/iinfo.c linux/fs/aufs/iinfo.c
 --- /usr/share/empty/fs/aufs/iinfo.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/iinfo.c	2025-02-04 20:03:40.679938505 +0100
-@@ -0,0 +1,287 @@
++++ linux/fs/aufs/iinfo.c	2026-02-08 10:11:28.889988407 +0100
+@@ -0,0 +1,288 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Copyright (C) 2005-2025 Junjiro R. Okajima
@@ -19218,7 +18887,7 @@ diff -urN /usr/share/empty/fs/aufs/iinfo.c linux/fs/aufs/iinfo.c
 +			h_i = au_hinode(iinfo, bindex)->hi_inode;
 +			if (h_i
 +			    && !vfsub_inode_nlink(h_i, AU_I_BRANCH)
-+			    && !(h_i->i_state & I_LINKABLE))
++			    && !iinfo->ii_tmpfile)
 +				au_set_h_iptr(inode, bindex, NULL, 0);
 +		}
 +	}
@@ -19284,6 +18953,7 @@ diff -urN /usr/share/empty/fs/aufs/iinfo.c linux/fs/aufs/iinfo.c
 +		iinfo->ii_generation.ig_generation = au_sigen(sb);
 +		iinfo->ii_btop = -1;
 +		iinfo->ii_bbot = -1;
++		iinfo->ii_tmpfile = 0;
 +		iinfo->ii_vdir = NULL;
 +		return 0;
 +	}
@@ -19893,8 +19563,8 @@ diff -urN /usr/share/empty/fs/aufs/inode.c linux/fs/aufs/inode.c
 +}
 diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h
 --- /usr/share/empty/fs/aufs/inode.h	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/inode.h	2025-07-24 19:31:57.793180791 +0200
-@@ -0,0 +1,727 @@
++++ linux/fs/aufs/inode.h	2026-02-08 10:11:28.889988407 +0100
+@@ -0,0 +1,728 @@
 +/* SPDX-License-Identifier: GPL-2.0 */
 +/*
 + * Copyright (C) 2005-2025 Junjiro R. Okajima
@@ -19970,6 +19640,7 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h
 +
 +	struct au_rwsem		ii_rwsem;
 +	aufs_bindex_t		ii_btop, ii_bbot;
++	unsigned char		ii_tmpfile;	/* born with nlink == 0 */
 +	__u32			ii_higen;
 +	struct au_hinode	*ii_hinode;
 +	struct au_vdir		*ii_vdir;
@@ -20624,7 +20295,7 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h
 +#endif /* __AUFS_INODE_H__ */
 diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c
 --- /usr/share/empty/fs/aufs/ioctl.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/ioctl.c	2025-02-04 20:03:40.679938505 +0100
++++ linux/fs/aufs/ioctl.c	2025-12-01 15:04:46.896666712 +0100
 @@ -0,0 +1,220 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
@@ -20848,8 +20519,8 @@ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c
 +#endif
 diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 --- /usr/share/empty/fs/aufs/i_op_add.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/i_op_add.c	2025-06-19 20:53:32.793295933 +0200
-@@ -0,0 +1,971 @@
++++ linux/fs/aufs/i_op_add.c	2026-02-08 10:11:28.889988407 +0100
+@@ -0,0 +1,947 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Copyright (C) 2005-2025 Junjiro R. Okajima
@@ -21184,9 +20855,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +
 +	/* revert */
 +	if (created /* && d_is_positive(a->h_path.dentry) */) {
-+		/* no delegation since it is just created */
-+		rerr = vfsub_unlink(h_dir, &a->h_path, /*delegated*/NULL,
-+				    /*force*/0);
++		rerr = vfsub_unlink(h_dir, &a->h_path, /*force*/0);
 +		if (rerr) {
 +			AuIOErr("%pd revert failure(%d, %d)\n",
 +				dentry, err, rerr);
@@ -21357,6 +21026,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +	}
 +
 +	vfsub_inode_nlink_init(inode, 1);
++	au_ii(inode)->ii_tmpfile = 1;
 +	d_tmpfile(file, inode);
 +	au_di(dentry)->di_tmpfile = 1;
 +	get_file(h_file);
@@ -21451,7 +21121,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +	unsigned char plink;
 +	aufs_bindex_t bbot;
 +	struct dentry *h_src_dentry;
-+	struct inode *h_inode, *inode, *delegated;
++	struct inode *h_inode, *inode;
 +	struct super_block *sb;
 +	struct file *h_file;
 +
@@ -21518,14 +21188,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +
 +		}
 +		if (h_src_dentry) {
-+			delegated = NULL;
 +			err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin),
-+					 &a->h_path, &delegated);
-+			if (unlikely(err == -EWOULDBLOCK)) {
-+				pr_warn("cannot retry for NFSv4 delegation"
-+					" for an internal link\n");
-+				iput(delegated);
-+			}
++					 &a->h_path);
 +			dput(h_src_dentry);
 +		} else {
 +			AuIOErr("no dentry found for hi%lu on b%d\n",
@@ -21549,7 +21213,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +	struct au_dtime dt;
 +	struct au_link_args *a;
 +	struct dentry *wh_dentry, *h_src_dentry;
-+	struct inode *inode, *delegated;
++	struct inode *inode;
 +	struct super_block *sb;
 +	struct au_wr_dir_args wr_dir_args = {
 +		/* .force_btgt	= -1, */
@@ -21614,16 +21278,9 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +		if (a->bdst < a->bsrc
 +		    /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */)
 +			err = au_cpup_or_link(src_dentry, dentry, a);
-+		else {
-+			delegated = NULL;
++		else
 +			err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin),
-+					 &a->h_path, &delegated);
-+			if (unlikely(err == -EWOULDBLOCK)) {
-+				pr_warn("cannot retry for NFSv4 delegation"
-+					" for an internal link\n");
-+				iput(delegated);
-+			}
-+		}
++					 &a->h_path);
 +		dput(h_src_dentry);
 +	} else {
 +		/*
@@ -21647,18 +21304,10 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +		if (!err) {
 +			h_src_dentry = au_h_dptr(src_dentry, a->bdst);
 +			err = -ENOENT;
-+			if (h_src_dentry && d_is_positive(h_src_dentry)) {
-+				delegated = NULL;
++			if (h_src_dentry && d_is_positive(h_src_dentry))
 +				err = vfsub_link(h_src_dentry,
 +						 au_pinned_h_dir(&a->pin),
-+						 &a->h_path, &delegated);
-+				if (unlikely(err == -EWOULDBLOCK)) {
-+					pr_warn("cannot retry"
-+						" for NFSv4 delegation"
-+						" for an internal link\n");
-+					iput(delegated);
-+				}
-+			}
++						 &a->h_path);
 +		}
 +	}
 +	if (unlikely(err))
@@ -21685,9 +21334,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +	goto out_unpin; /* success */
 +
 +out_revert:
-+	/* no delegation since it is just created */
-+	rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path,
-+			    /*delegated*/NULL, /*force*/0);
++	rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, /*force*/0);
 +	if (unlikely(rerr)) {
 +		AuIOErr("%pd reverting failed(%d, %d)\n", dentry, err, rerr);
 +		err = -EIO;
@@ -21823,8 +21470,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c
 +}
 diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 --- /usr/share/empty/fs/aufs/i_op.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/i_op.c	2025-07-24 19:31:57.793180791 +0200
-@@ -0,0 +1,1526 @@
++++ linux/fs/aufs/i_op.c	2026-02-08 10:11:28.889988407 +0100
+@@ -0,0 +1,1522 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Copyright (C) 2005-2025 Junjiro R. Okajima
@@ -22766,7 +22413,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +			struct iattr *ia)
 +{
 +	int err;
-+	struct inode *inode, *delegated;
++	struct inode *inode;
 +	struct super_block *sb;
 +	struct file *file;
 +	struct au_icpup_args *a;
@@ -22827,16 +22474,20 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +	}
 +
 +	a->h_path.mnt = au_sbr_mnt(sb, a->btgt);
++	err = vfsub_mnt_want_write(a->h_path.mnt);
++	if (unlikely(err))
++		goto out_unlock;
++
 +	if ((ia->ia_valid & (ATTR_MODE | ATTR_CTIME))
 +	    == (ATTR_MODE | ATTR_CTIME)) {
 +		err = security_path_chmod(&a->h_path, ia->ia_mode);
 +		if (unlikely(err))
-+			goto out_unlock;
++			goto out_mnt_write;
 +	} else if ((ia->ia_valid & (ATTR_UID | ATTR_GID))
 +		   && (ia->ia_valid & ATTR_CTIME)) {
 +		err = security_path_chown(&a->h_path, ia->ia_uid, ia->ia_gid);
 +		if (unlikely(err))
-+			goto out_unlock;
++			goto out_mnt_write;
 +	}
 +
 +	if (ia->ia_valid & ATTR_SIZE) {
@@ -22852,18 +22503,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +		inode_unlock(a->h_inode);
 +		err = vfsub_trunc(&a->h_path, ia->ia_size, ia->ia_valid, f);
 +		inode_lock_nested(a->h_inode, AuLsc_I_CHILD);
-+	} else {
-+		delegated = NULL;
-+		while (1) {
-+			err = vfsub_notify_change(&a->h_path, ia, &delegated);
-+			if (delegated) {
-+				err = break_deleg_wait(&delegated);
-+				if (!err)
-+					continue;
-+			}
-+			break;
-+		}
-+	}
++	} else
++		err = vfsub_notify_change(&a->h_path, ia);
 +	/*
 +	 * regardless aufs 'acl' option setting.
 +	 * why don't all acl-aware fs call this func from their ->setattr()?
@@ -22875,6 +22516,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +	if (!err)
 +		au_cpup_attr_changeable(inode);
 +
++out_mnt_write:
++	vfsub_mnt_drop_write(a->h_path.mnt);
 +out_unlock:
 +	inode_unlock(a->h_inode);
 +	au_unpin(&a->pin);
@@ -23353,8 +22996,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c
 +};
 diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c
 --- /usr/share/empty/fs/aufs/i_op_del.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/i_op_del.c	2025-02-04 20:03:40.679938505 +0100
-@@ -0,0 +1,523 @@
++++ linux/fs/aufs/i_op_del.c	2026-02-08 10:11:28.889988407 +0100
+@@ -0,0 +1,517 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Copyright (C) 2005-2025 Junjiro R. Okajima
@@ -23670,7 +23313,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c
 +{
 +	int err;
 +	aufs_bindex_t bwh, bindex, btop;
-+	struct inode *inode, *h_dir, *delegated, *h_inode;
++	struct inode *inode, *h_dir, *h_inode;
 +	struct dentry *parent, *wh_dentry;
 +	/* to reduce stack size */
 +	struct {
@@ -23714,13 +23357,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c
 +	dget(a->h_path.dentry);
 +	if (bindex == btop) {
 +		h_dir = au_pinned_h_dir(&a->pin);
-+		delegated = NULL;
-+		err = vfsub_unlink(h_dir, &a->h_path, &delegated, /*force*/0);
-+		if (unlikely(err == -EWOULDBLOCK)) {
-+			pr_warn("cannot retry for NFSv4 delegation"
-+				" for an internal unlink\n");
-+			iput(delegated);
-+		}
++		err = vfsub_unlink(h_dir, &a->h_path, /*force*/0);
 +	} else {
 +		/* dir inode is locked */
 +		h_dir = d_inode(wh_dentry->d_parent);
@@ -23880,8 +23517,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c
 +}
 diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c
 --- /usr/share/empty/fs/aufs/i_op_ren.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/i_op_ren.c	2025-07-24 19:31:57.793180791 +0200
-@@ -0,0 +1,1264 @@
++++ linux/fs/aufs/i_op_ren.c	2026-02-08 10:11:28.889988407 +0100
+@@ -0,0 +1,1242 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Copyright (C) 2005-2025 Junjiro R. Okajima
@@ -24033,7 +23670,6 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c
 +static void au_ren_rev_rename(int err, struct au_ren_args *a)
 +{
 +	int rerr;
-+	struct inode *delegated;
 +	struct path h_ppath = {
 +		.dentry	= a->src_h_parent,
 +		.mnt	= a->h_path.mnt
@@ -24046,15 +23682,9 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c
 +		return;
 +	}
 +
-+	delegated = NULL;
 +	rerr = vfsub_rename(a->dst_h_dir,
 +			    au_h_dptr(a->src_dentry, a->btgt),
-+			    a->src_h_dir, &a->h_path, &delegated, a->flags);
-+	if (unlikely(rerr == -EWOULDBLOCK)) {
-+		pr_warn("cannot retry for NFSv4 delegation"
-+			" for an internal rename\n");
-+		iput(delegated);
-+	}
++			    a->src_h_dir, &a->h_path, a->flags);
 +	d_drop(a->h_path.dentry);
 +	dput(a->h_path.dentry);
 +	/* au_set_h_dptr(a->src_dentry, a->btgt, NULL); */
@@ -24065,7 +23695,6 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c
 +static void au_ren_rev_whtmp(int err, struct au_ren_args *a)
 +{
 +	int rerr;
-+	struct inode *delegated;
 +	struct path h_ppath = {
 +		.dentry	= a->dst_h_parent,
 +		.mnt	= a->h_path.mnt
@@ -24083,14 +23712,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c
 +		return;
 +	}
 +
-+	delegated = NULL;
 +	rerr = vfsub_rename(a->dst_h_dir, a->h_dst, a->dst_h_dir, &a->h_path,
-+			    &delegated, a->flags);
-+	if (unlikely(rerr == -EWOULDBLOCK)) {
-+		pr_warn("cannot retry for NFSv4 delegation"
-+			" for an internal rename\n");
-+		iput(delegated);
-+	}
++			    a->flags);
 +	d_drop(a->h_path.dentry);
 +	dput(a->h_path.dentry);
 +	if (!rerr)
@@ -24122,21 +23745,13 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c
 +{
 +	int err;
 +	struct dentry *d;
-+	struct inode *delegated;
 +
 +	d = a->src_dentry;
 +	if (au_dbtop(d) == a->btgt) {
 +		a->h_path.dentry = a->dst_h_dentry;
 +		AuDebugOn(au_dbtop(d) != a->btgt);
-+		delegated = NULL;
 +		err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt),
-+				   a->dst_h_dir, &a->h_path, &delegated,
-+				   a->flags);
-+		if (unlikely(err == -EWOULDBLOCK)) {
-+			pr_warn("cannot retry for NFSv4 delegation"
-+				" for an internal rename\n");
-+			iput(delegated);
-+		}
++				   a->dst_h_dir, &a->h_path, a->flags);
 +	} else
 +		BUG();
 +
@@ -25789,7 +25404,7 @@ diff -urN /usr/share/empty/fs/aufs/magic.mk linux/fs/aufs/magic.mk
 +endif
 diff -urN /usr/share/empty/fs/aufs/Makefile linux/fs/aufs/Makefile
 --- /usr/share/empty/fs/aufs/Makefile	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/Makefile	2025-06-19 20:53:32.789962600 +0200
++++ linux/fs/aufs/Makefile	2025-12-01 15:04:47.556666712 +0100
 @@ -0,0 +1,46 @@
 +# SPDX-License-Identifier: GPL-2.0
 +
@@ -25815,7 +25430,7 @@ diff -urN /usr/share/empty/fs/aufs/Makefile linux/fs/aufs/Makefile
 +	cpup.o whout.o wbr_policy.o \
 +	dinfo.o dentry.o \
 +	dynop.o \
-+	finfo.o file.o f_op.o \
++	finfo.o file.o f_op.o mf.o \
 +	dir.o vdir.o \
 +	iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o \
 +	mvdown.o ioctl.o
@@ -25837,9 +25452,132 @@ diff -urN /usr/share/empty/fs/aufs/Makefile linux/fs/aufs/Makefile
 +aufs-$(CONFIG_AUFS_BR_HFSPLUS) += hfsplus.o
 +aufs-$(CONFIG_AUFS_DEBUG) += debug.o
 +aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o
+diff -urN /usr/share/empty/fs/aufs/mf.c linux/fs/aufs/mf.c
+--- /usr/share/empty/fs/aufs/mf.c	1970-01-01 01:00:00.000000000 +0100
++++ linux/fs/aufs/mf.c	2025-12-01 15:04:47.560000045 +0100
+@@ -0,0 +1,119 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2025 Junjiro R. Okajima
++ */
++
++/*
++ * mmapped files.
++ */
++
++#include "aufs.h"
++
++/*
++ * File hashtable.
++ * It identifies aufs file by branch's file as a key.
++ * Used by customized file_user_path() and file_user_inode() in
++ * include/linux/fs.h.
++ * This table doesn't make get/put call for the elements.
++ *
++ * INIT_HLIST_BL_HEAD() sets NULL to its member, so we can skip it since this is
++ * 'static'.
++ */
++#define N 0x0ff
++static struct hlist_bl_head au_mmapped_finfo[N + 1];
++
++static unsigned int au_mf_hash(struct file *h_file)
++{
++	uintptr_t ptr;
++
++	BUILD_BUG_ON(sizeof(ptr) < sizeof(h_file));
++	ptr = (uintptr_t)h_file;
++	return (ptr >> 8) & N;
++}
++
++void au_mf_add(struct file *h_file, struct file *file)
++{
++	struct au_finfo *finfo;
++	unsigned int hash;
++	struct hlist_bl_head *hbl_head;
++
++	finfo = au_fi(file);
++	AuDebugOn(!au_test_mmapped(file));
++	if (atomic_read(&finfo->fi_mmapped) == 1) {
++		hash = au_mf_hash(h_file);
++		hbl_head = au_mmapped_finfo + hash;
++		au_hbl_add(&finfo->fi_mf, hbl_head);
++	}
++}
++
++void au_mf_del(struct file *h_file, struct file *file)
++{
++	struct au_finfo *finfo;
++	unsigned int hash;
++	struct hlist_bl_head *hbl_head;
++
++	finfo = au_fi(file);
++	hash = au_mf_hash(h_file);
++	hbl_head = au_mmapped_finfo + hash;
++	au_hbl_del(&finfo->fi_mf, hbl_head);
++}
++
++static struct file *au_mf_find(struct file *h_file)
++{
++	struct file *found;
++	unsigned int hash;
++	struct hlist_bl_head *hbl_head;
++	struct hlist_bl_node *hbl_node;
++	struct au_finfo *finfo;
++	struct au_hfile *hfile;
++
++	found = NULL;
++	hash = au_mf_hash(h_file);
++	hbl_head = au_mmapped_finfo + hash;
++	hlist_bl_lock(hbl_head);
++	au_hbl_for_each(hbl_node, hbl_head) {
++		if (!hbl_node)
++			continue;
++
++		finfo = container_of(hbl_node, struct au_finfo, fi_mf);
++		hfile = &finfo->fi_htop;
++		if (hfile->hf_file == h_file) {
++			found = finfo->fi_file;
++			break;
++		}
++	}
++	hlist_bl_unlock(hbl_head);
++
++	return found;
++}
++
++/* ---------------------------------------------------------------------- */
++/* declared in include/linux/fs.h */
++
++const struct path *au_do_file_user_path(struct file *h_file)
++{
++	struct path *path;
++	struct file *file;
++
++	path = NULL;
++	file = au_mf_find(h_file);
++	if (file)
++		path = &file->f_path;
++
++	return path;
++}
++EXPORT_SYMBOL_GPL(au_do_file_user_path);
++
++const struct inode *au_do_file_user_inode(struct file *h_file)
++{
++	struct inode *inode;
++	struct file *file;
++
++	inode = NULL;
++	file = au_mf_find(h_file);
++	if (file)
++		inode = file->f_inode;
++
++	return inode;
++}
++EXPORT_SYMBOL_GPL(au_do_file_user_inode);
 diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c
 --- /usr/share/empty/fs/aufs/module.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/module.c	2025-02-04 20:03:40.679938505 +0100
++++ linux/fs/aufs/module.c	2025-12-01 15:04:46.896666712 +0100
 @@ -0,0 +1,275 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
@@ -26118,7 +25856,7 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c
 +module_exit(aufs_exit);
 diff -urN /usr/share/empty/fs/aufs/module.h linux/fs/aufs/module.h
 --- /usr/share/empty/fs/aufs/module.h	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/module.h	2025-07-24 19:31:57.793180791 +0200
++++ linux/fs/aufs/module.h	2025-12-01 15:04:46.896666712 +0100
 @@ -0,0 +1,180 @@
 +/* SPDX-License-Identifier: GPL-2.0 */
 +/*
@@ -26302,8 +26040,8 @@ diff -urN /usr/share/empty/fs/aufs/module.h linux/fs/aufs/module.h
 +#endif /* __AUFS_MODULE_H__ */
 diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c
 --- /usr/share/empty/fs/aufs/mvdown.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/mvdown.c	2025-07-24 19:31:57.793180791 +0200
-@@ -0,0 +1,714 @@
++++ linux/fs/aufs/mvdown.c	2026-02-08 10:11:28.889988407 +0100
+@@ -0,0 +1,700 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Copyright (C) 2011-2025 Junjiro R. Okajima
@@ -26561,7 +26299,6 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c
 +	int err;
 +	struct path h_path;
 +	struct au_branch *br;
-+	struct inode *delegated;
 +
 +	br = au_sbr(a->sb, a->mvd_bdst);
 +	h_path.dentry = au_wh_lkup(a->mvd_h_dst_parent, &a->dentry->d_name, br);
@@ -26574,14 +26311,8 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c
 +	err = 0;
 +	if (d_is_positive(h_path.dentry)) {
 +		h_path.mnt = au_br_mnt(br);
-+		delegated = NULL;
 +		err = vfsub_unlink(d_inode(a->mvd_h_dst_parent), &h_path,
-+				   &delegated, /*force*/0);
-+		if (unlikely(err == -EWOULDBLOCK)) {
-+			pr_warn("cannot retry for NFSv4 delegation"
-+				" for an internal unlink\n");
-+			iput(delegated);
-+		}
++				   /*force*/0);
 +		if (unlikely(err))
 +			AU_MVD_PR(dmsg, "wh_unlink failed\n");
 +	}
@@ -26599,17 +26330,10 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c
 +{
 +	int err;
 +	struct path h_path;
-+	struct inode *delegated;
 +
 +	h_path.mnt = au_sbr_mnt(a->sb, a->mvd_bsrc);
 +	h_path.dentry = au_h_dptr(a->dentry, a->mvd_bsrc);
-+	delegated = NULL;
-+	err = vfsub_unlink(a->mvd_h_src_dir, &h_path, &delegated, /*force*/0);
-+	if (unlikely(err == -EWOULDBLOCK)) {
-+		pr_warn("cannot retry for NFSv4 delegation"
-+			" for an internal unlink\n");
-+		iput(delegated);
-+	}
++	err = vfsub_unlink(a->mvd_h_src_dir, &h_path, /*force*/0);
 +	if (unlikely(err))
 +		AU_MVD_PR(dmsg, "unlink failed\n");
 +
@@ -28322,8 +28046,8 @@ diff -urN /usr/share/empty/fs/aufs/opts.h linux/fs/aufs/opts.h
 +#endif /* __AUFS_OPTS_H__ */
 diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c
 --- /usr/share/empty/fs/aufs/plink.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/plink.c	2025-02-04 20:03:40.683271838 +0100
-@@ -0,0 +1,516 @@
++++ linux/fs/aufs/plink.c	2026-02-08 10:11:28.889988407 +0100
+@@ -0,0 +1,508 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Copyright (C) 2005-2025 Junjiro R. Okajima
@@ -28594,45 +28318,37 @@ diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c
 +{
 +	int err;
 +	struct path h_path;
-+	struct inode *h_dir, *delegated;
++	struct inode *h_dir;
 +
 +	h_dir = d_inode(h_ppath->dentry);
 +	inode_lock_nested(h_dir, AuLsc_I_CHILD2);
 +	h_path.mnt = h_ppath->mnt;
++	err = vfsub_mnt_want_write(h_path.mnt);
++	if (unlikely(err))
++		goto out;
 +again:
 +	h_path.dentry = vfsub_lkup_one(tgt, h_ppath);
 +	err = PTR_ERR(h_path.dentry);
 +	if (IS_ERR(h_path.dentry))
-+		goto out;
++		goto out_mnt_write;
 +
 +	err = 0;
 +	/* wh.plink dir is not monitored */
 +	/* todo: is it really safe? */
 +	if (d_is_positive(h_path.dentry)
 +	    && d_inode(h_path.dentry) != d_inode(h_dentry)) {
-+		delegated = NULL;
-+		err = vfsub_unlink(h_dir, &h_path, &delegated, /*force*/0);
-+		if (unlikely(err == -EWOULDBLOCK)) {
-+			pr_warn("cannot retry for NFSv4 delegation"
-+				" for an internal unlink\n");
-+			iput(delegated);
-+		}
++		err = vfsub_unlink(h_dir, &h_path, /*force*/0);
 +		dput(h_path.dentry);
 +		h_path.dentry = NULL;
 +		if (!err)
 +			goto again;
 +	}
-+	if (!err && d_is_negative(h_path.dentry)) {
-+		delegated = NULL;
-+		err = vfsub_link(h_dentry, h_dir, &h_path, &delegated);
-+		if (unlikely(err == -EWOULDBLOCK)) {
-+			pr_warn("cannot retry for NFSv4 delegation"
-+				" for an internal link\n");
-+			iput(delegated);
-+		}
-+	}
++	if (!err && d_is_negative(h_path.dentry))
++		err = vfsub_link(h_dentry, h_dir, &h_path);
 +	dput(h_path.dentry);
 +
++out_mnt_write:
++	vfsub_mnt_drop_write(h_path.mnt);
 +out:
 +	inode_unlock(h_dir);
 +	return err;
@@ -29982,7 +29698,7 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c
 +}
 diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 --- /usr/share/empty/fs/aufs/super.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/super.c	2025-06-19 20:53:32.793295933 +0200
++++ linux/fs/aufs/super.c	2025-12-01 15:04:46.896666712 +0100
 @@ -0,0 +1,871 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
@@ -30857,7 +30573,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c
 +};
 diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h
 --- /usr/share/empty/fs/aufs/super.h	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/super.h	2025-07-24 19:31:57.793180791 +0200
++++ linux/fs/aufs/super.h	2025-12-01 15:04:46.896666712 +0100
 @@ -0,0 +1,618 @@
 +/* SPDX-License-Identifier: GPL-2.0 */
 +/*
@@ -33122,8 +32838,8 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c
 +}
 diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 --- /usr/share/empty/fs/aufs/vfsub.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/vfsub.c	2025-07-24 19:31:57.793180791 +0200
-@@ -0,0 +1,966 @@
++++ linux/fs/aufs/vfsub.c	2026-02-08 10:11:28.893321741 +0100
+@@ -0,0 +1,1005 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Copyright (C) 2005-2025 Junjiro R. Okajima
@@ -33146,6 +32862,7 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 + * sub-routines for VFS
 + */
 +
++#include <linux/filelock.h>
 +#include <linux/mnt_namespace.h>
 +#include <linux/nsproxy.h>
 +#include <linux/security.h>
@@ -33422,13 +33139,15 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +{
 +	int err;
 +	struct dentry *d;
++	struct inode *inode;
 +	struct mnt_idmap *idmap;
 +
 +	IMustLock(dir);
 +
 +	d = path->dentry;
 +	path->dentry = d->d_parent;
-+	err = security_path_mknod(path, d, mode, 0);
++	inode = d_inode(path->dentry);
++	err = security_path_mknod(path, d, mode_strip_umask(inode, mode), 0);
 +	path->dentry = d;
 +	if (unlikely(err))
 +		goto out;
@@ -33441,6 +33160,7 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +		struct path tmp = *path;
 +		int did;
 +
++		security_path_post_mknod(idmap, d);
 +		vfsub_update_h_iattr(&tmp, &did);
 +		if (did) {
 +			tmp.dentry = path->dentry->d_parent;
@@ -33492,13 +33212,16 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +{
 +	int err;
 +	struct dentry *d;
++	struct inode *inode;
 +	struct mnt_idmap *idmap;
 +
 +	IMustLock(dir);
 +
 +	d = path->dentry;
 +	path->dentry = d->d_parent;
-+	err = security_path_mknod(path, d, mode, new_encode_dev(dev));
++	inode = d_inode(path->dentry);
++	err = security_path_mknod(path, d, mode_strip_umask(inode, mode),
++				  new_encode_dev(dev));
 +	path->dentry = d;
 +	if (unlikely(err))
 +		goto out;
@@ -33533,12 +33256,12 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +	return -EMLINK;
 +}
 +
-+int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path,
-+	       struct inode **delegated_inode)
++int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path)
 +{
-+	int err;
++	int err, e;
 +	struct dentry *d;
 +	struct mnt_idmap *idmap;
++	struct inode *deleg = NULL;
 +
 +	IMustLock(dir);
 +
@@ -33553,11 +33276,19 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +	path->dentry = d;
 +	if (unlikely(err))
 +		goto out;
-+	idmap = mnt_idmap(path->mnt);
 +
-+	lockdep_off();
-+	err = vfs_link(src_dentry, idmap, dir, path->dentry, delegated_inode);
-+	lockdep_on();
++	idmap = mnt_idmap(path->mnt);
++	do {
++		lockdep_off();
++		err = vfs_link(src_dentry, idmap, dir, path->dentry, &deleg);
++		lockdep_on();
++		if (deleg) {
++			e = break_deleg_wait(&deleg);
++			if (!e)
++				continue;
++		}
++		break;
++	} while (1);
 +	if (!err) {
 +		struct path tmp = *path;
 +		int did;
@@ -33578,11 +33309,11 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +}
 +
 +int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry,
-+		 struct inode *dir, struct path *path,
-+		 struct inode **delegated_inode, unsigned int flags)
++		 struct inode *dir, struct path *path, unsigned int flags)
 +{
-+	int err;
++	int err, e;
 +	struct renamedata rd;
++	struct inode *deleg = NULL;
 +	struct path tmp = {
 +		.mnt	= path->mnt
 +	};
@@ -33605,11 +33336,19 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +	rd.new_mnt_idmap = rd.old_mnt_idmap;
 +	rd.new_dir = dir;
 +	rd.new_dentry = path->dentry;
-+	rd.delegated_inode = delegated_inode;
++	rd.delegated_inode = &deleg;
 +	rd.flags = flags;
-+	lockdep_off();
-+	err = vfs_rename(&rd);
-+	lockdep_on();
++	do {
++		lockdep_off();
++		err = vfs_rename(&rd);
++		lockdep_on();
++		if (deleg) {
++			e = break_deleg_wait(&deleg);
++			if (!e)
++				continue;
++		}
++		break;
++	} while (1);
 +	if (!err) {
 +		int did;
 +
@@ -33632,13 +33371,15 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +{
 +	int err;
 +	struct dentry *d;
++	struct inode *inode;
 +	struct mnt_idmap *idmap;
 +
 +	IMustLock(dir);
 +
 +	d = path->dentry;
 +	path->dentry = d->d_parent;
-+	err = security_path_mkdir(path, d, mode);
++	inode = d_inode(path->dentry);
++	err = security_path_mkdir(path, d, mode_strip_umask(inode, mode));
 +	path->dentry = d;
 +	if (unlikely(err))
 +		goto out;
@@ -33888,11 +33629,9 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +
 +	idmap = mnt_idmap(path->mnt);
 +	do_sio = au_test_h_perm_sio(idmap, dir, MAY_EXEC | MAY_WRITE);
-+	if (!do_sio) {
-+		lockdep_off();
++	if (!do_sio)
 +		err = vfsub_mkdir(dir, path, mode);
-+		lockdep_on();
-+	} else {
++	else {
 +		struct au_vfsub_mkdir_args args = {
 +			.errp	= &err,
 +			.dir	= dir,
@@ -33950,7 +33689,6 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +	int *errp;
 +	struct path *path;
 +	struct iattr *ia;
-+	struct inode **delegated_inode;
 +};
 +
 +static void call_notify_change(void *args)
@@ -33958,32 +33696,43 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +	struct notify_change_args *a = args;
 +	struct inode *h_inode;
 +	struct mnt_idmap *idmap;
++	struct inode *deleg = NULL;
 +
 +	h_inode = d_inode(a->path->dentry);
 +	IMustLock(h_inode);
 +
 +	*a->errp = -EPERM;
-+	if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) {
-+		idmap = mnt_idmap(a->path->mnt);
++	if (IS_IMMUTABLE(h_inode) || IS_APPEND(h_inode))
++		goto out;
++
++	idmap = mnt_idmap(a->path->mnt);
++	do {
 +		lockdep_off();
-+		*a->errp = notify_change(idmap, a->path->dentry, a->ia,
-+					 a->delegated_inode);
++		*a->errp = notify_change(idmap, a->path->dentry, a->ia, &deleg);
 +		lockdep_on();
-+		if (!*a->errp)
-+			vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/
-+	}
++		if (deleg) {
++			int e;
++
++			e = break_deleg_wait(&deleg);
++			if (!e)
++				continue;
++		}
++		break;
++	} while (1);
++	if (!*a->errp)
++		vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/
++
++out:
 +	AuTraceErr(*a->errp);
 +}
 +
-+int vfsub_notify_change(struct path *path, struct iattr *ia,
-+			struct inode **delegated_inode)
++int vfsub_notify_change(struct path *path, struct iattr *ia)
 +{
 +	int err;
 +	struct notify_change_args args = {
-+		.errp			= &err,
-+		.path			= path,
-+		.ia			= ia,
-+		.delegated_inode	= delegated_inode
++		.errp	= &err,
++		.path	= path,
++		.ia	= ia
 +	};
 +
 +	call_notify_change(&args);
@@ -33991,15 +33740,13 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +	return err;
 +}
 +
-+int vfsub_sio_notify_change(struct path *path, struct iattr *ia,
-+			    struct inode **delegated_inode)
++int vfsub_sio_notify_change(struct path *path, struct iattr *ia)
 +{
 +	int err, wkq_err;
 +	struct notify_change_args args = {
-+		.errp			= &err,
-+		.path			= path,
-+		.ia			= ia,
-+		.delegated_inode	= delegated_inode
++		.errp	= &err,
++		.path	= path,
++		.ia	= ia
 +	};
 +
 +	wkq_err = au_wkq_wait(call_notify_change, &args);
@@ -34015,7 +33762,6 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +	int *errp;
 +	struct inode *dir;
 +	struct path *path;
-+	struct inode **delegated_inode;
 +};
 +
 +static void call_unlink(void *args)
@@ -34024,6 +33770,7 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +	struct dentry *d = a->path->dentry;
 +	struct inode *h_inode;
 +	struct mnt_idmap *idmap;
++	struct inode *deleg = NULL;
 +	const int stop_sillyrename = (au_test_nfs(d->d_sb)
 +				      && au_dcount(d) == 1);
 +
@@ -34044,9 +33791,19 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +	}
 +
 +	idmap = mnt_idmap(a->path->mnt);
-+	lockdep_off();
-+	*a->errp = vfs_unlink(idmap, a->dir, d, a->delegated_inode);
-+	lockdep_on();
++	do {
++		lockdep_off();
++		*a->errp = vfs_unlink(idmap, a->dir, d, &deleg);
++		lockdep_on();
++		if (deleg) {
++			int e;
++
++			e = break_deleg_wait(&deleg);
++			if (!e)
++				continue;
++		}
++		break;
++	} while (1);
 +	if (!*a->errp) {
 +		struct path tmp = {
 +			.dentry = d->d_parent,
@@ -34067,15 +33824,13 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 + * @dir: must be locked.
 + * @dentry: target dentry.
 + */
-+int vfsub_unlink(struct inode *dir, struct path *path,
-+		 struct inode **delegated_inode, int force)
++int vfsub_unlink(struct inode *dir, struct path *path, int force)
 +{
 +	int err;
 +	struct unlink_args args = {
-+		.errp			= &err,
-+		.dir			= dir,
-+		.path			= path,
-+		.delegated_inode	= delegated_inode
++		.errp	= &err,
++		.dir	= dir,
++		.path	= path
 +	};
 +
 +	if (!force)
@@ -34092,8 +33847,8 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c
 +}
 diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h
 --- /usr/share/empty/fs/aufs/vfsub.h	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/vfsub.h	2025-07-24 19:31:57.793180791 +0200
-@@ -0,0 +1,441 @@
++++ linux/fs/aufs/vfsub.h	2026-02-08 10:11:28.893321741 +0100
+@@ -0,0 +1,436 @@
 +/* SPDX-License-Identifier: GPL-2.0 */
 +/*
 + * Copyright (C) 2005-2025 Junjiro R. Okajima
@@ -34310,11 +34065,9 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h
 +int vfsub_symlink(struct inode *dir, struct path *path,
 +		  const char *symname);
 +int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev);
-+int vfsub_link(struct dentry *src_dentry, struct inode *dir,
-+	       struct path *path, struct inode **delegated_inode);
++int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path);
 +int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry,
-+		 struct inode *hdir, struct path *path,
-+		 struct inode **delegated_inode, unsigned int flags);
++		 struct inode *hdir, struct path *path, unsigned int flags);
 +int vfsub_mkdir(struct inode *dir, struct path *path, int mode);
 +int vfsub_rmdir(struct inode *dir, struct path *path);
 +
@@ -34462,12 +34215,9 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h
 +
 +int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode);
 +int vfsub_sio_rmdir(struct inode *dir, struct path *path);
-+int vfsub_sio_notify_change(struct path *path, struct iattr *ia,
-+			    struct inode **delegated_inode);
-+int vfsub_notify_change(struct path *path, struct iattr *ia,
-+			struct inode **delegated_inode);
-+int vfsub_unlink(struct inode *dir, struct path *path,
-+		 struct inode **delegated_inode, int force);
++int vfsub_sio_notify_change(struct path *path, struct iattr *ia);
++int vfsub_notify_change(struct path *path, struct iattr *ia);
++int vfsub_unlink(struct inode *dir, struct path *path, int force);
 +
 +static inline int vfsub_getattr(const struct path *path, struct kstat *st)
 +{
@@ -34537,8 +34287,8 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h
 +#endif /* __AUFS_VFSUB_H__ */
 diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
 --- /usr/share/empty/fs/aufs/wbr_policy.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/wbr_policy.c	2025-07-24 19:31:57.796514124 +0200
-@@ -0,0 +1,830 @@
++++ linux/fs/aufs/wbr_policy.c	2026-02-08 10:11:28.893321741 +0100
+@@ -0,0 +1,836 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Copyright (C) 2005-2025 Junjiro R. Okajima
@@ -34572,6 +34322,10 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
 +	struct iattr ia;
 +	struct inode *h_isrc;
 +
++	err = vfsub_mnt_want_write(h_path->mnt);
++	if (unlikely(err))
++		goto out;
++
 +	h_isrc = d_inode(h_src);
 +	ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID;
 +	ia.ia_mode = h_isrc->i_mode;
@@ -34579,16 +34333,18 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
 +	ia.ia_gid = h_isrc->i_gid;
 +	sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID));
 +	au_cpup_attr_flags(d_inode(h_path->dentry), h_isrc->i_flags);
-+	/* no delegation since it is just created */
-+	err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL);
++	err = vfsub_sio_notify_change(h_path, &ia);
 +
 +	/* is this nfs only? */
 +	if (!err && sbits && au_test_nfs(h_path->dentry->d_sb)) {
 +		ia.ia_valid = ATTR_FORCE | ATTR_MODE;
 +		ia.ia_mode = h_isrc->i_mode;
-+		err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL);
++		err = vfsub_sio_notify_change(h_path, &ia);
 +	}
 +
++	vfsub_mnt_drop_write(h_path->mnt);
++
++out:
 +	return err;
 +}
 +
@@ -35371,8 +35127,8 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c
 +};
 diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
 --- /usr/share/empty/fs/aufs/whout.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/whout.c	2025-06-19 20:53:32.796629267 +0200
-@@ -0,0 +1,1072 @@
++++ linux/fs/aufs/whout.c	2026-02-08 10:11:28.893321741 +0100
+@@ -0,0 +1,1049 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Copyright (C) 2005-2025 Junjiro R. Okajima
@@ -35559,7 +35315,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
 +	struct path h_path = {
 +		.mnt = au_br_mnt(br)
 +	};
-+	struct inode *h_dir, *delegated;
++	struct inode *h_dir;
 +	struct dentry *h_parent;
 +
 +	h_parent = h_dentry->d_parent; /* dir inode is locked */
@@ -35572,15 +35328,8 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
 +		goto out;
 +
 +	/* under the same dir, no need to lock_rename() */
-+	delegated = NULL;
-+	err = vfsub_rename(h_dir, h_dentry, h_dir, &h_path, &delegated,
-+			   /*flags*/0);
++	err = vfsub_rename(h_dir, h_dentry, h_dir, &h_path, /*flags*/0);
 +	AuTraceErr(err);
-+	if (unlikely(err == -EWOULDBLOCK)) {
-+		pr_warn("cannot retry for NFSv4 delegation"
-+			" for an internal rename\n");
-+		iput(delegated);
-+	}
 +	dput(h_path.dentry);
 +
 +out:
@@ -35596,7 +35345,6 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
 +static int do_unlink_wh(struct inode *h_dir, struct path *h_path)
 +{
 +	int err, force;
-+	struct inode *delegated;
 +
 +	/*
 +	 * forces superio when the dir has a sticky bit.
@@ -35604,13 +35352,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
 +	 */
 +	force = (h_dir->i_mode & S_ISVTX)
 +		&& !uid_eq(current_fsuid(), d_inode(h_path->dentry)->i_uid);
-+	delegated = NULL;
-+	err = vfsub_unlink(h_dir, h_path, &delegated, force);
-+	if (unlikely(err == -EWOULDBLOCK)) {
-+		pr_warn("cannot retry for NFSv4 delegation"
-+			" for an internal unlink\n");
-+		iput(delegated);
-+	}
++	err = vfsub_unlink(h_dir, h_path, force);
 +	return err;
 +}
 +
@@ -35655,22 +35397,15 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
 +			const int isdir)
 +{
 +	int err;
-+	struct inode *delegated;
 +
 +	if (d_is_negative(whpath->dentry))
 +		return;
 +
 +	if (isdir)
 +		err = vfsub_rmdir(h_dir, whpath);
-+	else {
-+		delegated = NULL;
-+		err = vfsub_unlink(h_dir, whpath, &delegated, /*force*/0);
-+		if (unlikely(err == -EWOULDBLOCK)) {
-+			pr_warn("cannot retry for NFSv4 delegation"
-+				" for an internal unlink\n");
-+			iput(delegated);
-+		}
-+	}
++	else
++		err = vfsub_unlink(h_dir, whpath, /*force*/0);
++
 +	if (unlikely(err))
 +		pr_warn("failed removing %pd (%d), ignored.\n",
 +			whpath->dentry, err);
@@ -35827,7 +35562,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
 + */
 +int au_wh_init(struct au_branch *br, struct super_block *sb)
 +{
-+	int err, i;
++	int err, i, need_drop;
 +	const unsigned char do_plink
 +		= !!au_opt_test(au_mntflags(sb), PLINK);
 +	struct inode *h_dir;
@@ -35881,7 +35616,12 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
 +			wbr->wbr_wh[i] = NULL;
 +		}
 +
-+	err = 0;
++	need_drop = 0;
++	err = vfsub_mnt_want_write(path.mnt);
++	if (unlikely(err))
++		goto out_err;
++	need_drop = 1;
++
 +	if (!au_br_writable(br->br_perm)) {
 +		h_dir = d_inode(h_root);
 +		au_wh_init_ro(h_dir, base, &path);
@@ -35904,6 +35644,8 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
 +	pr_err("an error(%d) on the writable branch %pd(%s)\n",
 +	       err, h_root, au_sbtype(h_root->d_sb));
 +out:
++	if (need_drop)
++		vfsub_mnt_drop_write(path.mnt);
 +	for (i = 0; i < AuBrWh_Last; i++)
 +		dput(base[i].dentry);
 +	return err;
@@ -35928,7 +35670,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
 +	struct path h_path;
 +	struct reinit_br_wh *a = arg;
 +	struct au_wbr *wbr;
-+	struct inode *dir, *delegated;
++	struct inode *dir;
 +	struct dentry *h_root;
 +	struct au_hinode *hdir;
 +
@@ -35955,13 +35697,10 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
 +	if (!err) {
 +		h_path.dentry = wbr->wbr_whbase;
 +		h_path.mnt = au_br_mnt(a->br);
-+		delegated = NULL;
-+		err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated,
-+				   /*force*/0);
-+		if (unlikely(err == -EWOULDBLOCK)) {
-+			pr_warn("cannot retry for NFSv4 delegation"
-+				" for an internal unlink\n");
-+			iput(delegated);
++		err = vfsub_mnt_want_write(h_path.mnt);
++		if (!err) {
++			err = vfsub_unlink(hdir->hi_inode, &h_path, /*force*/0);
++			vfsub_mnt_drop_write(h_path.mnt);
 +		}
 +	} else {
 +		pr_warn("%pd is moved, ignored\n", wbr->wbr_whbase);
@@ -36036,7 +35775,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
 +	struct au_branch *br;
 +	struct au_wbr *wbr;
 +	struct dentry *h_parent;
-+	struct inode *h_dir, *delegated;
++	struct inode *h_dir;
 +
 +	h_parent = wh->d_parent; /* dir inode is locked */
 +	h_dir = d_inode(h_parent);
@@ -36047,13 +35786,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
 +	wbr = br->br_wbr;
 +	wbr_wh_read_lock(wbr);
 +	if (wbr->wbr_whbase) {
-+		delegated = NULL;
-+		err = vfsub_link(wbr->wbr_whbase, h_dir, &h_path, &delegated);
-+		if (unlikely(err == -EWOULDBLOCK)) {
-+			pr_warn("cannot retry for NFSv4 delegation"
-+				" for an internal link\n");
-+			iput(delegated);
-+		}
++		err = vfsub_link(wbr->wbr_whbase, h_dir, &h_path);
 +		if (!err || err != -EMLINK)
 +			goto out;
 +
@@ -36447,7 +36180,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c
 +}
 diff -urN /usr/share/empty/fs/aufs/whout.h linux/fs/aufs/whout.h
 --- /usr/share/empty/fs/aufs/whout.h	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/whout.h	2025-02-04 20:03:40.686605172 +0100
++++ linux/fs/aufs/whout.h	2025-12-01 15:04:46.900000045 +0100
 @@ -0,0 +1,87 @@
 +/* SPDX-License-Identifier: GPL-2.0 */
 +/*
@@ -37369,8 +37102,8 @@ diff -urN /usr/share/empty/fs/aufs/xattr.c linux/fs/aufs/xattr.c
 +}
 diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
 --- /usr/share/empty/fs/aufs/xino.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux/fs/aufs/xino.c	2025-02-04 20:03:40.686605172 +0100
-@@ -0,0 +1,1926 @@
++++ linux/fs/aufs/xino.c	2026-02-08 10:11:28.893321741 +0100
+@@ -0,0 +1,1927 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Copyright (C) 2005-2025 Junjiro R. Okajima
@@ -37566,13 +37299,15 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
 +	h_parent = au_dget_parent_lock(d, AuLsc_I_PARENT);
 +	if (!wbrtop)
 +		mutex_unlock(&mtx);
-+	/* mnt_want_write() is unnecessary here */
 +	h_dir = d_inode(h_parent);
 +	inode = file_inode(file);
-+	/* no delegation since it is just created */
-+	if (vfsub_inode_nlink(inode, AU_I_BRANCH))
-+		err = vfsub_unlink(h_dir, &file->f_path, /*delegated*/NULL,
-+				   /*force*/0);
++	if (vfsub_inode_nlink(inode, AU_I_BRANCH)) {
++		err = vfsub_mnt_want_write(file->f_path.mnt);
++		if (!err) {
++			err = vfsub_unlink(h_dir, &file->f_path, /*force*/0);
++			vfsub_mnt_drop_write(file->f_path.mnt);
++		}
++	}
 +	inode_unlock(h_dir);
 +	dput(h_parent);
 +	if (unlikely(err)) {
@@ -37609,7 +37344,7 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
 +{
 +	struct file *file;
 +	struct dentry *dentry;
-+	struct inode *dir, *delegated;
++	struct inode *dir;
 +	struct qstr *name;
 +	struct path ppath, path;
 +	int err, do_unlock;
@@ -37631,32 +37366,29 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
 +		goto out;
 +	}
 +
-+	/* no need to mnt_want_write() since we call dentry_open() later */
++	path.mnt = base->mnt;
++	err = vfsub_mnt_want_write(path.mnt);
++	if (unlikely(err))
++		goto out_dput;
++
 +	err = vfs_create(mnt_idmap(base->mnt), dir, path.dentry, 0666, NULL);
 +	if (unlikely(err)) {
 +		file = ERR_PTR(err);
 +		pr_err("%pd create err %d\n", dentry, err);
-+		goto out_dput;
++		goto out_mnt_write;
 +	}
 +
-+	path.mnt = base->mnt;
 +	file = vfsub_dentry_open(&path,
 +				 O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE
 +				 /* | __FMODE_NONOTIFY */);
 +	if (IS_ERR(file)) {
 +		pr_err("%pd open err %ld\n", dentry, PTR_ERR(file));
-+		goto out_dput;
++		goto out_mnt_write;
 +	}
 +
-+	delegated = NULL;
-+	err = vfsub_unlink(dir, &file->f_path, &delegated, /*force*/0);
++	err = vfsub_unlink(dir, &file->f_path, /*force*/0);
 +	au_xino_unlock_dir(&ldir);
 +	do_unlock = 0;
-+	if (unlikely(err == -EWOULDBLOCK)) {
-+		pr_warn("cannot retry for NFSv4 delegation"
-+			" for an internal unlink\n");
-+		iput(delegated);
-+	}
 +	if (unlikely(err)) {
 +		pr_err("%pd unlink err %d\n", dentry, err);
 +		goto out_fput;
@@ -37670,11 +37402,13 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
 +			goto out_fput;
 +		}
 +	}
-+	goto out_dput; /* success */
++	goto out_mnt_write; /* success */
 +
 +out_fput:
 +	fput(file);
 +	file = ERR_PTR(err);
++out_mnt_write:
++	vfsub_mnt_drop_write(path.mnt);
 +out_dput:
 +	dput(path.dentry);
 +out:
@@ -39299,7 +39033,7 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c
 +}
 diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/linux/aufs_type.h
 --- /usr/share/empty/include/uapi/linux/aufs_type.h	1970-01-01 01:00:00.000000000 +0100
-+++ linux/include/uapi/linux/aufs_type.h	2025-07-24 19:32:13.479847454 +0200
++++ linux/include/uapi/linux/aufs_type.h	2026-02-08 10:11:28.893321741 +0100
 @@ -0,0 +1,452 @@
 +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 +/*
@@ -39343,7 +39077,7 @@ diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/lin
 +#include <limits.h>
 +#endif /* __KERNEL__ */
 +
-+#define AUFS_VERSION	"6.12.29-20250623"
++#define AUFS_VERSION	"6.12.29-20260112"
 +
 +/* todo? move this to linux-2.6.19/include/magic.h */
 +#define AUFS_SUPER_MAGIC	('a' << 24 | 'u' << 16 | 'f' << 8 | 's')
@@ -39904,10 +39638,10 @@ index c8eba5ada9950..52b55a88c7af2 100644
  
  static int loop_clr_fd(struct loop_device *lo)
 diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c
-index db7e9fcf1056a..6d202136d29af 100644
+index cb5781e56e1e1..93e7a6a369d0a 100644
 --- a/fs/aufs/f_op.c
 +++ b/fs/aufs/f_op.c
-@@ -317,7 +317,7 @@ static ssize_t aufs_read_iter(struct kiocb *kio, struct iov_iter *iov_iter)
+@@ -326,7 +326,7 @@ static ssize_t aufs_read_iter(struct kiocb *kio, struct iov_iter *iov_iter)
  	if (IS_ERR(h_file))
  		goto out;
  
@@ -39979,7 +39713,7 @@ index 9c30cba527421..8161108d0f6d5 100644
  
  /* ---------------------------------------------------------------------- */
 diff --git a/include/linux/fs.h b/include/linux/fs.h
-index cb9f98b540e31..ec4579150dfb7 100644
+index 44805e9a38604..522b633c33d7a 100644
 --- a/include/linux/fs.h
 +++ b/include/linux/fs.h
 @@ -2248,6 +2248,11 @@ struct super_operations {
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/kernel.git/commitdiff/9e85a475bb6ea6ba1c99fe66ccba217af82aeca7



More information about the pld-cvs-commit mailing list