X-Git-Url: http://git.pld-linux.org/?a=blobdiff_plain;f=kernel-aufs4.patch;h=01990861c20b22785fb48c4ef8e58e4bbd686256;hb=60be809a16d133931251706c0904d5c3489ec02f;hp=0d0604488b326b240909fa949a8f08a57979468a;hpb=be118d2926e068389e8fca21bd218d1567d4358d;p=packages%2Fkernel.git diff --git a/kernel-aufs4.patch b/kernel-aufs4.patch index 0d060448..01990861 100644 --- a/kernel-aufs4.patch +++ b/kernel-aufs4.patch @@ -2,10 +2,10 @@ SPDX-License-Identifier: GPL-2.0 aufs4.x-rcN kbuild patch diff --git a/fs/Kconfig b/fs/Kconfig -index bc821a8..7ae814c 100644 +index ac474a6..284cee9 100644 --- a/fs/Kconfig +++ b/fs/Kconfig -@@ -251,6 +251,7 @@ source "fs/pstore/Kconfig" +@@ -255,6 +255,7 @@ source "fs/pstore/Kconfig" source "fs/sysv/Kconfig" source "fs/ufs/Kconfig" source "fs/exofs/Kconfig" @@ -14,7 +14,7 @@ index bc821a8..7ae814c 100644 endif # MISC_FILESYSTEMS diff --git a/fs/Makefile b/fs/Makefile -index add789e..26100d6 100644 +index 293733f..12d19d0 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -128,3 +128,4 @@ obj-y += exofs/ # Multiple modules @@ -26,10 +26,10 @@ SPDX-License-Identifier: GPL-2.0 aufs4.x-rcN base patch diff --git a/MAINTAINERS b/MAINTAINERS -index 4623caf..7617c0e 100644 +index 8119141..5e84420 100644 --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -2484,6 +2484,19 @@ F: include/linux/audit.h +@@ -2590,6 +2590,19 @@ F: include/linux/audit.h F: include/uapi/linux/audit.h F: kernel/audit* @@ -48,13 +48,13 @@ index 4623caf..7617c0e 100644 + AUXILIARY DISPLAY DRIVERS M: Miguel Ojeda Sandonis - W: http://miguelojeda.es/auxdisplay.htm + S: Maintained diff --git a/drivers/block/loop.c b/drivers/block/loop.c -index 87855b5..962b2d6 100644 +index cb0cc86..470dd02 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c -@@ -691,6 +691,24 @@ static inline int is_loop_device(struct file *file) - return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == LOOP_MAJOR; +@@ -738,6 +738,24 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, + return error; } +/* @@ -79,20 +79,20 @@ index 87855b5..962b2d6 100644 static ssize_t loop_attr_show(struct device *dev, char *page, diff --git a/fs/dcache.c b/fs/dcache.c -index 7c38f39..9ce5e26 100644 +index 2593153..6369b30 100644 --- a/fs/dcache.c +++ b/fs/dcache.c -@@ -1200,7 +1200,7 @@ enum d_walk_ret { +@@ -1224,7 +1224,7 @@ enum d_walk_ret { * - * The @enter() and @finish() callbacks are called with d_lock held. + * The @enter() callbacks are called with d_lock held. */ -static void d_walk(struct dentry *parent, void *data, +void d_walk(struct dentry *parent, void *data, - enum d_walk_ret (*enter)(void *, struct dentry *), - void (*finish)(void *)) + enum d_walk_ret (*enter)(void *, struct dentry *)) { + struct dentry *this_parent; diff --git a/fs/fcntl.c b/fs/fcntl.c -index 1e97f1f..8cd01f7 100644 +index 0831851..78234ee 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -32,7 +32,7 @@ @@ -114,23 +114,23 @@ index 1e97f1f..8cd01f7 100644 return error; diff --git a/fs/inode.c b/fs/inode.c -index ef36236..929a5a3 100644 +index 35d2108..d2395eb 100644 --- a/fs/inode.c +++ b/fs/inode.c -@@ -1659,7 +1659,7 @@ EXPORT_SYMBOL(generic_update_time); +@@ -1660,7 +1660,7 @@ EXPORT_SYMBOL(generic_update_time); * This does the actual work of updating an inodes time or version. Must have * had called mnt_want_write() before calling this. */ --static int update_time(struct inode *inode, struct timespec *time, int flags) -+int update_time(struct inode *inode, struct timespec *time, int flags) +-static int update_time(struct inode *inode, struct timespec64 *time, int flags) ++int update_time(struct inode *inode, struct timespec64 *time, int flags) { - int (*update_time)(struct inode *, struct timespec *, int); + int (*update_time)(struct inode *, struct timespec64 *, int); diff --git a/fs/namespace.c b/fs/namespace.c -index 9d1374a..26ef600 100644 +index a7f9126..46ed643 100644 --- a/fs/namespace.c +++ b/fs/namespace.c -@@ -846,6 +846,12 @@ static inline int check_mnt(struct mount *mnt) +@@ -770,6 +770,12 @@ static inline int check_mnt(struct mount *mnt) return mnt->mnt_ns == current->nsproxy->mnt_ns; } @@ -144,10 +144,10 @@ index 9d1374a..26ef600 100644 * vfsmount lock must be held for write */ diff --git a/fs/read_write.c b/fs/read_write.c -index f8547b8..0a5c47b 100644 +index 58f3053..a2a55ea 100644 --- a/fs/read_write.c +++ b/fs/read_write.c -@@ -484,6 +484,28 @@ ssize_t __vfs_write(struct file *file, const char __user *p, size_t count, +@@ -489,6 +489,28 @@ ssize_t __vfs_write(struct file *file, const char __user *p, size_t count, return -EINVAL; } @@ -177,7 +177,7 @@ index f8547b8..0a5c47b 100644 { mm_segment_t old_fs; diff --git a/fs/splice.c b/fs/splice.c -index 39e2dc0..c5fb195 100644 +index de2ede0..5dcf77b 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -837,8 +837,8 @@ EXPORT_SYMBOL(generic_splice_sendpage); @@ -205,7 +205,7 @@ index 39e2dc0..c5fb195 100644 ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); diff --git a/fs/sync.c b/fs/sync.c -index 6e0a2cb..a6891ee 100644 +index b54e054..2860782 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -28,7 +28,7 @@ @@ -217,23 +217,11 @@ index 6e0a2cb..a6891ee 100644 { if (wait) sync_inodes_sb(sb); -diff --git a/include/linux/file.h b/include/linux/file.h -index 279720d..76e38ea 100644 ---- a/include/linux/file.h -+++ b/include/linux/file.h -@@ -20,6 +20,7 @@ struct dentry; - struct path; - extern struct file *alloc_file(const struct path *, fmode_t mode, - const struct file_operations *fop); -+extern struct file *get_empty_filp(void); - - static inline void fput_light(struct file *file, int fput_needed) - { diff --git a/include/linux/fs.h b/include/linux/fs.h -index 79c41398..383ab06 100644 +index c95c080..0e44705 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h -@@ -1270,6 +1270,7 @@ extern void fasync_free(struct fasync_struct *); +@@ -1305,6 +1305,7 @@ extern void fasync_free(struct fasync_struct *); /* can be called from interrupts */ extern void kill_fasync(struct fasync_struct **, int, int); @@ -241,7 +229,7 @@ index 79c41398..383ab06 100644 extern void __f_setown(struct file *filp, struct pid *, enum pid_type, int force); extern int f_setown(struct file *filp, unsigned long arg, int force); extern void f_delown(struct file *filp); -@@ -1721,6 +1722,7 @@ struct file_operations { +@@ -1797,6 +1798,7 @@ struct file_operations { ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); int (*check_flags)(int); @@ -249,7 +237,7 @@ index 79c41398..383ab06 100644 int (*flock) (struct file *, int, struct file_lock *); ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); -@@ -1791,6 +1793,12 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, +@@ -1867,6 +1869,12 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, struct iovec *fast_pointer, struct iovec **ret_pointer); @@ -262,15 +250,15 @@ index 79c41398..383ab06 100644 extern ssize_t __vfs_read(struct file *, char __user *, size_t, loff_t *); extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *); extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *); -@@ -2195,6 +2203,7 @@ extern int current_umask(void); +@@ -2292,6 +2300,7 @@ extern int current_umask(void); extern void ihold(struct inode * inode); extern void iput(struct inode *); - extern int generic_update_time(struct inode *, struct timespec *, int); -+extern int update_time(struct inode *, struct timespec *, int); + extern int generic_update_time(struct inode *, struct timespec64 *, int); ++extern int update_time(struct inode *, struct timespec64 *, int); /* /sys/fs */ extern struct kobject *fs_kobj; -@@ -2475,6 +2484,7 @@ static inline bool sb_is_blkdev_sb(struct super_block *sb) +@@ -2579,6 +2588,7 @@ static inline bool sb_is_blkdev_sb(struct super_block *sb) return false; } #endif @@ -279,10 +267,10 @@ index 79c41398..383ab06 100644 extern const struct file_operations def_blk_fops; extern const struct file_operations def_chr_fops; diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h -index 6fc77d4..27e76f0 100644 +index 1fd82ff..a5ccac5 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h -@@ -313,6 +313,8 @@ static inline int lockdep_match_key(struct lockdep_map *lock, +@@ -308,6 +308,8 @@ static inline int lockdep_match_key(struct lockdep_map *lock, return lock->key == key; } @@ -291,7 +279,7 @@ index 6fc77d4..27e76f0 100644 /* * Acquire a lock. * -@@ -439,6 +441,7 @@ struct lockdep_map { }; +@@ -434,6 +436,7 @@ struct lockdep_map { }; #define lockdep_depth(tsk) (0) @@ -334,12 +322,12 @@ index 74b4911..19789fb 100644 + unsigned int flags); #endif diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c -index 89b5f83..0dca42f 100644 +index 1efada2..447bc0b 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -140,7 +140,7 @@ static struct lock_list list_entries[MAX_LOCKDEP_ENTRIES]; unsigned long nr_lock_classes; - static struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; + struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; -static inline struct lock_class *hlock_class(struct held_lock *hlock) +inline struct lock_class *lockdep_hlock_class(struct held_lock *hlock) @@ -358,10 +346,10 @@ SPDX-License-Identifier: GPL-2.0 aufs4.x-rcN mmap patch diff --git a/fs/proc/base.c b/fs/proc/base.c -index 9298324..da5bf4f9 100644 +index ce34654..28508b1 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c -@@ -2014,7 +2014,7 @@ static int map_files_get_link(struct dentry *dentry, struct path *path) +@@ -2016,7 +2016,7 @@ static int map_files_get_link(struct dentry *dentry, struct path *path) down_read(&mm->mmap_sem); vma = find_exact_vma(mm, vm_start, vm_end); if (vma && vma->vm_file) { @@ -371,7 +359,7 @@ index 9298324..da5bf4f9 100644 rc = 0; } diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c -index 7563437..7c0dc0f 100644 +index 3b63be6..fb9913b 100644 --- a/fs/proc/nommu.c +++ b/fs/proc/nommu.c @@ -45,7 +45,10 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region) @@ -387,10 +375,10 @@ index 7563437..7c0dc0f 100644 ino = inode->i_ino; } diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c -index ec6d298..34c7193 100644 +index 47c3764..e37e4b5 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c -@@ -311,7 +311,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) +@@ -305,7 +305,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma) const char *name = NULL; if (file) { @@ -402,7 +390,7 @@ index ec6d298..34c7193 100644 dev = inode->i_sb->s_dev; ino = inode->i_ino; pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT; -@@ -1741,7 +1744,7 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid) +@@ -1729,7 +1732,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; @@ -412,10 +400,10 @@ index ec6d298..34c7193 100644 struct mm_walk walk = { .hugetlb_entry = gather_hugetlb_stats, diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c -index 5b62f57..dfb4a3b 100644 +index 0b63d68..400d1c5 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c -@@ -156,7 +156,10 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma, +@@ -155,7 +155,10 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma) file = vma->vm_file; if (file) { @@ -428,10 +416,10 @@ index 5b62f57..dfb4a3b 100644 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 ad06d42..75e5d37 100644 +index 5411de9..b3cd025 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h -@@ -1368,6 +1368,28 @@ static inline void unmap_shared_mapping_range(struct address_space *mapping, +@@ -1460,6 +1460,28 @@ static inline void unmap_shared_mapping_range(struct address_space *mapping, unmap_mapping_range(mapping, holebegin, holelen, 0); } @@ -461,10 +449,10 @@ index ad06d42..75e5d37 100644 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 fd1af6b..89ec438 100644 +index 5ed8f62..0122975 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h -@@ -249,6 +249,7 @@ struct vm_region { +@@ -239,6 +239,7 @@ 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 */ @@ -472,7 +460,7 @@ index fd1af6b..89ec438 100644 int vm_usage; /* region usage count (access under nommu_region_sem) */ bool vm_icache_flushed : 1; /* true if the icache has been flushed for -@@ -323,6 +324,7 @@ struct vm_area_struct { +@@ -313,6 +314,7 @@ 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). */ @@ -481,10 +469,10 @@ index fd1af6b..89ec438 100644 atomic_long_t swap_readahead_info; diff --git a/kernel/fork.c b/kernel/fork.c -index e5d9d40..f6f6fbf 100644 +index 07cddff..d837e55 100644 --- a/kernel/fork.c +++ b/kernel/fork.c -@@ -474,7 +474,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, +@@ -546,7 +546,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, struct inode *inode = file_inode(file); struct address_space *mapping = file->f_mapping; @@ -494,24 +482,24 @@ index e5d9d40..f6f6fbf 100644 atomic_dec(&inode->i_writecount); i_mmap_lock_write(mapping); diff --git a/mm/Makefile b/mm/Makefile -index e669f02..9c36567 100644 +index d210cc9..e77e80c 100644 --- a/mm/Makefile +++ b/mm/Makefile -@@ -39,7 +39,7 @@ obj-y := filemap.o mempool.o oom_kill.o \ +@@ -39,7 +39,7 @@ obj-y := filemap.o mempool.o oom_kill.o fadvise.o \ mm_init.o mmu_context.o percpu.o slab_common.o \ - compaction.o vmacache.o swap_slots.o \ + compaction.o vmacache.o \ interval_tree.o list_lru.o workingset.o \ - debug.o $(mmu-y) + prfile.o debug.o $(mmu-y) obj-y += init-mm.o - + obj-y += memblock.o diff --git a/mm/filemap.c b/mm/filemap.c -index 693f622..ea46048 100644 +index 81adec8..8507cec 100644 --- a/mm/filemap.c +++ b/mm/filemap.c -@@ -2703,7 +2703,7 @@ int filemap_page_mkwrite(struct vm_fault *vmf) - int ret = VM_FAULT_LOCKED; +@@ -2609,7 +2609,7 @@ vm_fault_t filemap_page_mkwrite(struct vm_fault *vmf) + vm_fault_t ret = VM_FAULT_LOCKED; sb_start_pagefault(inode->i_sb); - file_update_time(vmf->vma->vm_file); @@ -520,19 +508,19 @@ index 693f622..ea46048 100644 if (page->mapping != inode->i_mapping) { unlock_page(page); diff --git a/mm/mmap.c b/mm/mmap.c -index 9efdc021..d77f01f 100644 +index 6c04292..f3629c1 100644 --- a/mm/mmap.c +++ b/mm/mmap.c -@@ -171,7 +171,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma) +@@ -180,7 +180,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma) if (vma->vm_ops && vma->vm_ops->close) vma->vm_ops->close(vma); if (vma->vm_file) - fput(vma->vm_file); + vma_fput(vma); mpol_put(vma_policy(vma)); - kmem_cache_free(vm_area_cachep, vma); + vm_area_free(vma); return next; -@@ -896,7 +896,7 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start, +@@ -929,7 +929,7 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start, if (remove_next) { if (file) { uprobe_munmap(next, next->vm_start, next->vm_end); @@ -541,7 +529,7 @@ index 9efdc021..d77f01f 100644 } if (next->anon_vma) anon_vma_merge(vma, next); -@@ -1761,8 +1761,8 @@ unsigned long mmap_region(struct file *file, unsigned long addr, +@@ -1845,8 +1845,8 @@ unsigned long mmap_region(struct file *file, unsigned long addr, return addr; unmap_and_free_vma: @@ -551,7 +539,7 @@ index 9efdc021..d77f01f 100644 /* Undo any partial mapping done by a device driver. */ unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end); -@@ -2586,7 +2586,7 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, +@@ -2665,7 +2665,7 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, goto out_free_mpol; if (new->vm_file) @@ -560,7 +548,7 @@ index 9efdc021..d77f01f 100644 if (new->vm_ops && new->vm_ops->open) new->vm_ops->open(new); -@@ -2605,7 +2605,7 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, +@@ -2684,7 +2684,7 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, if (new->vm_ops && new->vm_ops->close) new->vm_ops->close(new); if (new->vm_file) @@ -569,16 +557,16 @@ index 9efdc021..d77f01f 100644 unlink_anon_vmas(new); out_free_mpol: mpol_put(vma_policy(new)); -@@ -2767,7 +2767,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, +@@ -2874,7 +2874,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, struct vm_area_struct *vma; unsigned long populate = 0; unsigned long ret = -EINVAL; - struct file *file; + struct file *file, *prfile; - pr_warn_once("%s (%d) uses deprecated remap_file_pages() syscall. See Documentation/vm/remap_file_pages.txt.\n", + pr_warn_once("%s (%d) uses deprecated remap_file_pages() syscall. See Documentation/vm/remap_file_pages.rst.\n", current->comm, current->pid); -@@ -2842,10 +2842,27 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, +@@ -2949,10 +2949,27 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, } } @@ -607,7 +595,7 @@ index 9efdc021..d77f01f 100644 out: up_write(&mm->mmap_sem); if (populate) -@@ -3153,7 +3170,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, +@@ -3258,7 +3275,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) @@ -617,10 +605,10 @@ index 9efdc021..d77f01f 100644 new_vma->vm_ops->open(new_vma); vma_link(mm, new_vma, prev, rb_link, rb_parent); diff --git a/mm/nommu.c b/mm/nommu.c -index ebb6e61..8cf2428 100644 +index 749276b..d56f8f2 100644 --- a/mm/nommu.c +++ b/mm/nommu.c -@@ -641,7 +641,7 @@ static void __put_nommu_region(struct vm_region *region) +@@ -625,7 +625,7 @@ static void __put_nommu_region(struct vm_region *region) up_write(&nommu_region_sem); if (region->vm_file) @@ -629,16 +617,16 @@ index ebb6e61..8cf2428 100644 /* IO memory and memory shared directly out of the pagecache * from ramfs/tmpfs mustn't be released here */ -@@ -799,7 +799,7 @@ static void delete_vma(struct mm_struct *mm, struct vm_area_struct *vma) +@@ -763,7 +763,7 @@ static void delete_vma(struct mm_struct *mm, struct vm_area_struct *vma) if (vma->vm_ops && vma->vm_ops->close) vma->vm_ops->close(vma); if (vma->vm_file) - fput(vma->vm_file); + vma_fput(vma); put_nommu_region(vma->vm_region); - kmem_cache_free(vm_area_cachep, vma); + vm_area_free(vma); } -@@ -1321,7 +1321,7 @@ unsigned long do_mmap(struct file *file, +@@ -1286,7 +1286,7 @@ unsigned long do_mmap(struct file *file, goto error_just_free; } } @@ -647,7 +635,7 @@ index ebb6e61..8cf2428 100644 kmem_cache_free(vm_region_jar, region); region = pregion; result = start; -@@ -1396,10 +1396,10 @@ unsigned long do_mmap(struct file *file, +@@ -1361,7 +1361,7 @@ unsigned long do_mmap(struct file *file, up_write(&nommu_region_sem); error: if (region->vm_file) @@ -655,26 +643,22 @@ index ebb6e61..8cf2428 100644 + vmr_fput(region); kmem_cache_free(vm_region_jar, region); if (vma->vm_file) -- fput(vma->vm_file); -+ vma_fput(vma); - kmem_cache_free(vm_area_cachep, vma); - return ret; - + fput(vma->vm_file); diff --git a/mm/prfile.c b/mm/prfile.c new file mode 100644 -index 0000000..3f56669 +index 0000000..a27ac36 --- /dev/null +++ b/mm/prfile.c @@ -0,0 +1,86 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * 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-2017 Junjro R. Okajima ++ * Copyright (c) 2014-2018 Junjro R. Okajima + * Copyright (c) 2014 Ian Campbell + */ + @@ -756,10 +740,10 @@ SPDX-License-Identifier: GPL-2.0 aufs4.x-rcN standalone patch diff --git a/fs/dcache.c b/fs/dcache.c -index 9ce5e26..0f59369 100644 +index 6369b30..df4a5fe 100644 --- a/fs/dcache.c +++ b/fs/dcache.c -@@ -1308,6 +1308,7 @@ void d_walk(struct dentry *parent, void *data, +@@ -1329,6 +1329,7 @@ void d_walk(struct dentry *parent, void *data, seq = 1; goto again; } @@ -767,7 +751,7 @@ index 9ce5e26..0f59369 100644 struct check_mount { struct vfsmount *mnt; -@@ -2920,6 +2921,7 @@ void d_exchange(struct dentry *dentry1, struct dentry *dentry2) +@@ -2817,6 +2818,7 @@ void d_exchange(struct dentry *dentry1, struct dentry *dentry2) write_sequnlock(&rename_lock); } @@ -776,7 +760,7 @@ index 9ce5e26..0f59369 100644 /** * d_ancestor - search for an ancestor diff --git a/fs/exec.c b/fs/exec.c -index 7eb8d21..56d7985 100644 +index fc281b7..65eaaca 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -109,6 +109,7 @@ bool path_noexec(const struct path *path) @@ -788,7 +772,7 @@ index 7eb8d21..56d7985 100644 #ifdef CONFIG_USELIB /* diff --git a/fs/fcntl.c b/fs/fcntl.c -index 8cd01f7..bdd1c6c 100644 +index 78234ee..2072f69 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -85,6 +85,7 @@ int setfl(int fd, struct file * filp, unsigned long arg) @@ -800,18 +784,18 @@ index 8cd01f7..bdd1c6c 100644 static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, int force) diff --git a/fs/file_table.c b/fs/file_table.c -index 7ec0b3e..819ee07 100644 +index e49af4c..569020f 100644 --- a/fs/file_table.c +++ b/fs/file_table.c -@@ -147,6 +147,7 @@ struct file *get_empty_filp(void) +@@ -161,6 +161,7 @@ struct file *alloc_empty_file(int flags, const struct cred *cred) } return ERR_PTR(-ENFILE); } -+EXPORT_SYMBOL_GPL(get_empty_filp); ++EXPORT_SYMBOL_GPL(alloc_empty_file); - /** - * alloc_file - allocate and initialize a 'struct file' -@@ -257,6 +258,7 @@ void flush_delayed_fput(void) + /* + * Variant of alloc_empty_file() that doesn't check and modify nr_files. +@@ -323,6 +324,7 @@ void flush_delayed_fput(void) { delayed_fput(NULL); } @@ -819,27 +803,19 @@ index 7ec0b3e..819ee07 100644 static DECLARE_DELAYED_WORK(delayed_fput_work, delayed_fput); -@@ -299,6 +301,7 @@ void __fput_sync(struct file *file) +@@ -365,6 +367,7 @@ void __fput_sync(struct file *file) } EXPORT_SYMBOL(fput); +EXPORT_SYMBOL_GPL(__fput_sync); - void put_filp(struct file *file) - { -@@ -307,6 +310,7 @@ void put_filp(struct file *file) - file_free(file); - } - } -+EXPORT_SYMBOL_GPL(put_filp); - void __init files_init(void) { diff --git a/fs/inode.c b/fs/inode.c -index 929a5a3..d93653e 100644 +index d2395eb..b8be7be 100644 --- a/fs/inode.c +++ b/fs/inode.c -@@ -1668,6 +1668,7 @@ int update_time(struct inode *inode, struct timespec *time, int flags) +@@ -1669,6 +1669,7 @@ int update_time(struct inode *inode, struct timespec64 *time, int flags) return update_time(inode, time, flags); } @@ -848,10 +824,10 @@ index 929a5a3..d93653e 100644 /** * touch_atime - update the access time diff --git a/fs/namespace.c b/fs/namespace.c -index 26ef600..a4b9707 100644 +index 46ed643..44502c2 100644 --- a/fs/namespace.c +++ b/fs/namespace.c -@@ -517,6 +517,7 @@ void __mnt_drop_write(struct vfsmount *mnt) +@@ -437,6 +437,7 @@ void __mnt_drop_write(struct vfsmount *mnt) mnt_dec_writers(real_mount(mnt)); preempt_enable(); } @@ -859,7 +835,7 @@ index 26ef600..a4b9707 100644 /** * mnt_drop_write - give up write access to a mount -@@ -851,6 +852,7 @@ int is_current_mnt_ns(struct vfsmount *mnt) +@@ -775,6 +776,7 @@ int is_current_mnt_ns(struct vfsmount *mnt) { return check_mnt(real_mount(mnt)); } @@ -867,7 +843,7 @@ index 26ef600..a4b9707 100644 /* * vfsmount lock must be held for write -@@ -1887,6 +1889,7 @@ int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg, +@@ -1844,6 +1846,7 @@ int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg, } return 0; } @@ -876,18 +852,18 @@ index 26ef600..a4b9707 100644 static void cleanup_group_ids(struct mount *mnt, struct mount *end) { diff --git a/fs/notify/group.c b/fs/notify/group.c -index b7a4b6a..5a69d60 100644 +index c03b836..817f22c 100644 --- a/fs/notify/group.c +++ b/fs/notify/group.c -@@ -22,6 +22,7 @@ - #include +@@ -23,6 +23,7 @@ #include #include + #include +#include #include #include "fsnotify.h" -@@ -109,6 +110,7 @@ void fsnotify_get_group(struct fsnotify_group *group) +@@ -112,6 +113,7 @@ void fsnotify_get_group(struct fsnotify_group *group) { refcount_inc(&group->refcnt); } @@ -895,7 +871,7 @@ index b7a4b6a..5a69d60 100644 /* * Drop a reference to a group. Free it if it's through. -@@ -118,6 +120,7 @@ void fsnotify_put_group(struct fsnotify_group *group) +@@ -121,6 +123,7 @@ void fsnotify_put_group(struct fsnotify_group *group) if (refcount_dec_and_test(&group->refcnt)) fsnotify_final_destroy_group(group); } @@ -903,7 +879,7 @@ index b7a4b6a..5a69d60 100644 /* * Create a new fsnotify_group and hold a reference for the group returned. -@@ -147,6 +150,7 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) +@@ -150,6 +153,7 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) return group; } @@ -912,18 +888,18 @@ index b7a4b6a..5a69d60 100644 int fsnotify_fasync(int fd, struct file *file, int on) { diff --git a/fs/notify/mark.c b/fs/notify/mark.c -index e9191b4..1f8ccfa 100644 +index d2dd16c..cf709b7 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c -@@ -108,6 +108,7 @@ void fsnotify_get_mark(struct fsnotify_mark *mark) - WARN_ON_ONCE(!refcount_read(&mark->refcnt)); - refcount_inc(&mark->refcnt); +@@ -289,6 +289,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) + queue_delayed_work(system_unbound_wq, &reaper_work, + FSNOTIFY_REAPER_DELAY); } +EXPORT_SYMBOL_GPL(fsnotify_put_mark); - static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) - { -@@ -392,6 +393,7 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark, + /* + * Get mark reference when we found the mark via lockless traversal of object +@@ -443,6 +444,7 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark, mutex_unlock(&group->mark_mutex); fsnotify_free_mark(mark); } @@ -931,15 +907,15 @@ index e9191b4..1f8ccfa 100644 /* * Sorting function for lists of fsnotify marks. -@@ -606,6 +608,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, struct inode *inode, - fsnotify_put_mark(mark); +@@ -658,6 +660,7 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_connp_t *connp, + mutex_unlock(&group->mark_mutex); return ret; } +EXPORT_SYMBOL_GPL(fsnotify_add_mark); - int fsnotify_add_mark(struct fsnotify_mark *mark, struct inode *inode, - struct vfsmount *mnt, int allow_dups) -@@ -741,6 +744,7 @@ void fsnotify_init_mark(struct fsnotify_mark *mark, + /* + * Given a list of marks, find the mark associated with given group. If found +@@ -781,6 +784,7 @@ void fsnotify_init_mark(struct fsnotify_mark *mark, fsnotify_get_group(group); mark->group = group; } @@ -948,7 +924,7 @@ index e9191b4..1f8ccfa 100644 /* * Destroy all marks in destroy_list, waits for SRCU period to finish before diff --git a/fs/open.c b/fs/open.c -index 7ea1184..6e2e241 100644 +index 0285ce7..cb81623 100644 --- a/fs/open.c +++ b/fs/open.c @@ -64,6 +64,7 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, @@ -959,19 +935,11 @@ index 7ea1184..6e2e241 100644 long vfs_truncate(const struct path *path, loff_t length) { -@@ -691,6 +692,7 @@ int open_check_o_direct(struct file *f) - } - return 0; - } -+EXPORT_SYMBOL_GPL(open_check_o_direct); - - static int do_dentry_open(struct file *f, - struct inode *inode, diff --git a/fs/read_write.c b/fs/read_write.c -index 0a5c47b..d423a5f 100644 +index a2a55ea..a1366ed 100644 --- a/fs/read_write.c +++ b/fs/read_write.c -@@ -454,6 +454,7 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) +@@ -459,6 +459,7 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) return ret; } @@ -979,7 +947,7 @@ index 0a5c47b..d423a5f 100644 static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) { -@@ -494,6 +495,7 @@ vfs_readf_t vfs_readf(struct file *file) +@@ -499,6 +500,7 @@ vfs_readf_t vfs_readf(struct file *file) return new_sync_read; return ERR_PTR(-ENOSYS); } @@ -987,7 +955,7 @@ index 0a5c47b..d423a5f 100644 vfs_writef_t vfs_writef(struct file *file) { -@@ -505,6 +507,7 @@ vfs_writef_t vfs_writef(struct file *file) +@@ -510,6 +512,7 @@ vfs_writef_t vfs_writef(struct file *file) return new_sync_write; return ERR_PTR(-ENOSYS); } @@ -995,7 +963,7 @@ index 0a5c47b..d423a5f 100644 ssize_t __kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos) { -@@ -574,6 +577,7 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ +@@ -579,6 +582,7 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ return ret; } @@ -1004,7 +972,7 @@ index 0a5c47b..d423a5f 100644 static inline loff_t file_pos_read(struct file *file) { diff --git a/fs/splice.c b/fs/splice.c -index c5fb195..ce01a74 100644 +index 5dcf77b..63fe265 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -850,6 +850,7 @@ long do_splice_from(struct pipe_inode_info *pipe, struct file *out, @@ -1024,7 +992,7 @@ index c5fb195..ce01a74 100644 /** * splice_direct_to_actor - splices data directly between two non-pipes diff --git a/fs/sync.c b/fs/sync.c -index a6891ee..47a78bd 100644 +index 2860782..ffd7ea4 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -39,6 +39,7 @@ int __sync_filesystem(struct super_block *sb, int wait) @@ -1036,10 +1004,10 @@ index a6891ee..47a78bd 100644 /* * Write out and wait upon all dirty data associated with this diff --git a/fs/xattr.c b/fs/xattr.c -index 61cd28b..35570cd 100644 +index 0d6a6a4..7ce4701 100644 --- a/fs/xattr.c +++ b/fs/xattr.c -@@ -297,6 +297,7 @@ vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value, +@@ -295,6 +295,7 @@ vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value, *xattr_value = value; return error; } @@ -1048,7 +1016,7 @@ index 61cd28b..35570cd 100644 ssize_t __vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name, diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c -index 0dca42f..7bb20c5 100644 +index 447bc0b..4e7581c 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -151,6 +151,7 @@ inline struct lock_class *lockdep_hlock_class(struct held_lock *hlock) @@ -1069,10 +1037,10 @@ index 0fef395..83fb1ec 100644 } +EXPORT_SYMBOL_GPL(task_work_run); diff --git a/security/commoncap.c b/security/commoncap.c -index 48620c9..4981104 100644 +index 18a4fdf..e49f723 100644 --- a/security/commoncap.c +++ b/security/commoncap.c -@@ -1330,12 +1330,14 @@ int cap_mmap_addr(unsigned long addr) +@@ -1333,12 +1333,14 @@ int cap_mmap_addr(unsigned long addr) } return ret; } @@ -1088,7 +1056,7 @@ index 48620c9..4981104 100644 #ifdef CONFIG_SECURITY diff --git a/security/device_cgroup.c b/security/device_cgroup.c -index c65b39b..e363d22 100644 +index cd97929..424fd23 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -8,6 +8,7 @@ @@ -1105,10 +1073,10 @@ index c65b39b..e363d22 100644 } +EXPORT_SYMBOL_GPL(__devcgroup_check_permission); diff --git a/security/security.c b/security/security.c -index 1cd8526..f2e4736 100644 +index 04d173e..470af62 100644 --- a/security/security.c +++ b/security/security.c -@@ -531,6 +531,7 @@ int security_path_rmdir(const struct path *dir, struct dentry *dentry) +@@ -553,6 +553,7 @@ int security_path_rmdir(const struct path *dir, struct dentry *dentry) return 0; return call_int_hook(path_rmdir, 0, dir, dentry); } @@ -1116,7 +1084,7 @@ index 1cd8526..f2e4736 100644 int security_path_unlink(const struct path *dir, struct dentry *dentry) { -@@ -547,6 +548,7 @@ int security_path_symlink(const struct path *dir, struct dentry *dentry, +@@ -569,6 +570,7 @@ int security_path_symlink(const struct path *dir, struct dentry *dentry, return 0; return call_int_hook(path_symlink, 0, dir, dentry, old_name); } @@ -1124,7 +1092,7 @@ index 1cd8526..f2e4736 100644 int security_path_link(struct dentry *old_dentry, const struct path *new_dir, struct dentry *new_dentry) -@@ -555,6 +557,7 @@ int security_path_link(struct dentry *old_dentry, const struct path *new_dir, +@@ -577,6 +579,7 @@ int security_path_link(struct dentry *old_dentry, const struct path *new_dir, return 0; return call_int_hook(path_link, 0, old_dentry, new_dir, new_dentry); } @@ -1132,7 +1100,7 @@ index 1cd8526..f2e4736 100644 int security_path_rename(const struct path *old_dir, struct dentry *old_dentry, const struct path *new_dir, struct dentry *new_dentry, -@@ -582,6 +585,7 @@ int security_path_truncate(const struct path *path) +@@ -604,6 +607,7 @@ int security_path_truncate(const struct path *path) return 0; return call_int_hook(path_truncate, 0, path); } @@ -1140,7 +1108,7 @@ index 1cd8526..f2e4736 100644 int security_path_chmod(const struct path *path, umode_t mode) { -@@ -589,6 +593,7 @@ int security_path_chmod(const struct path *path, umode_t mode) +@@ -611,6 +615,7 @@ int security_path_chmod(const struct path *path, umode_t mode) return 0; return call_int_hook(path_chmod, 0, path, mode); } @@ -1148,7 +1116,7 @@ index 1cd8526..f2e4736 100644 int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid) { -@@ -596,6 +601,7 @@ int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid) +@@ -618,6 +623,7 @@ int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid) return 0; return call_int_hook(path_chown, 0, path, uid, gid); } @@ -1156,7 +1124,7 @@ index 1cd8526..f2e4736 100644 int security_path_chroot(const struct path *path) { -@@ -681,6 +687,7 @@ int security_inode_readlink(struct dentry *dentry) +@@ -703,6 +709,7 @@ int security_inode_readlink(struct dentry *dentry) return 0; return call_int_hook(inode_readlink, 0, dentry); } @@ -1164,7 +1132,7 @@ index 1cd8526..f2e4736 100644 int security_inode_follow_link(struct dentry *dentry, struct inode *inode, bool rcu) -@@ -696,6 +703,7 @@ int security_inode_permission(struct inode *inode, int mask) +@@ -718,6 +725,7 @@ int security_inode_permission(struct inode *inode, int mask) return 0; return call_int_hook(inode_permission, 0, inode, mask); } @@ -1172,7 +1140,7 @@ index 1cd8526..f2e4736 100644 int security_inode_setattr(struct dentry *dentry, struct iattr *attr) { -@@ -867,6 +875,7 @@ int security_file_permission(struct file *file, int mask) +@@ -889,6 +897,7 @@ int security_file_permission(struct file *file, int mask) return fsnotify_perm(file, mask); } @@ -1180,7 +1148,7 @@ index 1cd8526..f2e4736 100644 int security_file_alloc(struct file *file) { -@@ -926,6 +935,7 @@ int security_mmap_file(struct file *file, unsigned long prot, +@@ -948,6 +957,7 @@ int security_mmap_file(struct file *file, unsigned long prot, return ret; return ima_file_mmap(file, prot); } @@ -1190,8 +1158,8 @@ index 1cd8526..f2e4736 100644 { diff -urN /usr/share/empty/Documentation/ABI/testing/debugfs-aufs linux/Documentation/ABI/testing/debugfs-aufs --- /usr/share/empty/Documentation/ABI/testing/debugfs-aufs 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/ABI/testing/debugfs-aufs 2018-04-06 07:48:44.201271351 +0200 -@@ -0,0 +1,50 @@ ++++ linux/Documentation/ABI/testing/debugfs-aufs 2018-08-12 23:43:05.450124426 +0200 +@@ -0,0 +1,55 @@ +What: /debug/aufs/si_/ +Date: March 2009 +Contact: J. R. Okajima @@ -1222,15 +1190,20 @@ diff -urN /usr/share/empty/Documentation/ABI/testing/debugfs-aufs linux/Document + When the aufs mount option 'noxino' is specified, it + will be empty. About XINO files, see the aufs manual. + -+What: /debug/aufs/si_/xino0, xino1 ... xinoN ++What: /debug/aufs/si_/xi0, xi1 ... xiN and xiN-N +Date: March 2009 +Contact: J. R. Okajima +Description: + It shows the consumed blocks by xino (External Inode Number + Translation Table), its link count, block size and file + size. -+ When the aufs mount option 'noxino' is specified, it -+ will be empty. About XINO files, see the aufs manual. ++ Due to the file size limit, there may exist multiple ++ xino files per branch. In this case, "-N" is added to ++ the filename and it corresponds to the index of the ++ internal xino array. "-0" is omitted. ++ When the aufs mount option 'noxino' is specified, Those ++ entries won't exist. About XINO files, see the aufs ++ manual. + +What: /debug/aufs/si_/xigen +Date: March 2009 @@ -1244,7 +1217,7 @@ diff -urN /usr/share/empty/Documentation/ABI/testing/debugfs-aufs linux/Document + will be empty. About XINO files, see the aufs manual. diff -urN /usr/share/empty/Documentation/ABI/testing/sysfs-aufs linux/Documentation/ABI/testing/sysfs-aufs --- /usr/share/empty/Documentation/ABI/testing/sysfs-aufs 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/ABI/testing/sysfs-aufs 2018-04-06 07:48:44.201271351 +0200 ++++ linux/Documentation/ABI/testing/sysfs-aufs 2017-07-29 12:14:25.893041746 +0200 @@ -0,0 +1,31 @@ +What: /sys/fs/aufs/si_/ +Date: March 2009 @@ -1279,10 +1252,10 @@ diff -urN /usr/share/empty/Documentation/ABI/testing/sysfs-aufs linux/Documentat + will be empty. About XINO files, see the aufs manual. diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/01intro.txt linux/Documentation/filesystems/aufs/design/01intro.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/01intro.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/01intro.txt 2018-04-06 07:48:44.201271351 +0200 ++++ linux/Documentation/filesystems/aufs/design/01intro.txt 2018-04-15 08:49:13.394483860 +0200 @@ -0,0 +1,171 @@ + -+# Copyright (C) 2005-2017 Junjiro R. Okajima ++# Copyright (C) 2005-2018 Junjiro R. Okajima +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by @@ -1454,10 +1427,10 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/01intro.txt lin +about it. But currently I have implemented it in kernel space. diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/02struct.txt linux/Documentation/filesystems/aufs/design/02struct.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/02struct.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/02struct.txt 2018-04-06 07:48:44.201271351 +0200 ++++ linux/Documentation/filesystems/aufs/design/02struct.txt 2018-04-15 08:49:13.394483860 +0200 @@ -0,0 +1,258 @@ + -+# Copyright (C) 2005-2017 Junjiro R. Okajima ++# Copyright (C) 2005-2018 Junjiro R. Okajima +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by @@ -1716,10 +1689,10 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/02struct.txt li +For this purpose, use "aumvdown" command in aufs-util.git. diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/03atomic_open.txt linux/Documentation/filesystems/aufs/design/03atomic_open.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/03atomic_open.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/03atomic_open.txt 2018-04-06 07:48:44.201271351 +0200 ++++ linux/Documentation/filesystems/aufs/design/03atomic_open.txt 2018-04-15 08:49:13.394483860 +0200 @@ -0,0 +1,85 @@ + -+# Copyright (C) 2015-2017 Junjiro R. Okajima ++# Copyright (C) 2015-2018 Junjiro R. Okajima +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by @@ -1805,10 +1778,10 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/03atomic_open.t + be implemented in aufs, but not all I am afraid. diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/03lookup.txt linux/Documentation/filesystems/aufs/design/03lookup.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/03lookup.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/03lookup.txt 2018-04-06 07:48:44.201271351 +0200 ++++ linux/Documentation/filesystems/aufs/design/03lookup.txt 2018-04-15 08:49:13.394483860 +0200 @@ -0,0 +1,113 @@ + -+# Copyright (C) 2005-2017 Junjiro R. Okajima ++# Copyright (C) 2005-2018 Junjiro R. Okajima +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by @@ -1922,10 +1895,10 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/03lookup.txt li + by over-mounting something (or another method). diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/04branch.txt linux/Documentation/filesystems/aufs/design/04branch.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/04branch.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/04branch.txt 2018-04-06 07:48:44.201271351 +0200 ++++ linux/Documentation/filesystems/aufs/design/04branch.txt 2018-04-15 08:49:13.394483860 +0200 @@ -0,0 +1,74 @@ + -+# Copyright (C) 2005-2017 Junjiro R. Okajima ++# Copyright (C) 2005-2018 Junjiro R. Okajima +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by @@ -2000,10 +1973,10 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/04branch.txt li + same named entry on the upper branch. diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/05wbr_policy.txt linux/Documentation/filesystems/aufs/design/05wbr_policy.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/05wbr_policy.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/05wbr_policy.txt 2018-04-06 07:48:44.201271351 +0200 ++++ linux/Documentation/filesystems/aufs/design/05wbr_policy.txt 2018-04-15 08:49:13.394483860 +0200 @@ -0,0 +1,64 @@ + -+# Copyright (C) 2005-2017 Junjiro R. Okajima ++# Copyright (C) 2005-2018 Junjiro R. Okajima +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by @@ -2068,7 +2041,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/05wbr_policy.tx + copyup policy. diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/06dirren.dot linux/Documentation/filesystems/aufs/design/06dirren.dot --- /usr/share/empty/Documentation/filesystems/aufs/design/06dirren.dot 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/06dirren.dot 2018-04-06 07:48:44.201271351 +0200 ++++ linux/Documentation/filesystems/aufs/design/06dirren.dot 2018-04-15 08:49:13.394483860 +0200 @@ -0,0 +1,31 @@ + +// to view this graph, run dot(1) command in GRAPHVIZ. @@ -2103,10 +2076,10 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/06dirren.dot li +} diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/06dirren.txt linux/Documentation/filesystems/aufs/design/06dirren.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/06dirren.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/06dirren.txt 2018-04-06 07:48:44.201271351 +0200 ++++ linux/Documentation/filesystems/aufs/design/06dirren.txt 2018-04-15 08:49:13.394483860 +0200 @@ -0,0 +1,102 @@ + -+# Copyright (C) 2017 Junjiro R. Okajima ++# Copyright (C) 2017-2018 Junjiro R. Okajima +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by @@ -2209,10 +2182,10 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/06dirren.txt li +equivalen to udba=reval case. diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/06fhsm.txt linux/Documentation/filesystems/aufs/design/06fhsm.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/06fhsm.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/06fhsm.txt 2018-04-06 07:48:44.201271351 +0200 ++++ linux/Documentation/filesystems/aufs/design/06fhsm.txt 2018-04-15 08:49:13.394483860 +0200 @@ -0,0 +1,120 @@ + -+# Copyright (C) 2011-2017 Junjiro R. Okajima ++# Copyright (C) 2011-2018 Junjiro R. Okajima +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by @@ -2333,10 +2306,10 @@ 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 2018-04-06 07:48:44.201271351 +0200 ++++ linux/Documentation/filesystems/aufs/design/06mmap.txt 2018-04-15 08:49:13.394483860 +0200 @@ -0,0 +1,72 @@ + -+# Copyright (C) 2005-2017 Junjiro R. Okajima ++# Copyright (C) 2005-2018 Junjiro R. Okajima +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by @@ -2409,10 +2382,10 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/06mmap.txt linu +I have to give up this "looks-smater" approach. 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 2018-04-06 07:48:44.201271351 +0200 ++++ linux/Documentation/filesystems/aufs/design/06xattr.txt 2018-04-15 08:49:13.394483860 +0200 @@ -0,0 +1,96 @@ + -+# Copyright (C) 2014-2017 Junjiro R. Okajima ++# Copyright (C) 2014-2018 Junjiro R. Okajima +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by @@ -2509,10 +2482,10 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/06xattr.txt lin +now, aufs implements the branch attributes to ignore the error. diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/07export.txt linux/Documentation/filesystems/aufs/design/07export.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/07export.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/07export.txt 2018-04-06 07:48:44.201271351 +0200 ++++ linux/Documentation/filesystems/aufs/design/07export.txt 2018-04-15 08:49:13.394483860 +0200 @@ -0,0 +1,58 @@ + -+# Copyright (C) 2005-2017 Junjiro R. Okajima ++# Copyright (C) 2005-2018 Junjiro R. Okajima +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by @@ -2571,10 +2544,10 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/07export.txt li + lookup_one_len(), vfs_getattr(), encode_fh() and others. diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/08shwh.txt linux/Documentation/filesystems/aufs/design/08shwh.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/08shwh.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/08shwh.txt 2018-04-06 07:48:44.201271351 +0200 ++++ linux/Documentation/filesystems/aufs/design/08shwh.txt 2018-04-15 08:49:13.394483860 +0200 @@ -0,0 +1,52 @@ + -+# Copyright (C) 2005-2017 Junjiro R. Okajima ++# Copyright (C) 2005-2018 Junjiro R. Okajima +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by @@ -2627,10 +2600,10 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/08shwh.txt linu +initramfs will use it to replace the old one at the next boot. diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/10dynop.txt linux/Documentation/filesystems/aufs/design/10dynop.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/10dynop.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/10dynop.txt 2018-04-06 07:48:44.201271351 +0200 ++++ linux/Documentation/filesystems/aufs/design/10dynop.txt 2018-04-15 08:49:13.394483860 +0200 @@ -0,0 +1,47 @@ + -+# Copyright (C) 2010-2017 Junjiro R. Okajima ++# Copyright (C) 2010-2018 Junjiro R. Okajima +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by @@ -2678,8 +2651,8 @@ 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 2018-04-06 07:48:44.201271351 +0200 -@@ -0,0 +1,393 @@ ++++ linux/Documentation/filesystems/aufs/README 2018-12-27 13:19:17.705082621 +0100 +@@ -0,0 +1,395 @@ + +Aufs4 -- advanced multi layered unification filesystem version 4.x +http://aufs.sf.net @@ -3053,9 +3026,11 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/README linux/Documenta +James B made a donation (2014/7 and 2015/7). +Stefano Di Biase made a donation (2014/8). +Daniel Epellei made a donation (2015/1). -+OmegaPhil made a donation (2016/1). ++OmegaPhil made a donation (2016/1, 2018/4). +Tomasz Szewczyk made a donation (2016/4). +James Burry made a donation (2016/12). ++Carsten Rose made a donation (2018/9). ++Porteus Kiosk made a donation (2018/10). + +Thank you very much. +Donations are always, including future donations, very important and @@ -3075,10 +3050,11 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/README linux/Documenta +# End: ; diff -urN /usr/share/empty/fs/aufs/aufs.h linux/fs/aufs/aufs.h --- /usr/share/empty/fs/aufs/aufs.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/aufs.h 2018-04-06 07:48:44.201271351 +0200 -@@ -0,0 +1,60 @@ ++++ linux/fs/aufs/aufs.h 2018-10-23 12:33:35.592708932 +0200 +@@ -0,0 +1,62 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -3125,6 +3101,7 @@ diff -urN /usr/share/empty/fs/aufs/aufs.h linux/fs/aufs/aufs.h +#include "fstype.h" +#include "hbl.h" +#include "inode.h" ++#include "lcnt.h" +#include "loop.h" +#include "module.h" +#include "opts.h" @@ -3139,10 +3116,11 @@ diff -urN /usr/share/empty/fs/aufs/aufs.h linux/fs/aufs/aufs.h +#endif /* __AUFS_H__ */ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c --- /usr/share/empty/fs/aufs/branch.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/branch.c 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,1432 @@ ++++ linux/fs/aufs/branch.c 2018-12-27 13:19:17.708416053 +0100 +@@ -0,0 +1,1422 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -3178,15 +3156,12 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + au_hnotify_fin_br(br); + /* always, regardless the mount option */ + au_dr_hino_free(&br->br_dirren); ++ au_xino_put(br); + -+ if (br->br_xino.xi_file) -+ fput(br->br_xino.xi_file); -+ for (i = br->br_xino.xi_nondir.total - 1; i >= 0; i--) -+ AuDebugOn(br->br_xino.xi_nondir.array[i]); -+ kfree(br->br_xino.xi_nondir.array); -+ -+ AuDebugOn(au_br_count(br)); -+ au_br_count_fin(br); ++ AuLCntZero(au_lcnt_read(&br->br_nfiles, /*do_rev*/0)); ++ au_lcnt_fin(&br->br_nfiles, /*do_sync*/0); ++ AuLCntZero(au_lcnt_read(&br->br_count, /*do_rev*/0)); ++ au_lcnt_fin(&br->br_count, /*do_sync*/0); + + wbr = br->br_wbr; + if (wbr) { @@ -3198,7 +3173,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + + if (br->br_fhsm) { + au_br_fhsm_fin(br->br_fhsm); -+ kfree(br->br_fhsm); ++ au_kfree_try_rcu(br->br_fhsm); + } + + key = br->br_dykey; @@ -3209,11 +3184,16 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + break; + + /* recursive lock, s_umount of branch's */ ++ /* synchronize_rcu(); */ /* why? */ + lockdep_off(); + path_put(&br->br_path); + lockdep_on(); -+ kfree(wbr); -+ kfree(br); ++ au_kfree_rcu(wbr); ++ au_lcnt_wait_for_fin(&br->br_nfiles); ++ au_lcnt_wait_for_fin(&br->br_count); ++ /* I don't know why, but percpu_refcount requires this */ ++ /* synchronize_rcu(); */ ++ au_kfree_rcu(br); +} + +/* @@ -3280,16 +3260,12 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + add_branch = kzalloc(sizeof(*add_branch), GFP_NOFS); + if (unlikely(!add_branch)) + goto out; -+ add_branch->br_xino.xi_nondir.total = 8; /* initial size */ -+ add_branch->br_xino.xi_nondir.array -+ = kcalloc(add_branch->br_xino.xi_nondir.total, sizeof(ino_t), -+ GFP_NOFS); -+ if (unlikely(!add_branch->br_xino.xi_nondir.array)) ++ add_branch->br_xino = au_xino_alloc(/*nfile*/1); ++ if (unlikely(!add_branch->br_xino)) + goto out_br; -+ + err = au_hnotify_init_br(add_branch, perm); + if (unlikely(err)) -+ goto out_xinondir; ++ goto out_xino; + + if (au_br_writable(perm)) { + /* may be freed separately at changing the branch permission */ @@ -3318,13 +3294,13 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + return add_branch; /* success */ + +out_wbr: -+ kfree(add_branch->br_wbr); ++ au_kfree_rcu(add_branch->br_wbr); +out_hnotify: + au_hnotify_fin_br(add_branch); -+out_xinondir: -+ kfree(add_branch->br_xino.xi_nondir.array); ++out_xino: ++ au_xino_put(add_branch); +out_br: -+ kfree(add_branch); ++ au_kfree_rcu(add_branch); +out: + return ERR_PTR(err); +} @@ -3490,7 +3466,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + br->br_perm = old_perm; + + if (!err && wbr && !au_br_writable(new_perm)) { -+ kfree(wbr); ++ au_kfree_rcu(wbr); + br->br_wbr = NULL; + } + @@ -3533,16 +3509,16 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + struct au_opt_add *add) +{ + int err; ++ struct au_branch *brbase; ++ struct file *xf; + struct inode *h_inode; + + err = 0; -+ spin_lock_init(&br->br_xino.xi_nondir.spin); -+ init_waitqueue_head(&br->br_xino.xi_nondir.wqh); + br->br_perm = add->perm; + br->br_path = add->path; /* set first, path_get() later */ + spin_lock_init(&br->br_dykey_lock); -+ au_br_count_init(br); -+ atomic_set(&br->br_xino_running, 0); ++ au_lcnt_init(&br->br_nfiles, /*release*/NULL); ++ au_lcnt_init(&br->br_count, /*release*/NULL); + br->br_id = au_new_br_id(sb); + AuDebugOn(br->br_id < 0); + @@ -3558,11 +3534,13 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + } + + if (au_opt_test(au_mntflags(sb), XINO)) { ++ brbase = au_sbr(sb, 0); ++ xf = au_xino_file(brbase->br_xino, /*idx*/-1); ++ AuDebugOn(!xf); + h_inode = d_inode(add->path.dentry); -+ err = au_xino_br(sb, br, h_inode->i_ino, -+ au_sbr(sb, 0)->br_xino.xi_file, /*do_test*/1); ++ err = au_xino_init_br(sb, br, h_inode->i_ino, &xf->f_path); + if (unlikely(err)) { -+ AuDebugOn(br->br_xino.xi_file); ++ AuDebugOn(au_xino_file(br->br_xino, /*idx*/-1)); + goto out_err; + } + } @@ -3678,13 +3656,10 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + } + + add_bindex = add->bindex; -+ if (!remount) -+ au_br_do_add(sb, add_branch, add_bindex); -+ else { -+ sysaufs_brs_del(sb, add_bindex); -+ au_br_do_add(sb, add_branch, add_bindex); -+ sysaufs_brs_add(sb, add_bindex); -+ } ++ sysaufs_brs_del(sb, add_bindex); /* remove successors */ ++ au_br_do_add(sb, add_branch, add_bindex); ++ sysaufs_brs_add(sb, add_bindex); /* append successors */ ++ dbgaufs_brs_add(sb, add_bindex, /*topdown*/0); /* rename successors */ + + h_dentry = add->path.dentry; + if (!add_bindex) { @@ -3693,18 +3668,6 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + } else + au_add_nlink(root_inode, d_inode(h_dentry)); + -+ /* -+ * this test/set prevents aufs from handling unnecesary notify events -+ * of xino files, in case of re-adding a writable branch which was -+ * once detached from aufs. -+ */ -+ if (au_xino_brid(sb) < 0 -+ && au_br_writable(add_branch->br_perm) -+ && !au_test_fs_bad_xino(h_dentry->d_sb) -+ && add_branch->br_xino.xi_file -+ && add_branch->br_xino.xi_file->f_path.dentry->d_parent == h_dentry) -+ au_xino_brid_set(sb, add_branch->br_id); -+ +out: + return err; +} @@ -3743,7 +3706,10 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c +static struct file **au_farray_alloc(struct super_block *sb, + unsigned long long *max) +{ -+ *max = au_nfiles(sb); ++ struct au_sbinfo *sbi; ++ ++ sbi = au_sbi(sb); ++ *max = au_lcnt_read(&sbi->si_nfiles, /*do_rev*/1); + return au_array_alloc(max, au_farray_cb, sb, /*arg*/NULL); +} + @@ -4006,7 +3972,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c +} + +static void br_del_file(struct file **to_free, unsigned long long opened, -+ aufs_bindex_t br_id) ++ aufs_bindex_t br_id) +{ + unsigned long long ull; + aufs_bindex_t bindex, btop, bbot, bfound; @@ -4186,11 +4152,16 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + AuVerbose(verbose, "no more branches left\n"); + goto out; + } ++ + br = au_sbr(sb, bindex); + AuDebugOn(!path_equal(&br->br_path, &del->h_path)); ++ if (unlikely(au_lcnt_read(&br->br_count, /*do_rev*/1))) { ++ AuVerbose(verbose, "br %pd2 is busy now\n", del->h_path.dentry); ++ goto out; ++ } + + br_id = br->br_id; -+ opened = au_br_count(br); ++ opened = au_lcnt_read(&br->br_nfiles, /*do_rev*/1); + if (unlikely(opened)) { + to_free = au_array_alloc(&opened, empty_cb, sb, NULL); + err = PTR_ERR(to_free); @@ -4233,13 +4204,11 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + di_write_lock_child(root); + } + -+ if (!remount) -+ au_br_do_del(sb, bindex, br); -+ else { -+ sysaufs_brs_del(sb, bindex); -+ au_br_do_del(sb, bindex, br); -+ sysaufs_brs_add(sb, bindex); -+ } ++ sysaufs_brs_del(sb, bindex); /* remove successors */ ++ dbgaufs_xino_del(br); /* remove one */ ++ au_br_do_del(sb, bindex, br); ++ sysaufs_brs_add(sb, bindex); /* append successors */ ++ dbgaufs_brs_add(sb, bindex, /*topdown*/1); /* rename successors */ + + if (!bindex) { + au_cpup_attr_all(d_inode(root), /*force*/1); @@ -4249,8 +4218,6 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + if (au_opt_test(mnt_flags, PLINK)) + au_plink_half_refresh(sb, br_id); + -+ if (au_xino_brid(sb) == br_id) -+ au_xino_brid_set(sb, -1); + goto out; /* success */ + +out_wh: @@ -4526,7 +4493,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + if (br->br_wbr) { + err = au_wbr_init(br, sb, mod->perm); + if (unlikely(err)) { -+ kfree(br->br_wbr); ++ au_kfree_rcu(br->br_wbr); + br->br_wbr = NULL; + } + } @@ -4538,7 +4505,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + if (!au_br_fhsm(mod->perm)) { + /* fhsm --> non-fhsm */ + au_br_fhsm_fin(br->br_fhsm); -+ kfree(br->br_fhsm); ++ au_kfree_rcu(br->br_fhsm); + br->br_fhsm = NULL; + } + } else if (au_br_fhsm(mod->perm)) @@ -4550,7 +4517,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + goto out; /* success */ + +out_bf: -+ kfree(bf); ++ au_kfree_try_rcu(bf); +out: + AuTraceErr(err); + return err; @@ -4575,10 +4542,11 @@ 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 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,333 @@ ++++ linux/fs/aufs/branch.h 2018-12-27 13:19:17.708416053 +0100 +@@ -0,0 +1,365 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -4606,14 +4574,17 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h +#include +#include "dirren.h" +#include "dynop.h" ++#include "lcnt.h" +#include "rwsem.h" +#include "super.h" + +/* ---------------------------------------------------------------------- */ + +/* a xino file */ -+struct au_xino_file { -+ struct file *xi_file; ++struct au_xino { ++ struct file **xi_file; ++ unsigned int xi_nfile; ++ + struct { + spinlock_t spin; + ino_t *array; @@ -4623,11 +4594,12 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h + wait_queue_head_t wqh; + } xi_nondir; + -+ /* todo: make xino files an array to support huge inode number */ ++ struct mutex xi_mtx; /* protects xi_file array */ ++ struct hlist_bl_head xi_writing; + -+#ifdef CONFIG_DEBUG_FS -+ struct dentry *xi_dbgaufs; -+#endif ++ atomic_t xi_truncating; ++ ++ struct kref xi_kref; +}; + +/* File-based Hierarchical Storage Management */ @@ -4678,7 +4650,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h + +/* protected by superblock rwsem */ +struct au_branch { -+ struct au_xino_file br_xino; ++ struct au_xino *br_xino; + + aufs_bindex_t br_id; + @@ -4686,14 +4658,12 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h + struct path br_path; + spinlock_t br_dykey_lock; + struct au_dykey *br_dykey[AuBrDynOp]; -+ struct percpu_counter br_count; ++ au_lcnt_t br_nfiles; /* opened files */ ++ au_lcnt_t br_count; /* in-use for other */ + + struct au_wbr *br_wbr; + struct au_br_fhsm *br_fhsm; + -+ /* xino truncation */ -+ atomic_t br_xino_running; -+ +#ifdef CONFIG_AUFS_HFSNOTIFY + struct au_br_hfsnotify *br_hfsn; +#endif @@ -4703,6 +4673,10 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h + struct au_brsysfs br_sysfs[AuBrSysfs_Last]; +#endif + ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *br_dbgaufs; /* xino */ ++#endif ++ + struct au_dr_br br_dirren; +}; + @@ -4723,31 +4697,6 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h + return au_br_mnt(br)->mnt_sb; +} + -+static inline void au_br_get(struct au_branch *br) -+{ -+ percpu_counter_inc(&br->br_count); -+} -+ -+static inline void au_br_put(struct au_branch *br) -+{ -+ percpu_counter_dec(&br->br_count); -+} -+ -+static inline s64 au_br_count(struct au_branch *br) -+{ -+ return percpu_counter_sum(&br->br_count); -+} -+ -+static inline void au_br_count_init(struct au_branch *br) -+{ -+ percpu_counter_init(&br->br_count, 0, GFP_NOFS); -+} -+ -+static inline void au_br_count_fin(struct au_branch *br) -+{ -+ percpu_counter_destroy(&br->br_count); -+} -+ +static inline int au_br_rdonly(struct au_branch *br) +{ + return (sb_rdonly(au_br_sb(br)) @@ -4776,6 +4725,28 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h + return err; +} + ++static inline void au_xino_get(struct au_branch *br) ++{ ++ struct au_xino *xi; ++ ++ xi = br->br_xino; ++ if (xi) ++ kref_get(&xi->xi_kref); ++} ++ ++static inline int au_xino_count(struct au_branch *br) ++{ ++ int v; ++ struct au_xino *xi; ++ ++ v = 0; ++ xi = br->br_xino; ++ if (xi) ++ v = kref_read(&xi->xi_kref); ++ ++ return v; ++} ++ +/* ---------------------------------------------------------------------- */ + +/* branch.c */ @@ -4799,34 +4770,72 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h +/* xino.c */ +static const loff_t au_loff_max = LLONG_MAX; + -+int au_xib_trunc(struct super_block *sb); ++aufs_bindex_t au_xi_root(struct super_block *sb, struct dentry *dentry); ++struct file *au_xino_create(struct super_block *sb, char *fpath, int silent); ++struct file *au_xino_create2(struct super_block *sb, struct path *base, ++ struct file *copy_src); ++struct au_xi_new { ++ struct au_xino *xi; /* switch between xino and xigen */ ++ int idx; ++ struct path *base; ++ struct file *copy_src; ++}; ++struct file *au_xi_new(struct super_block *sb, struct au_xi_new *xinew); ++ ++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t *ino); ++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t ino); +ssize_t xino_fread(vfs_readf_t func, struct file *file, void *buf, size_t size, + loff_t *pos); +ssize_t xino_fwrite(vfs_writef_t func, struct file *file, void *buf, + size_t size, loff_t *pos); -+struct file *au_xino_create2(struct file *base_file, struct file *copy_src); -+struct file *au_xino_create(struct super_block *sb, char *fname, int silent); -+ino_t au_xino_new_ino(struct super_block *sb); -+void au_xino_delete_inode(struct inode *inode, const int unlinked); -+int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, -+ ino_t ino); -+int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, -+ ino_t *ino); -+int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t hino, -+ struct file *base_file, int do_test); -+int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex); ++ ++int au_xib_trunc(struct super_block *sb); ++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex, int idx_begin); ++ ++struct au_xino *au_xino_alloc(unsigned int nfile); ++int au_xino_put(struct au_branch *br); ++struct file *au_xino_file1(struct au_xino *xi); + +struct au_opt_xino; -+int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount); +void au_xino_clr(struct super_block *sb); ++int au_xino_set(struct super_block *sb, struct au_opt_xino *xiopt, int remount); +struct file *au_xino_def(struct super_block *sb); -+int au_xino_path(struct seq_file *seq, struct file *file); ++int au_xino_init_br(struct super_block *sb, struct au_branch *br, ino_t hino, ++ struct path *base); ++ ++ino_t au_xino_new_ino(struct super_block *sb); ++void au_xino_delete_inode(struct inode *inode, const int unlinked); + +void au_xinondir_leave(struct super_block *sb, aufs_bindex_t bindex, + ino_t h_ino, int idx); +int au_xinondir_enter(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + int *idx); + ++int au_xino_path(struct seq_file *seq, struct file *file); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* @idx is signed to accept -1 meaning the first file */ ++static inline struct file *au_xino_file(struct au_xino *xi, int idx) ++{ ++ struct file *file; ++ ++ file = NULL; ++ if (!xi) ++ goto out; ++ ++ if (idx >= 0) { ++ if (idx < xi->xi_nfile) ++ file = xi->xi_file[idx]; ++ } else ++ file = au_xino_file1(xi); ++ ++out: ++ return file; ++} ++ +/* ---------------------------------------------------------------------- */ + +/* Superblock to branch */ @@ -4848,16 +4857,6 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h + return au_br_sb(au_sbr(sb, bindex)); +} + -+static inline void au_sbr_get(struct super_block *sb, aufs_bindex_t bindex) -+{ -+ au_br_get(au_sbr(sb, bindex)); -+} -+ -+static inline void au_sbr_put(struct super_block *sb, aufs_bindex_t bindex) -+{ -+ au_br_put(au_sbr(sb, bindex)); -+} -+ +static inline int au_sbr_perm(struct super_block *sb, aufs_bindex_t bindex) +{ + return au_sbr(sb, bindex)->br_perm; @@ -4912,7 +4911,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h +#endif /* __AUFS_BRANCH_H__ */ diff -urN /usr/share/empty/fs/aufs/conf.mk linux/fs/aufs/conf.mk --- /usr/share/empty/fs/aufs/conf.mk 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/conf.mk 2018-04-06 07:48:44.204604724 +0200 ++++ linux/fs/aufs/conf.mk 2018-06-04 09:08:09.181412645 +0200 @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: GPL-2.0 + @@ -4956,10 +4955,11 @@ 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 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,1441 @@ ++++ linux/fs/aufs/cpup.c 2018-12-27 13:19:17.708416053 +0100 +@@ -0,0 +1,1458 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -5296,9 +5296,11 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c + unsigned long blksize; + unsigned char do_kfree; + char *buf; ++ struct super_block *h_sb; + + err = -ENOMEM; -+ blksize = dst->f_path.dentry->d_sb->s_blocksize; ++ h_sb = file_inode(dst)->i_sb; ++ blksize = h_sb->s_blocksize; + if (!blksize || PAGE_SIZE < blksize) + blksize = PAGE_SIZE; + AuDbg("blksize %lu\n", blksize); @@ -5316,9 +5318,10 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c + src->f_pos = 0; + dst->f_pos = 0; + err = au_do_copy_file(dst, src, len, buf, blksize); -+ if (do_kfree) -+ kfree(buf); -+ else ++ if (do_kfree) { ++ AuDebugOn(!au_kfree_do_sz_test(blksize)); ++ au_kfree_do_rcu(buf); ++ } else + free_page((unsigned long)buf); + +out: @@ -5349,26 +5352,36 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c +static int au_clone_or_copy(struct file *dst, struct file *src, loff_t len) +{ + int err; ++ loff_t lo; + struct super_block *h_src_sb; + struct inode *h_src_inode; + + h_src_inode = file_inode(src); + h_src_sb = h_src_inode->i_sb; + if (h_src_sb != file_inode(dst)->i_sb -+ || !dst->f_op->clone_file_range) { ++ || !dst->f_op->remap_file_range) { + err = au_do_copy(dst, src, len); + goto out; + } + + if (!au_test_nfs(h_src_sb)) { + inode_unlock_shared(h_src_inode); -+ err = vfsub_clone_file_range(src, dst, len); ++ lo = vfsub_clone_file_range(src, dst, len); + inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); + } else -+ err = vfsub_clone_file_range(src, dst, len); -+ /* older XFS has a condition in cloning */ -+ if (unlikely(err != -EOPNOTSUPP)) ++ lo = vfsub_clone_file_range(src, dst, len); ++ if (lo == len) { ++ err = 0; ++ goto out; /* success */ ++ } else if (lo >= 0) ++ /* todo: possible? */ ++ /* paritially succeeded */ ++ AuDbg("lo %lld, len %lld. Retrying.\n", lo, len); ++ else if (lo != -EOPNOTSUPP) { ++ /* older XFS has a condition in cloning */ ++ err = lo; + goto out; ++ } + + /* the backend fs on NFS may not support cloning */ + err = au_do_copy(dst, src, len); @@ -5392,20 +5405,18 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c + struct dentry *dentry; + int force_wr; + struct file *file; -+ void *label; + } *f, file[] = { + { + .bindex = cpg->bsrc, + .flags = O_RDONLY | O_NOATIME | O_LARGEFILE, -+ .label = &&out + }, + { + .bindex = cpg->bdst, + .flags = O_WRONLY | O_NOATIME | O_LARGEFILE, + .force_wr = !!au_ftest_cpup(cpg->flags, RWDST), -+ .label = &&out_src + } + }; ++ struct au_branch *br; + struct super_block *sb, *h_src_sb; + struct inode *h_src_inode; + struct task_struct *tsk = current; @@ -5417,9 +5428,13 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c + f->dentry = au_h_dptr(cpg->dentry, f->bindex); + f->file = au_h_open(cpg->dentry, f->bindex, f->flags, + /*file*/NULL, f->force_wr); -+ err = PTR_ERR(f->file); -+ if (IS_ERR(f->file)) -+ goto *f->label; ++ if (IS_ERR(f->file)) { ++ err = PTR_ERR(f->file); ++ if (i == SRC) ++ goto out; ++ else ++ goto out_src; ++ } + } + + /* try stopping to update while we copyup */ @@ -5433,7 +5448,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c + if (tsk->flags & PF_KTHREAD) + __fput_sync(file[DST].file); + else { -+ /* it happend actually */ ++ /* it happened actually */ + fput(file[DST].file); + /* + * too bad. @@ -5443,11 +5458,13 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c + task_work_run(); + flush_delayed_fput(); + } -+ au_sbr_put(sb, file[DST].bindex); ++ br = au_sbr(sb, file[DST].bindex); ++ au_lcnt_dec(&br->br_nfiles); + +out_src: + fput(file[SRC].file); -+ au_sbr_put(sb, file[SRC].bindex); ++ br = au_sbr(sb, file[SRC].bindex); ++ au_lcnt_dec(&br->br_nfiles); +out: + return err; +} @@ -5579,7 +5596,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c + + /* + * strange behaviour from the users view, -+ * particularry setattr case ++ * particularly setattr case + */ + dir = d_inode(dst_parent); + if (au_ibtop(dir) == cpg->bdst) @@ -5635,8 +5652,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c + switch (mode & S_IFMT) { + case S_IFREG: + isreg = 1; -+ err = vfsub_create(h_dir, &h_path, S_IRUSR | S_IWUSR, -+ /*want_excl*/true); ++ err = vfsub_create(h_dir, &h_path, 0600, /*want_excl*/true); + if (!err) + err = au_do_cpup_regular(cpg, h_src_attr); + break; @@ -5741,7 +5757,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c + * in link/rename cases, @dst_parent may be different from the real one. + * basic->bsrc can be larger than basic->bdst. + * aufs doesn't touch the credential so -+ * security_inode_copy_up{,_xattr}() are unnecrssary. ++ * security_inode_copy_up{,_xattr}() are unnecessary. + */ +static int au_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) +{ @@ -5752,7 +5768,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c + struct inode *dst_inode, *h_dir, *inode, *delegated, *src_inode; + struct super_block *sb; + struct au_branch *br; -+ /* to reuduce stack size */ ++ /* to reduce stack size */ + struct { + struct au_dtime dt; + struct path h_path; @@ -5908,7 +5924,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c + } +out_parent: + dput(dst_parent); -+ kfree(a); ++ au_kfree_rcu(a); +out: + return err; +} @@ -6401,10 +6417,11 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c +} diff -urN /usr/share/empty/fs/aufs/cpup.h linux/fs/aufs/cpup.h --- /usr/share/empty/fs/aufs/cpup.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/cpup.h 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,99 @@ ++++ linux/fs/aufs/cpup.h 2018-08-12 23:43:05.453457863 +0200 +@@ -0,0 +1,100 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -6494,7 +6511,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.h linux/fs/aufs/cpup.h +struct au_dtime { + struct dentry *dt_dentry; + struct path dt_h_path; -+ struct timespec dt_atime, dt_mtime; ++ struct timespec64 dt_atime, dt_mtime; +}; +void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, + struct path *h_path); @@ -6504,10 +6521,11 @@ 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 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,437 @@ ++++ linux/fs/aufs/dbgaufs.c 2018-12-27 13:19:17.708416053 +0100 +@@ -0,0 +1,526 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -6535,7 +6553,7 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c +#endif + +static struct dentry *dbgaufs; -+static const mode_t dbgaufs_mode = S_IRUSR | S_IRGRP | S_IROTH; ++static const mode_t dbgaufs_mode = 0444; + +/* 20 is max digits length of ulong 64 */ +struct dbgaufs_arg { @@ -6549,11 +6567,19 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c +static int dbgaufs_xi_release(struct inode *inode __maybe_unused, + struct file *file) +{ -+ kfree(file->private_data); ++ void *p; ++ ++ p = file->private_data; ++ if (p) { ++ /* this is struct dbgaufs_arg */ ++ AuDebugOn(!au_kfree_sz_test(p)); ++ au_kfree_do_rcu(p); ++ } + return 0; +} + -+static int dbgaufs_xi_open(struct file *xf, struct file *file, int do_fcnt) ++static int dbgaufs_xi_open(struct file *xf, struct file *file, int do_fcnt, ++ int cnt) +{ + int err; + struct kstat st; @@ -6574,8 +6600,8 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c + if (!err) { + if (do_fcnt) + p->n = snprintf -+ (p->a, sizeof(p->a), "%ld, %llux%u %lld\n", -+ (long)file_count(xf), st.blocks, st.blksize, ++ (p->a, sizeof(p->a), "%d, %llux%u %lld\n", ++ cnt, st.blocks, st.blksize, + (long long)st.size); + else + p->n = snprintf(p->a, sizeof(p->a), "%llux%u %lld\n", @@ -6589,7 +6615,6 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c + +out: + return err; -+ +} + +static ssize_t dbgaufs_xi_read(struct file *file, char __user *buf, @@ -6706,7 +6731,7 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c + sbinfo = inode->i_private; + sb = sbinfo->si_sb; + si_noflush_read_lock(sb); -+ err = dbgaufs_xi_open(sbinfo->si_xib, file, /*do_fcnt*/0); ++ err = dbgaufs_xi_open(sbinfo->si_xib, file, /*do_fcnt*/0, /*cnt*/0); + si_read_unlock(sb); + return err; +} @@ -6724,35 +6749,61 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c + +static int dbgaufs_xino_open(struct inode *inode, struct file *file) +{ -+ int err; ++ int err, idx; + long l; ++ aufs_bindex_t bindex; ++ char *p, a[sizeof(DbgaufsXi_PREFIX) + 8]; + struct au_sbinfo *sbinfo; + struct super_block *sb; ++ struct au_xino *xi; + struct file *xf; + struct qstr *name; ++ struct au_branch *br; + + err = -ENOENT; -+ xf = NULL; + name = &file->f_path.dentry->d_name; + if (unlikely(name->len < sizeof(DbgaufsXi_PREFIX) + || memcmp(name->name, DbgaufsXi_PREFIX, + sizeof(DbgaufsXi_PREFIX) - 1))) + goto out; -+ err = kstrtol(name->name + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l); ++ ++ AuDebugOn(name->len >= sizeof(a)); ++ memcpy(a, name->name, name->len); ++ a[name->len] = '\0'; ++ p = strchr(a, '-'); ++ if (p) ++ *p = '\0'; ++ err = kstrtol(a + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l); + if (unlikely(err)) + goto out; ++ bindex = l; ++ idx = 0; ++ if (p) { ++ err = kstrtol(p + 1, 10, &l); ++ if (unlikely(err)) ++ goto out; ++ idx = l; ++ } + ++ err = -ENOENT; + sbinfo = inode->i_private; + sb = sbinfo->si_sb; + si_noflush_read_lock(sb); -+ if (l <= au_sbbot(sb)) { -+ xf = au_sbr(sb, (aufs_bindex_t)l)->br_xino.xi_file; -+ err = dbgaufs_xi_open(xf, file, /*do_fcnt*/1); -+ } else -+ err = -ENOENT; -+ si_read_unlock(sb); ++ if (unlikely(bindex < 0 || bindex > au_sbbot(sb))) ++ goto out_si; ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ if (unlikely(idx >= xi->xi_nfile)) ++ goto out_si; ++ xf = au_xino_file(xi, idx); ++ if (xf) ++ err = dbgaufs_xi_open(xf, file, /*do_fcnt*/1, ++ au_xino_count(br)); + ++out_si: ++ si_read_unlock(sb); +out: ++ AuTraceErr(err); + return err; +} + @@ -6763,11 +6814,25 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c + .read = dbgaufs_xi_read +}; + ++void dbgaufs_xino_del(struct au_branch *br) ++{ ++ struct dentry *dbgaufs; ++ ++ dbgaufs = br->br_dbgaufs; ++ if (!dbgaufs) ++ return; ++ ++ br->br_dbgaufs = NULL; ++ /* debugfs acquires the parent i_mutex */ ++ lockdep_off(); ++ debugfs_remove(dbgaufs); ++ lockdep_on(); ++} ++ +void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) +{ + aufs_bindex_t bbot; + struct au_branch *br; -+ struct au_xino_file *xi; + + if (!au_sbi(sb)->si_dbgaufs) + return; @@ -6775,23 +6840,70 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c + bbot = au_sbbot(sb); + for (; bindex <= bbot; bindex++) { + br = au_sbr(sb, bindex); -+ xi = &br->br_xino; -+ /* debugfs acquires the parent i_mutex */ ++ dbgaufs_xino_del(br); ++ } ++} ++ ++static void dbgaufs_br_do_add(struct super_block *sb, aufs_bindex_t bindex, ++ unsigned int idx, struct dentry *parent, ++ struct au_sbinfo *sbinfo) ++{ ++ struct au_branch *br; ++ struct dentry *d; ++ /* "xi" bindex(5) "-" idx(2) NULL */ ++ char name[sizeof(DbgaufsXi_PREFIX) + 8]; ++ ++ if (!idx) ++ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d", bindex); ++ else ++ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d-%u", ++ bindex, idx); ++ br = au_sbr(sb, bindex); ++ if (br->br_dbgaufs) { ++ struct qstr qstr = QSTR_INIT(name, strlen(name)); ++ ++ if (!au_qstreq(&br->br_dbgaufs->d_name, &qstr)) { ++ /* debugfs acquires the parent i_mutex */ ++ lockdep_off(); ++ d = debugfs_rename(parent, br->br_dbgaufs, parent, ++ name); ++ lockdep_on(); ++ if (unlikely(!d)) ++ pr_warn("failed renaming %pd/%s, ignored.\n", ++ parent, name); ++ } ++ } else { + lockdep_off(); -+ debugfs_remove(xi->xi_dbgaufs); ++ br->br_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent, ++ sbinfo, &dbgaufs_xino_fop); + lockdep_on(); -+ xi->xi_dbgaufs = NULL; ++ if (unlikely(!br->br_dbgaufs)) ++ pr_warn("failed creating %pd/%s, ignored.\n", ++ parent, name); + } +} + -+void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) ++static void dbgaufs_br_add(struct super_block *sb, aufs_bindex_t bindex, ++ struct dentry *parent, struct au_sbinfo *sbinfo) ++{ ++ struct au_branch *br; ++ struct au_xino *xi; ++ unsigned int u; ++ ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ for (u = 0; u < xi->xi_nfile; u++) ++ dbgaufs_br_do_add(sb, bindex, u, parent, sbinfo); ++} ++ ++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex, int topdown) +{ + struct au_sbinfo *sbinfo; + struct dentry *parent; -+ struct au_branch *br; -+ struct au_xino_file *xi; + aufs_bindex_t bbot; -+ char name[sizeof(DbgaufsXi_PREFIX) + 5]; /* "xi" bindex NULL */ ++ ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return; + + sbinfo = au_sbi(sb); + parent = sbinfo->si_dbgaufs; @@ -6799,20 +6911,12 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c + return; + + bbot = au_sbbot(sb); -+ for (; bindex <= bbot; bindex++) { -+ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d", bindex); -+ br = au_sbr(sb, bindex); -+ xi = &br->br_xino; -+ AuDebugOn(xi->xi_dbgaufs); -+ /* debugfs acquires the parent i_mutex */ -+ lockdep_off(); -+ xi->xi_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent, -+ sbinfo, &dbgaufs_xino_fop); -+ lockdep_on(); -+ /* ignore an error */ -+ if (unlikely(!xi->xi_dbgaufs)) -+ AuWarn1("failed %s under debugfs\n", name); -+ } ++ if (topdown) ++ for (; bindex <= bbot; bindex++) ++ dbgaufs_br_add(sb, bindex, parent, sbinfo); ++ else ++ for (; bbot >= bindex; bbot--) ++ dbgaufs_br_add(sb, bbot, parent, sbinfo); +} + +/* ---------------------------------------------------------------------- */ @@ -6827,7 +6931,7 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c + sbinfo = inode->i_private; + sb = sbinfo->si_sb; + si_noflush_read_lock(sb); -+ err = dbgaufs_xi_open(sbinfo->si_xigen, file, /*do_fcnt*/0); ++ err = dbgaufs_xi_open(sbinfo->si_xigen, file, /*do_fcnt*/0, /*cnt*/0); + si_read_unlock(sb); + return err; +} @@ -6877,7 +6981,6 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c + + debugfs_remove_recursive(sbinfo->si_dbgaufs); + sbinfo->si_dbgaufs = NULL; -+ kobject_put(&sbinfo->si_kobj); +} + +int dbgaufs_si_init(struct au_sbinfo *sbinfo) @@ -6902,20 +7005,21 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c + sbinfo->si_dbgaufs = debugfs_create_dir(name, dbgaufs); + if (unlikely(!sbinfo->si_dbgaufs)) + goto out; -+ kobject_get(&sbinfo->si_kobj); -+ -+ sbinfo->si_dbgaufs_xib = debugfs_create_file -+ ("xib", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, -+ &dbgaufs_xib_fop); -+ if (unlikely(!sbinfo->si_dbgaufs_xib)) -+ goto out_dir; + ++ /* regardless plink/noplink option */ + sbinfo->si_dbgaufs_plink = debugfs_create_file + ("plink", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, + &dbgaufs_plink_fop); + if (unlikely(!sbinfo->si_dbgaufs_plink)) + goto out_dir; + ++ /* regardless xino/noxino option */ ++ sbinfo->si_dbgaufs_xib = debugfs_create_file ++ ("xib", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_xib_fop); ++ if (unlikely(!sbinfo->si_dbgaufs_xib)) ++ goto out_dir; ++ + err = dbgaufs_xigen_init(sbinfo); + if (!err) + goto out; /* success */ @@ -6923,6 +7027,8 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c +out_dir: + dbgaufs_si_fin(sbinfo); +out: ++ if (unlikely(err)) ++ pr_err("debugfs/aufs failed\n"); + return err; +} + @@ -6945,10 +7051,11 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c +} diff -urN /usr/share/empty/fs/aufs/dbgaufs.h linux/fs/aufs/dbgaufs.h --- /usr/share/empty/fs/aufs/dbgaufs.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/dbgaufs.h 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,48 @@ ++++ linux/fs/aufs/dbgaufs.h 2018-08-12 23:43:05.453457863 +0200 +@@ -0,0 +1,53 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -6975,18 +7082,22 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.h linux/fs/aufs/dbgaufs.h + +struct super_block; +struct au_sbinfo; ++struct au_branch; + +#ifdef CONFIG_DEBUG_FS +/* dbgaufs.c */ ++void dbgaufs_xino_del(struct au_branch *br); +void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); -+void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); ++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex, int topdown); +void dbgaufs_si_fin(struct au_sbinfo *sbinfo); +int dbgaufs_si_init(struct au_sbinfo *sbinfo); +void dbgaufs_fin(void); +int __init dbgaufs_init(void); +#else ++AuStubVoid(dbgaufs_xino_del, struct au_branch *br) +AuStubVoid(dbgaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) -+AuStubVoid(dbgaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(dbgaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex, ++ int topdown) +AuStubVoid(dbgaufs_si_fin, struct au_sbinfo *sbinfo) +AuStubInt0(dbgaufs_si_init, struct au_sbinfo *sbinfo) +AuStubVoid(dbgaufs_fin, void) @@ -6997,10 +7108,11 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.h linux/fs/aufs/dbgaufs.h +#endif /* __DBGAUFS_H__ */ diff -urN /usr/share/empty/fs/aufs/dcsub.c linux/fs/aufs/dcsub.c --- /usr/share/empty/fs/aufs/dcsub.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/dcsub.c 2018-04-06 07:48:44.204604724 +0200 ++++ linux/fs/aufs/dcsub.c 2018-12-27 13:19:17.708416053 +0100 @@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -7053,7 +7165,7 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.c linux/fs/aufs/dcsub.c + return 0; /* success */ + +out_dpages: -+ kfree(dpages->dpages); ++ au_kfree_try_rcu(dpages->dpages); +out: + return err; +} @@ -7066,7 +7178,7 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.c linux/fs/aufs/dcsub.c + p = dpages->dpages; + for (i = 0; i < dpages->ndpage; i++) + au_dpage_free(p++); -+ kfree(dpages->dpages); ++ au_kfree_try_rcu(dpages->dpages); +} + +static int au_dpages_append(struct au_dcsub_pages *dpages, @@ -7117,8 +7229,7 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.c linux/fs/aufs/dcsub.c +}; + +extern void d_walk(struct dentry *parent, void *data, -+ enum d_walk_ret (*enter)(void *, struct dentry *), -+ void (*finish)(void *)); ++ enum d_walk_ret (*enter)(void *, struct dentry *)); + +struct ac_dpages_arg { + int err; @@ -7158,7 +7269,7 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.c linux/fs/aufs/dcsub.c + .arg = arg + }; + -+ d_walk(root, &args, au_call_dpages_append, NULL); ++ d_walk(root, &args, au_call_dpages_append); + + return args.err; +} @@ -7226,10 +7337,11 @@ 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 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,136 @@ ++++ linux/fs/aufs/dcsub.h 2018-08-12 23:43:05.453457863 +0200 +@@ -0,0 +1,137 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -7366,10 +7478,11 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.h linux/fs/aufs/dcsub.h +#endif /* __AUFS_DCSUB_H__ */ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c --- /usr/share/empty/fs/aufs/debug.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/debug.c 2018-04-06 07:48:44.204604724 +0200 ++++ linux/fs/aufs/debug.c 2018-12-27 13:19:17.708416053 +0100 @@ -0,0 +1,440 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -7423,7 +7536,7 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c + +atomic_t aufs_debug = ATOMIC_INIT(0); +MODULE_PARM_DESC(debug, "debug print"); -+module_param_named(debug, aufs_debug, atomic_t, S_IRUGO | S_IWUSR | S_IWGRP); ++module_param_named(debug, aufs_debug, atomic_t, 0664); + +DEFINE_MUTEX(au_dbg_mtx); /* just to serialize the dbg msgs */ +char *au_plevel = KERN_DEBUG; @@ -7500,7 +7613,7 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c + inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??", + atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode, + i_size_read(inode), (unsigned long long)inode->i_blocks, -+ hn, (long long)timespec_to_ns(&inode->i_ctime) & 0x0ffff, ++ hn, (long long)timespec64_to_ns(&inode->i_ctime) & 0x0ffff, + inode->i_mapping ? inode->i_mapping->nrpages : 0, + inode->i_state, inode->i_flags, inode_peek_iversion(inode), + inode->i_generation, @@ -7669,13 +7782,14 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c + if (!sb || IS_ERR(sb)) + goto out; + -+ dpri("s%d: {perm 0x%x, id %d, cnt %lld, wbr %p}, " ++ dpri("s%d: {perm 0x%x, id %d, wbr %p}, " + "%s, dev 0x%02x%02x, flags 0x%lx, cnt %d, active %d, " + "xino %d\n", -+ bindex, br->br_perm, br->br_id, au_br_count(br), -+ br->br_wbr, au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev), ++ bindex, br->br_perm, br->br_id, br->br_wbr, ++ au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev), + sb->s_flags, sb->s_count, -+ atomic_read(&sb->s_active), !!br->br_xino.xi_file); ++ atomic_read(&sb->s_active), ++ !!au_xino_file(br->br_xino, /*idx*/-1)); + return 0; + +out: @@ -7688,7 +7802,7 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c + struct au_sbinfo *sbinfo; + aufs_bindex_t bindex; + int err; -+ /* to reuduce stack size */ ++ /* to reduce stack size */ + struct { + struct vfsmount mnt; + struct au_branch fake; @@ -7703,10 +7817,8 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c + + a->mnt.mnt_sb = sb; + a->fake.br_path.mnt = &a->mnt; -+ au_br_count_init(&a->fake); + err = do_pri_br(-1, &a->fake); -+ au_br_count_fin(&a->fake); -+ kfree(a); ++ au_kfree_rcu(a); + dpri("dev 0x%x\n", sb->s_dev); + if (err || !au_test_aufs(sb)) + return; @@ -7810,10 +7922,11 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c +} diff -urN /usr/share/empty/fs/aufs/debug.h linux/fs/aufs/debug.h --- /usr/share/empty/fs/aufs/debug.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/debug.h 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,225 @@ ++++ linux/fs/aufs/debug.h 2018-08-12 23:43:05.453457863 +0200 +@@ -0,0 +1,226 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -8039,10 +8152,11 @@ 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 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,1152 @@ ++++ linux/fs/aufs/dentry.c 2018-12-27 13:19:17.708416053 +0100 +@@ -0,0 +1,1153 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -8276,7 +8390,7 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c + +out_parent: + dput(parent); -+ kfree(args.whname.name); ++ au_kfree_try_rcu(args.whname.name); + if (dirren) + au_dr_lkup_fin(&args); +out: @@ -8650,7 +8764,7 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c + if (d_really_is_positive(dentry)) + inode = d_inode(dentry); + if (!orig_h.inode) { -+ AuDbg("nagative originally\n"); ++ AuDbg("negative originally\n"); + if (inode) { + au_hide(dentry); + goto out; @@ -9195,10 +9309,11 @@ 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 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,266 @@ ++++ linux/fs/aufs/dentry.h 2018-12-27 13:19:17.708416053 +0100 +@@ -0,0 +1,268 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -9239,6 +9354,7 @@ diff -urN /usr/share/empty/fs/aufs/dentry.h linux/fs/aufs/dentry.h + aufs_bindex_t di_btop, di_bbot, di_bwh, di_bdiropq; + unsigned char di_tmpfile; /* to allow the different name */ + struct au_hdentry *di_hdentry; ++ struct rcu_head rcu; +} ____cacheline_aligned_in_smp; + +/* ---------------------------------------------------------------------- */ @@ -9465,10 +9581,11 @@ diff -urN /usr/share/empty/fs/aufs/dentry.h linux/fs/aufs/dentry.h +#endif /* __AUFS_DENTRY_H__ */ diff -urN /usr/share/empty/fs/aufs/dinfo.c linux/fs/aufs/dinfo.c --- /usr/share/empty/fs/aufs/dinfo.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/dinfo.c 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,553 @@ ++++ linux/fs/aufs/dinfo.c 2018-12-27 13:19:17.708416053 +0100 +@@ -0,0 +1,554 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -9542,7 +9659,7 @@ diff -urN /usr/share/empty/fs/aufs/dinfo.c linux/fs/aufs/dinfo.c + while (bindex++ <= bbot) + au_hdput(p++); + } -+ kfree(dinfo->di_hdentry); ++ au_kfree_try_rcu(dinfo->di_hdentry); + au_cache_free_dinfo(dinfo); +} + @@ -10022,10 +10139,11 @@ diff -urN /usr/share/empty/fs/aufs/dinfo.c linux/fs/aufs/dinfo.c +} diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c --- /usr/share/empty/fs/aufs/dir.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/dir.c 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,759 @@ ++++ linux/fs/aufs/dir.c 2018-12-27 13:19:17.708416053 +0100 +@@ -0,0 +1,762 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -10169,7 +10287,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c + au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); + h_dir = au_h_iptr(dir, btop); + if (h_dir->i_nlink -+ && timespec_compare(&h_dir->i_mtime, &dt.dt_mtime) < 0) { ++ && timespec64_compare(&h_dir->i_mtime, &dt.dt_mtime) < 0) { + dt.dt_h_path = h_path; + au_dtime_revert(&dt); + } @@ -10182,7 +10300,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c +out: + dput(a->dentry); + au_nwt_done(&au_sbi(sb)->si_nowait); -+ kfree(arg); ++ au_kfree_try_rcu(arg); +} + +void au_dir_ts(struct inode *dir, aufs_bindex_t bindex) @@ -10218,7 +10336,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c + if (unlikely(wkq_err)) { + pr_err("wkq %d\n", wkq_err); + dput(dentry); -+ kfree(arg); ++ au_kfree_try_rcu(arg); + } + +out: @@ -10337,7 +10455,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c + }; + err = au_do_open(file, &args); + if (unlikely(err)) -+ kfree(fidir); ++ au_kfree_rcu(fidir); + } + si_read_unlock(sb); + return err; @@ -10373,7 +10491,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c + if (hf->hf_file) + au_hfput(hf, /*execed*/0); + } -+ kfree(fidir); ++ au_kfree_rcu(fidir); + finfo->fi_hdir = NULL; + } + au_finfo_fin(file); @@ -10502,7 +10620,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c + struct inode *inode, *h_inode; + struct super_block *sb; + -+ AuDbg("%pD, ctx{%pf, %llu}\n", file, ctx->actor, ctx->pos); ++ AuDbg("%pD, ctx{%ps, %llu}\n", file, ctx->actor, ctx->pos); + + dentry = file->f_path.dentry; + inode = d_inode(dentry); @@ -10613,6 +10731,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c +{ + int err; + struct file *h_file; ++ struct au_branch *br; + + h_file = au_h_open(dentry, arg->bindex, + O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_LARGEFILE, @@ -10637,7 +10756,8 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c + +out_put: + fput(h_file); -+ au_sbr_put(dentry->d_sb, arg->bindex); ++ br = au_sbr(dentry->d_sb, arg->bindex); ++ au_lcnt_dec(&br->br_nfiles); +out: + return err; +} @@ -10785,10 +10905,11 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c +}; diff -urN /usr/share/empty/fs/aufs/dir.h linux/fs/aufs/dir.h --- /usr/share/empty/fs/aufs/dir.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/dir.h 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,131 @@ ++++ linux/fs/aufs/dir.h 2018-12-27 13:19:17.708416053 +0100 +@@ -0,0 +1,134 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -10832,6 +10953,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.h linux/fs/aufs/dir.h +struct au_vdir_dehstr { + struct hlist_node hash; + struct au_vdir_destr *str; ++ struct rcu_head rcu; +} ____cacheline_aligned_in_smp; + +struct au_vdir_de { @@ -10869,7 +10991,8 @@ diff -urN /usr/share/empty/fs/aufs/dir.h linux/fs/aufs/dir.h + + u64 vd_version; + unsigned int vd_deblk_sz; -+ unsigned long vd_jiffy; ++ unsigned long vd_jiffy; ++ struct rcu_head rcu; +} ____cacheline_aligned_in_smp; + +/* ---------------------------------------------------------------------- */ @@ -10920,10 +11043,11 @@ 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 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,1315 @@ ++++ linux/fs/aufs/dirren.c 2018-12-27 13:19:17.708416053 +0100 +@@ -0,0 +1,1316 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2017 Junjiro R. Okajima ++ * Copyright (C) 2017-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -10940,7 +11064,7 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c + */ + +/* -+ * special handling in renaming a directoy ++ * special handling in renaming a directory + * in order to support looking-up the before-renamed name on the lower readonly + * branches + */ @@ -11041,7 +11165,7 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c + hbl = dr->dr_h_ino + i; + /* no spinlock since sbinfo must be write-locked */ + hlist_bl_for_each_entry_safe(ent, pos, tmp, hbl, dr_hnode) -+ kfree(ent); ++ au_kfree_rcu(ent); + INIT_HLIST_BL_HEAD(hbl); + } +} @@ -11483,7 +11607,7 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c + *ret = *drinfo; + ssz = vfsub_read_k(file, (void *)ret->oldname, len, &pos); + if (unlikely(ssz != len)) { -+ kfree(ret); ++ au_kfree_rcu(ret); + ret = ERR_PTR(-EIO); + AuIOErr("ssz %zd, %u, %pD2\n", ssz, len, file); + goto out; @@ -11521,7 +11645,7 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c + unsigned char no_sio, + allocated, /* current size of *fdata */ + infonamelen, /* room size for p */ -+ whnamelen, /* length of the genarated name */ ++ whnamelen, /* length of the generated name */ + renameback; /* renamed back */ +}; + @@ -11679,7 +11803,7 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c + +static void au_drinfo_store_work_fin(struct au_drinfo_store *w) +{ -+ kfree(w->fdata); ++ au_kfree_rcu(w->fdata); +} + +static void au_drinfo_store_rev(struct au_drinfo_rev *rev, @@ -11716,7 +11840,7 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c + elm->info_last->oldname, + elm->info_last->oldnamelen); + err = au_drinfo_store_sio(w, /*elm*/NULL); -+ kfree(elm->info_last); ++ au_kfree_rcu(elm->info_last); + } + if (unlikely(err)) + AuIOErr("%d, %s\n", err, w->whname); @@ -11792,7 +11916,7 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c + if (unlikely(err)) { + /* revert all drinfo */ + au_drinfo_store_rev(rev, &work); -+ kfree(rev); ++ au_kfree_try_rcu(rev); + *p = NULL; + } + au_hn_inode_unlock(hdir); @@ -11848,7 +11972,7 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c + /* revert */ + if (!already) + au_dr_hino_del(dr, ent); -+ kfree(ent); ++ au_kfree_rcu(ent); + +out: + AuTraceErr(err); @@ -11865,9 +11989,9 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c + elm = rev->elm; + for (nelm = rev->nelm; nelm > 0; nelm--, elm++) { + dput(elm->info_dentry); -+ kfree(elm->info_last); ++ au_kfree_rcu(elm->info_last); + } -+ kfree(rev); ++ au_kfree_try_rcu(rev); +} + +void au_dr_rename_rev(struct dentry *src, aufs_bindex_t btgt, void *_rev) @@ -11899,10 +12023,10 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c + ent = au_dr_hino_find(dr, h_inode->i_ino); + BUG_ON(!ent); + au_dr_hino_del(dr, ent); -+ kfree(ent); ++ au_kfree_rcu(ent); + +out: -+ kfree(rev); ++ au_kfree_try_rcu(rev); + if (unlikely(err)) + pr_err("failed to remove dirren info\n"); +} @@ -12027,7 +12151,7 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c + oldname.name = drinfo->oldname; + if (au_qstreq(w->qname, &oldname)) { + /* the name is renamed back */ -+ kfree(drinfo); ++ au_kfree_rcu(drinfo); + drinfo = NULL; + + infopath.dentry = info_dentry; @@ -12042,7 +12166,7 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c + if (unlikely(e == -EWOULDBLOCK)) + iput(delegated); + } -+ kfree(w->drinfo[bindex]); ++ au_kfree_rcu(w->drinfo[bindex]); + w->drinfo[bindex] = drinfo; + dput(info_dentry); + @@ -12058,8 +12182,8 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c + struct au_drinfo **p = drinfo; + + while (n-- > 0) -+ kfree(*drinfo++); -+ kfree(p); ++ au_kfree_rcu(*drinfo++); ++ au_kfree_try_rcu(p); +} + +int au_dr_lkup(struct au_do_lookup_args *lkup, struct dentry *dentry, @@ -12112,7 +12236,7 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c + ent = au_dr_hino_find(&br->br_dirren, h_dir->i_ino); + AuDebugOn(!ent); + au_dr_hino_del(&br->br_dirren, ent); -+ kfree(ent); ++ au_kfree_rcu(ent); + } + goto out; /* success */ + @@ -12143,7 +12267,7 @@ diff -urN /usr/share/empty/fs/aufs/dirren.c linux/fs/aufs/dirren.c + if (!drinfo) + goto out; + -+ kfree(lkup->whname.name); ++ au_kfree_try_rcu(lkup->whname.name); + lkup->whname.name = NULL; + lkup->dirren.dr_name.len = drinfo->oldnamelen; + lkup->dirren.dr_name.name = drinfo->oldname; @@ -12239,10 +12363,11 @@ 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 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,139 @@ ++++ linux/fs/aufs/dirren.h 2018-08-12 23:43:05.453457863 +0200 +@@ -0,0 +1,140 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2017 Junjiro R. Okajima ++ * Copyright (C) 2017-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -12382,10 +12507,11 @@ 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 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,369 @@ ++++ linux/fs/aufs/dynop.c 2018-12-27 13:19:17.708416053 +0100 +@@ -0,0 +1,370 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2010-2017 Junjiro R. Okajima ++ * Copyright (C) 2010-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -12499,7 +12625,7 @@ diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c + + key = container_of(rcu, struct au_dykey, dk_rcu); + DyPrSym(key); -+ kfree(key); ++ au_kfree_rcu(key); +} + +static void dy_free(struct kref *kref) @@ -12627,7 +12753,7 @@ diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c + p->set(key, op->dy_hop, au_br_sb(br)); + old = dy_gadd(hbl, key); + if (old) { -+ kfree(key); ++ au_kfree_rcu(key); + key = old; + } + @@ -12642,7 +12768,7 @@ diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c + +/* ---------------------------------------------------------------------- */ +/* -+ * Aufs prohibits O_DIRECT by defaut even if the branch supports it. ++ * Aufs prohibits O_DIRECT by default even if the branch supports it. + * This behaviour is necessary to return an error from open(O_DIRECT) instead + * of the succeeding I/O. The dio mount option enables O_DIRECT and makes + * open(O_DIRECT) always succeed, but the succeeding I/O may return an error. @@ -12755,10 +12881,11 @@ diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c +} diff -urN /usr/share/empty/fs/aufs/dynop.h linux/fs/aufs/dynop.h --- /usr/share/empty/fs/aufs/dynop.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/dynop.h 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,74 @@ ++++ linux/fs/aufs/dynop.h 2018-08-12 23:43:05.456791299 +0200 +@@ -0,0 +1,75 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2010-2017 Junjiro R. Okajima ++ * Copyright (C) 2010-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -12833,10 +12960,11 @@ 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 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,836 @@ ++++ linux/fs/aufs/export.c 2018-10-23 12:33:35.596042364 +0200 +@@ -0,0 +1,838 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -13018,7 +13146,7 @@ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c + return err; +} + -+int au_xigen_set(struct super_block *sb, struct file *base) ++int au_xigen_set(struct super_block *sb, struct path *path) +{ + int err; + struct au_sbinfo *sbinfo; @@ -13027,7 +13155,7 @@ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); -+ file = au_xino_create2(base, sbinfo->si_xigen); ++ file = au_xino_create2(sb, path, sbinfo->si_xigen); + err = PTR_ERR(file); + if (IS_ERR(file)) + goto out; @@ -13037,6 +13165,7 @@ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c + sbinfo->si_xigen = file; + +out: ++ AuTraceErr(err); + return err; +} + @@ -13457,7 +13586,7 @@ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c + + /* is the parent dir cached? */ + br = au_sbr(sb, nsi_lock.bindex); -+ au_br_get(br); ++ au_lcnt_inc(&br->br_nfiles); + dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock); + if (IS_ERR(dentry)) + goto out_unlock; @@ -13481,7 +13610,7 @@ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c + dentry = ERR_PTR(-ESTALE); +out_unlock: + if (br) -+ au_br_put(br); ++ au_lcnt_dec(&br->br_nfiles); + si_read_unlock(sb); +out: + AuTraceErrPtr(dentry); @@ -13673,10 +13802,11 @@ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c +} diff -urN /usr/share/empty/fs/aufs/fhsm.c linux/fs/aufs/fhsm.c --- /usr/share/empty/fs/aufs/fhsm.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/fhsm.c 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,425 @@ ++++ linux/fs/aufs/fhsm.c 2018-10-23 12:33:35.596042364 +0200 +@@ -0,0 +1,427 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2011-2017 Junjiro R. Okajima ++ * Copyright (C) 2011-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -13859,7 +13989,8 @@ diff -urN /usr/share/empty/fs/aufs/fhsm.c linux/fs/aufs/fhsm.c + if (atomic_read(&fhsm->fhsm_readable)) + mask = EPOLLIN /* | EPOLLRDNORM */; + -+ AuDbg("mask 0x%x\n", mask); ++ if (!mask) ++ AuDbg("mask 0x%x\n", mask); + return mask; +} + @@ -14030,7 +14161,7 @@ diff -urN /usr/share/empty/fs/aufs/fhsm.c linux/fs/aufs/fhsm.c + if (unlikely(fd < 0)) + goto out_pid; + -+ /* succeed reglardless 'fhsm' status */ ++ /* succeed regardless 'fhsm' status */ + kobject_get(&sbinfo->si_kobj); + si_noflush_read_lock(sb); + if (au_ftest_si(sbinfo, FHSM)) @@ -14102,10 +14233,11 @@ 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 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,856 @@ ++++ linux/fs/aufs/file.c 2018-10-23 12:33:35.596042364 +0200 +@@ -0,0 +1,863 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -14188,7 +14320,7 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c + } + } + flags &= ~O_CREAT; -+ au_br_get(br); ++ au_lcnt_inc(&br->br_nfiles); + h_path.dentry = h_dentry; + h_path.mnt = au_br_mnt(br); + h_file = vfsub_dentry_open(&h_path, flags); @@ -14207,7 +14339,7 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c + goto out; /* success */ + +out_br: -+ au_br_put(br); ++ au_lcnt_dec(&br->br_nfiles); +out: + return h_file; +} @@ -14355,7 +14487,8 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c + err = args->open(file, vfsub_file_flags(file), NULL); + else { + lockdep_off(); -+ err = args->open(file, vfsub_file_flags(file), NULL); ++ err = args->open(file, vfsub_file_flags(file), ++ args->h_file); + lockdep_on(); + } + } @@ -14389,10 +14522,12 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c + int err; + aufs_bindex_t btop; + struct dentry *dentry; ++ struct au_branch *br; + struct file *h_file, *h_file_tmp; + + dentry = file->f_path.dentry; + btop = au_dbtop(dentry); ++ br = au_sbr(dentry->d_sb, btop); + h_file_tmp = NULL; + if (au_fbtop(file) == btop) { + h_file = au_hf_top(file); @@ -14400,6 +14535,7 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c + return 0; /* success */ + h_file_tmp = h_file; + get_file(h_file_tmp); ++ au_lcnt_inc(&br->br_nfiles); + au_set_h_fptr(file, btop, NULL); + } + AuDebugOn(au_fi(file)->fi_hdir); @@ -14420,7 +14556,7 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) { + if (h_file_tmp) { -+ au_sbr_get(dentry->d_sb, btop); ++ /* revert */ + au_set_h_fptr(file, btop, h_file_tmp); + h_file_tmp = NULL; + } @@ -14435,8 +14571,10 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c + /* file->f_ra = h_file->f_ra; */ + +out: -+ if (h_file_tmp) ++ if (h_file_tmp) { + fput(h_file_tmp); ++ au_lcnt_dec(&br->br_nfiles); ++ } + return err; +} + @@ -14962,10 +15100,11 @@ 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 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,340 @@ ++++ linux/fs/aufs/file.h 2018-12-27 13:19:17.708416053 +0100 +@@ -0,0 +1,342 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -15031,6 +15170,7 @@ diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h + + struct hlist_bl_node fi_hlist; + struct file *fi_file; /* very ugly */ ++ struct rcu_head rcu; +} ____cacheline_aligned_in_smp; + +/* ---------------------------------------------------------------------- */ @@ -15058,7 +15198,7 @@ diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h + +/* poll.c */ +#ifdef CONFIG_AUFS_POLL -+__poll_t aufs_poll(struct file *file, poll_table *wait); ++__poll_t aufs_poll(struct file *file, struct poll_table_struct *pt); +#endif + +#ifdef CONFIG_AUFS_BR_HFSPLUS @@ -15306,10 +15446,11 @@ diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h +#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 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,148 @@ ++++ linux/fs/aufs/finfo.c 2018-10-23 12:33:35.596042364 +0200 +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -15337,7 +15478,7 @@ diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c + allow_write_access(hf->hf_file); + fput(hf->hf_file); + hf->hf_file = NULL; -+ au_br_put(hf->hf_br); ++ au_lcnt_dec(&hf->hf_br->br_nfiles); + hf->hf_br = NULL; +} + @@ -15416,7 +15557,7 @@ diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c +{ + struct au_finfo *finfo; + -+ au_nfiles_dec(file->f_path.dentry->d_sb); ++ au_lcnt_dec(&au_sbi(file->f_path.dentry->d_sb)->si_nfiles); + + finfo = au_fi(file); + AuDebugOn(finfo->fi_hdir); @@ -15444,7 +15585,7 @@ diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c + goto out; + + err = 0; -+ au_nfiles_inc(dentry->d_sb); ++ au_lcnt_inc(&au_sbi(dentry->d_sb)->si_nfiles); + au_rw_write_lock(&finfo->fi_rwsem); + finfo->fi_btop = -1; + finfo->fi_hdir = fidir; @@ -15458,10 +15599,11 @@ 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 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,817 @@ ++++ linux/fs/aufs/f_op.c 2018-10-23 12:33:35.596042364 +0200 +@@ -0,0 +1,819 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -15510,29 +15652,30 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + if (unlikely(err)) + goto out; + h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ goto out; ++ } + } else { + h_dentry = h_file->f_path.dentry; + err = vfsub_test_mntns(file->f_path.mnt, h_dentry->d_sb); + if (unlikely(err)) + goto out; -+ get_file(h_file); ++ /* br ref is already inc-ed */ + } -+ if (IS_ERR(h_file)) -+ err = PTR_ERR(h_file); -+ else { -+ if ((flags & __O_TMPFILE) -+ && !(flags & O_EXCL)) { -+ h_inode = file_inode(h_file); -+ spin_lock(&h_inode->i_lock); -+ h_inode->i_state |= I_LINKABLE; -+ spin_unlock(&h_inode->i_lock); -+ } -+ au_set_fbtop(file, bindex); -+ au_set_h_fptr(file, bindex, h_file); -+ au_update_figen(file); -+ /* todo: necessary? */ -+ /* file->f_ra = h_file->f_ra; */ ++ ++ if ((flags & __O_TMPFILE) ++ && !(flags & O_EXCL)) { ++ h_inode = file_inode(h_file); ++ spin_lock(&h_inode->i_lock); ++ h_inode->i_state |= I_LINKABLE; ++ spin_unlock(&h_inode->i_lock); + } ++ au_set_fbtop(file, bindex); ++ au_set_h_fptr(file, bindex, h_file); ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ + +out: + return err; @@ -15596,7 +15739,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c +/* + * read and write functions acquire [fdi]_rwsem once, but release before + * mmap_sem. This is because to stop a race condition between mmap(2). -+ * Releasing these aufs-rwsem should be safe, no branch-mamagement (by keeping ++ * Releasing these aufs-rwsem should be safe, no branch-management (by keeping + * si_rwsem), no harmful copy-up should happen. Actually copy-up may happen in + * read functions after [fdi]_rwsem are released, but it should be harmless. + */ @@ -15893,7 +16036,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + goto out; + + err = vfsub_splice_to(h_file, ppos, pipe, len, flags); -+ /* todo: necessasry? */ ++ /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + au_read_post(inode, h_file); + @@ -15983,7 +16126,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + au_mtx_and_read_lock(a_dst.inode); + /* + * in order to match the order in di_write_lock2_{child,parent}(), -+ * use f_path.dentry for this comparision. ++ * use f_path.dentry for this comparison. + */ + if (src->f_path.dentry < dst->f_path.dentry) { + a_src.h_file = au_read_pre(src, /*keep_fi*/1, AuLsc_FI_1); @@ -16049,9 +16192,9 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + * (Note that [fdi]i_rwsem are released before mmap_sem). + * - in mmap case + * mmap(2) -- mmap_sem -- aufs_mmap() -- si_rwsem for read -- [fdi]i_rwsem -+ * This AB-BA order is definitly bad, but is not a problem since "si_rwsem for -+ * read" allows muliple processes to acquire it and [fdi]i_rwsem are not held in -+ * file I/O. Aufs needs to stop lockdep in aufs_mmap() though. ++ * This AB-BA order is definitely bad, but is not a problem since "si_rwsem for ++ * read" allows multiple processes to acquire it and [fdi]i_rwsem are not held ++ * in file I/O. Aufs needs to stop lockdep in aufs_mmap() though. + * It means that when aufs acquires si_rwsem for write, the process should never + * acquire mmap_sem. + * @@ -16279,10 +16422,11 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c +}; diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h --- /usr/share/empty/fs/aufs/fstype.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/fstype.h 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,400 @@ ++++ linux/fs/aufs/fstype.h 2018-08-12 23:43:05.456791299 +0200 +@@ -0,0 +1,401 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -16683,10 +16827,11 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h +#endif /* __AUFS_FSTYPE_H__ */ diff -urN /usr/share/empty/fs/aufs/hbl.h linux/fs/aufs/hbl.h --- /usr/share/empty/fs/aufs/hbl.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/hbl.h 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,64 @@ ++++ linux/fs/aufs/hbl.h 2018-08-12 23:43:05.456791299 +0200 +@@ -0,0 +1,65 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2017 Junjiro R. Okajima ++ * Copyright (C) 2017-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -16751,10 +16896,11 @@ diff -urN /usr/share/empty/fs/aufs/hbl.h linux/fs/aufs/hbl.h +#endif /* __AUFS_HBL_H__ */ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c --- /usr/share/empty/fs/aufs/hfsnotify.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/hfsnotify.c 2018-04-06 07:48:44.204604724 +0200 ++++ linux/fs/aufs/hfsnotify.c 2018-12-27 13:19:17.708416053 +0100 @@ -0,0 +1,289 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -16816,8 +16962,7 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c + * h_inode, so specify 1 to allow dups. + */ + lockdep_off(); -+ err = fsnotify_add_mark(mark, hinode->hi_inode, /*mnt*/NULL, -+ /*allow_dups*/1); ++ err = fsnotify_add_inode_mark(mark, hinode->hi_inode, /*allow_dups*/1); + lockdep_on(); + + return err; @@ -16911,13 +17056,11 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c + struct au_br_hfsnotify *hfsn = group->private; + + /* AuDbg("here\n"); */ -+ kfree(hfsn); ++ au_kfree_try_rcu(hfsn); +} + +static int au_hfsn_handle_event(struct fsnotify_group *group, + struct inode *inode, -+ struct fsnotify_mark *inode_mark, -+ struct fsnotify_mark *vfsmount_mark, + u32 mask, const void *data, int data_type, + const unsigned char *file_name, u32 cookie, + struct fsnotify_iter_info *iter_info) @@ -16926,6 +17069,7 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c + struct au_hnotify *hnotify; + struct inode *h_dir, *h_inode; + struct qstr h_child_qstr = QSTR_INIT(file_name, strlen(file_name)); ++ struct fsnotify_mark *inode_mark; + + AuDebugOn(data_type != FSNOTIFY_EVENT_INODE); + @@ -16949,6 +17093,7 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c + au_debug_off(); +#endif + ++ inode_mark = fsnotify_iter_inode_mark(iter_info); + AuDebugOn(!inode_mark); + hnotify = container_of(inode_mark, struct au_hnotify, hn_mark); + err = au_hnotify(h_dir, hnotify, mask, &h_child_qstr, h_inode); @@ -17007,7 +17152,7 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c + goto out; /* success */ + +out_hfsn: -+ kfree(hfsn); ++ au_kfree_try_rcu(hfsn); +out: + return err; +} @@ -17044,10 +17189,11 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c +}; diff -urN /usr/share/empty/fs/aufs/hfsplus.c linux/fs/aufs/hfsplus.c --- /usr/share/empty/fs/aufs/hfsplus.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/hfsplus.c 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,56 @@ ++++ linux/fs/aufs/hfsplus.c 2018-10-23 12:33:35.596042364 +0200 +@@ -0,0 +1,60 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2010-2017 Junjiro R. Okajima ++ * Copyright (C) 2010-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -17064,11 +17210,11 @@ diff -urN /usr/share/empty/fs/aufs/hfsplus.c linux/fs/aufs/hfsplus.c + */ + +/* -+ * special support for filesystems which aqucires an inode mutex ++ * special support for filesystems which acquires an inode mutex + * at final closing a file, eg, hfsplus. + * + * This trick is very simple and stupid, just to open the file before really -+ * neceeary open to tell hfsplus that this is not the final closing. ++ * necessary open to tell hfsplus that this is not the final closing. + * The caller should call au_h_open_pre() after acquiring the inode mutex, + * and au_h_open_post() after releasing it. + */ @@ -17097,17 +17243,21 @@ diff -urN /usr/share/empty/fs/aufs/hfsplus.c linux/fs/aufs/hfsplus.c +void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, + struct file *h_file) +{ ++ struct au_branch *br; ++ + if (h_file) { + fput(h_file); -+ au_sbr_put(dentry->d_sb, bindex); ++ br = au_sbr(dentry->d_sb, bindex); ++ au_lcnt_dec(&br->br_nfiles); + } +} 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 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,719 @@ ++++ linux/fs/aufs/hnotify.c 2018-12-27 13:19:17.708416053 +0100 +@@ -0,0 +1,720 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -17146,9 +17296,9 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c + au_cache_free_hnotify(hn); + /* + * The upper dir was removed by udba, but the same named -+ * dir left. In this case, aufs assignes a new inode ++ * dir left. In this case, aufs assigns a new inode + * number and set the monitor again. -+ * For the lower dir, the old monitnor is still left. ++ * For the lower dir, the old monitor is still left. + */ + if (err == -EEXIST) + err = 0; @@ -17648,7 +17798,7 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c + iput(a->dir); + si_write_unlock(sb); + au_nwt_done(&sbinfo->si_nowait); -+ kfree(a); ++ au_kfree_rcu(a); +} + +/* ---------------------------------------------------------------------- */ @@ -17754,7 +17904,7 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c + iput(args->h_child_inode); + iput(args->h_dir); + iput(args->dir); -+ kfree(args); ++ au_kfree_rcu(args); + } + +out: @@ -17827,10 +17977,11 @@ 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 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,285 @@ ++++ linux/fs/aufs/iinfo.c 2018-12-27 13:19:17.711749485 +0100 +@@ -0,0 +1,286 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -18034,7 +18185,7 @@ diff -urN /usr/share/empty/fs/aufs/iinfo.c linux/fs/aufs/iinfo.c + nbr = 1; + hi = kmalloc_array(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS); + if (hi) { -+ au_ninodes_inc(sb); ++ au_lcnt_inc(&au_sbi(sb)->si_ninodes); + + iinfo->ii_hinode = hi; + for (i = 0; i < nbr; i++, hi++) @@ -18082,7 +18233,7 @@ diff -urN /usr/share/empty/fs/aufs/iinfo.c linux/fs/aufs/iinfo.c + AuDebugOn(au_is_bad_inode(inode)); + + sb = inode->i_sb; -+ au_ninodes_dec(sb); ++ au_lcnt_dec(&au_sbi(sb)->si_ninodes); + if (si_pid_test(sb)) + au_xino_delete_inode(inode, unlinked); + else { @@ -18111,15 +18262,16 @@ diff -urN /usr/share/empty/fs/aufs/iinfo.c linux/fs/aufs/iinfo.c + hi++; + } + } -+ kfree(iinfo->ii_hinode); ++ au_kfree_rcu(iinfo->ii_hinode); + AuRwDestroy(&iinfo->ii_rwsem); +} diff -urN /usr/share/empty/fs/aufs/inode.c linux/fs/aufs/inode.c --- /usr/share/empty/fs/aufs/inode.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/inode.c 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,527 @@ ++++ linux/fs/aufs/inode.c 2018-08-12 23:43:05.460124736 +0200 +@@ -0,0 +1,528 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -18647,10 +18799,11 @@ 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 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,695 @@ ++++ linux/fs/aufs/inode.h 2018-12-27 13:19:17.711749485 +0100 +@@ -0,0 +1,698 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -18687,6 +18840,7 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h + struct fsnotify_mark hn_mark; +#endif + struct inode *hn_aufs_inode; /* no get/put */ ++ struct rcu_head rcu; +#endif +} ____cacheline_aligned_in_smp; + @@ -18727,9 +18881,10 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h +}; + +struct au_icntnr { -+ struct au_iinfo iinfo; -+ struct inode vfs_inode; -+ struct hlist_bl_node plink; ++ struct au_iinfo iinfo; ++ struct inode vfs_inode; ++ struct hlist_bl_node plink; ++ struct rcu_head rcu; +} ____cacheline_aligned_in_smp; + +/* au_pin flags */ @@ -19346,10 +19501,11 @@ 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 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,219 @@ ++++ linux/fs/aufs/ioctl.c 2018-10-23 12:33:35.599375796 +0200 +@@ -0,0 +1,220 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -19455,7 +19611,7 @@ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c + if (IS_ERR(h_file)) + goto out_fd; + -+ au_br_put(br); /* cf. au_h_open() */ ++ au_lcnt_dec(&br->br_nfiles); /* cf. au_h_open() */ + fd_install(fd, h_file); + err = fd; + goto out; /* success */ @@ -19569,10 +19725,11 @@ 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 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,920 @@ ++++ linux/fs/aufs/i_op_add.c 2018-12-27 13:19:17.711749485 +0100 +@@ -0,0 +1,935 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -19819,11 +19976,12 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c + unsigned char created; + const unsigned char try_aopen + = (arg->type == Creat && arg->u.c.try_aopen); ++ struct vfsub_aopen_args *aopen = arg->u.c.aopen; + struct dentry *wh_dentry, *parent; + struct inode *h_dir; + struct super_block *sb; + struct au_branch *br; -+ /* to reuduce stack size */ ++ /* to reduce stack size */ + struct { + struct au_dtime dt; + struct au_pin pin; @@ -19866,30 +20024,42 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c + h_dir = au_pinned_h_dir(&a->pin); + switch (arg->type) { + case Creat: -+ err = 0; -+ if (!try_aopen || !h_dir->i_op->atomic_open) ++ if (!try_aopen || !h_dir->i_op->atomic_open) { + err = vfsub_create(h_dir, &a->h_path, arg->u.c.mode, + arg->u.c.want_excl); -+ else -+ err = vfsub_atomic_open(h_dir, a->h_path.dentry, -+ arg->u.c.aopen, br); ++ created = !err; ++ if (!err && try_aopen) ++ aopen->file->f_mode |= FMODE_CREATED; ++ } else { ++ aopen->br = br; ++ err = vfsub_atomic_open(h_dir, a->h_path.dentry, aopen); ++ AuDbg("err %d\n", err); ++ AuDbgFile(aopen->file); ++ created = err >= 0 ++ && !!(aopen->file->f_mode & FMODE_CREATED); ++ } + break; + case Symlink: + err = vfsub_symlink(h_dir, &a->h_path, arg->u.s.symname); ++ created = !err; + break; + case Mknod: + err = vfsub_mknod(h_dir, &a->h_path, arg->u.m.mode, + arg->u.m.dev); ++ created = !err; + break; + default: + BUG(); + } -+ created = !err; ++ if (unlikely(err < 0)) ++ goto out_unpin; ++ ++ err = epilog(dir, btop, wh_dentry, dentry); + if (!err) -+ err = epilog(dir, btop, wh_dentry, dentry); ++ goto out_unpin; /* success */ + + /* revert */ -+ if (unlikely(created && err && d_is_positive(a->h_path.dentry))) { ++ 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); @@ -19900,13 +20070,14 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c + } + au_dtime_revert(&a->dt); + } ++ if (try_aopen && h_dir->i_op->atomic_open ++ && (aopen->file->f_mode & FMODE_OPENED)) ++ /* aopen->file is still opened */ ++ au_lcnt_dec(&aopen->br->br_nfiles); + -+ if (!err && try_aopen && !h_dir->i_op->atomic_open) -+ *arg->u.c.aopen->opened |= FILE_CREATED; -+ ++out_unpin: + au_unpin(&a->pin); + dput(wh_dentry); -+ +out_parent: + if (!try_aopen) + di_write_unlock(parent); @@ -19918,7 +20089,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c + if (!try_aopen) + aufs_read_unlock(dentry, AuLock_DW); +out_free: -+ kfree(a); ++ au_kfree_rcu(a); +out: + return err; +} @@ -20279,7 +20450,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c + + /* + * aufs doesn't touch the credential so -+ * security_dentry_create_files_as() is unnecrssary. ++ * security_dentry_create_files_as() is unnecessary. + */ + if (au_opt_test(au_mntflags(sb), PLINK)) { + if (a->bdst < a->bsrc @@ -20378,7 +20549,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c + } + aufs_read_and_write_unlock2(dentry, src_dentry); +out_kfree: -+ kfree(a); ++ au_kfree_rcu(a); +out: + AuTraceErr(err); + return err; @@ -20487,16 +20658,17 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c + } + aufs_read_unlock(dentry, AuLock_DW); +out_free: -+ kfree(a); ++ au_kfree_rcu(a); +out: + return err; +} 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 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,1459 @@ ++++ linux/fs/aufs/i_op.c 2018-12-27 13:19:17.708416053 +0100 +@@ -0,0 +1,1506 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -20536,7 +20708,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + if (((mask & MAY_EXEC) + && S_ISREG(h_inode->i_mode) + && (path_noexec(h_path) -+ || !(h_inode->i_mode & S_IXUGO)))) ++ || !(h_inode->i_mode & 0111)))) + goto out; + + /* @@ -20551,7 +20723,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + && write_mask && !(mask & MAY_READ)) + || !h_inode->i_op->permission) { + /* AuLabel(generic_permission); */ -+ /* AuDbg("get_acl %pf\n", h_inode->i_op->get_acl); */ ++ /* AuDbg("get_acl %ps\n", h_inode->i_op->get_acl); */ + err = generic_permission(h_inode, mask); + if (err == -EOPNOTSUPP && au_test_nfs_noacl(h_inode)) + err = h_inode->i_op->permission(h_inode, mask); @@ -20748,6 +20920,28 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + +/* ---------------------------------------------------------------------- */ + ++/* ++ * very dirty and complicated aufs ->atomic_open(). ++ * aufs_atomic_open() ++ * + au_aopen_or_create() ++ * + add_simple() ++ * + vfsub_atomic_open() ++ * + branch fs ->atomic_open() ++ * may call the actual 'open' for h_file ++ * + inc br_nfiles only if opened ++ * + au_aopen_no_open() or au_aopen_do_open() ++ * ++ * au_aopen_do_open() ++ * + finish_open() ++ * + au_do_aopen() ++ * + au_do_open() the body of all 'open' ++ * + au_do_open_nondir() ++ * set the passed h_file ++ * ++ * au_aopen_no_open() ++ * + finish_no_open() ++ */ ++ +struct aopen_node { + struct hlist_bl_node hblist; + struct file *file, *h_file; @@ -20776,18 +20970,50 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + return au_do_open(file, &args); +} + ++static int au_aopen_do_open(struct file *file, struct dentry *dentry, ++ struct aopen_node *aopen_node) ++{ ++ int err; ++ struct hlist_bl_head *aopen; ++ ++ AuLabel(here); ++ aopen = &au_sbi(dentry->d_sb)->si_aopen; ++ au_hbl_add(&aopen_node->hblist, aopen); ++ err = finish_open(file, dentry, au_do_aopen); ++ au_hbl_del(&aopen_node->hblist, aopen); ++ /* AuDbgFile(file); */ ++ AuDbg("%pd%s%s\n", dentry, ++ (file->f_mode & FMODE_CREATED) ? " created" : "", ++ (file->f_mode & FMODE_OPENED) ? " opened" : ""); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_aopen_no_open(struct file *file, struct dentry *dentry) ++{ ++ int err; ++ ++ AuLabel(here); ++ dget(dentry); ++ err = finish_no_open(file, dentry); ++ ++ AuTraceErr(err); ++ return err; ++} ++ +static int aufs_atomic_open(struct inode *dir, struct dentry *dentry, + struct file *file, unsigned int open_flag, -+ umode_t create_mode, int *opened) ++ umode_t create_mode) +{ -+ int err, unlocked, h_opened = *opened; ++ int err, did_open; + unsigned int lkup_flags; ++ aufs_bindex_t bindex; ++ struct super_block *sb; + struct dentry *parent, *d; -+ struct hlist_bl_head *aopen; + struct vfsub_aopen_args args = { + .open_flag = open_flag, -+ .create_mode = create_mode, -+ .opened = &h_opened ++ .create_mode = create_mode + }; + struct aopen_node aopen_node = { + .file = file @@ -20822,82 +21048,73 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + if (d_is_positive(dentry) + || d_unhashed(dentry) + || d_unlinked(dentry) -+ || !(open_flag & O_CREAT)) -+ goto out_no_open; ++ || !(open_flag & O_CREAT)) { ++ err = au_aopen_no_open(file, dentry); ++ goto out; /* success */ ++ } + -+ unlocked = 0; + err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); + if (unlikely(err)) + goto out; + ++ sb = dentry->d_sb; + parent = dentry->d_parent; /* dir is locked */ + di_write_lock_parent(parent); + err = au_lkup_dentry(dentry, /*btop*/0, AuLkup_ALLOW_NEG); -+ if (unlikely(err)) -+ goto out_unlock; ++ if (unlikely(err < 0)) ++ goto out_parent; + + AuDbgDentry(dentry); -+ if (d_is_positive(dentry)) -+ goto out_unlock; ++ if (d_is_positive(dentry)) { ++ err = au_aopen_no_open(file, dentry); ++ goto out_parent; /* success */ ++ } + -+ args.file = get_empty_filp(); ++ args.file = alloc_empty_file(file->f_flags, current_cred()); + err = PTR_ERR(args.file); + if (IS_ERR(args.file)) -+ goto out_unlock; ++ goto out_parent; + -+ args.file->f_flags = file->f_flags; ++ bindex = au_dbtop(dentry); + err = au_aopen_or_create(dir, dentry, &args); + AuTraceErr(err); + AuDbgFile(args.file); -+ if (unlikely(err < 0)) { -+ if (h_opened & FILE_OPENED) -+ fput(args.file); -+ else -+ put_filp(args.file); -+ goto out_unlock; ++ file->f_mode = args.file->f_mode & ~FMODE_OPENED; ++ did_open = !!(args.file->f_mode & FMODE_OPENED); ++ if (!did_open) { ++ fput(args.file); ++ args.file = NULL; + } + di_write_unlock(parent); + di_write_unlock(dentry); -+ unlocked = 1; -+ -+ /* some filesystems don't set FILE_CREATED while succeeded? */ -+ *opened |= FILE_CREATED; -+ if (h_opened & FILE_OPENED) -+ aopen_node.h_file = args.file; -+ else { -+ put_filp(args.file); -+ args.file = NULL; ++ if (unlikely(err < 0)) { ++ if (args.file) ++ fput(args.file); ++ goto out_sb; + } -+ aopen = &au_sbi(dir->i_sb)->si_aopen; -+ au_hbl_add(&aopen_node.hblist, aopen); -+ err = finish_open(file, dentry, au_do_aopen, opened); -+ au_hbl_del(&aopen_node.hblist, aopen); -+ AuTraceErr(err); -+ AuDbgFile(file); -+ if (aopen_node.h_file) -+ fput(aopen_node.h_file); + -+out_unlock: -+ if (unlocked) -+ si_read_unlock(dentry->d_sb); ++ if (!did_open) ++ err = au_aopen_no_open(file, dentry); + else { -+ di_write_unlock(parent); -+ aufs_read_unlock(dentry, AuLock_DW); ++ aopen_node.h_file = args.file; ++ err = au_aopen_do_open(file, dentry, &aopen_node); + } -+ AuDbgDentry(dentry); -+ if (unlikely(err < 0)) -+ goto out; -+out_no_open: -+ if (err >= 0 && !(*opened & FILE_CREATED)) { -+ AuLabel(out_no_open); -+ dget(dentry); -+ err = finish_no_open(file, dentry); ++ if (unlikely(err < 0)) { ++ if (args.file) ++ fput(args.file); ++ if (did_open) ++ au_lcnt_dec(&args.br->br_nfiles); + } ++ goto out_sb; /* success */ ++ ++out_parent: ++ di_write_unlock(parent); ++ di_write_unlock(dentry); ++out_sb: ++ si_read_unlock(sb); +out: -+ AuDbg("%pd%s%s\n", dentry, -+ (*opened & FILE_CREATED) ? " created" : "", -+ (*opened & FILE_OPENED) ? " opened" : ""); + AuTraceErr(err); ++ AuDbgFile(file); + return err; +} + @@ -21507,7 +21724,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c +out_si: + si_read_unlock(sb); +out_kfree: -+ kfree(a); ++ au_kfree_rcu(a); +out: + AuTraceErr(err); + return err; @@ -21598,7 +21815,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + di_write_unlock(dentry); + si_read_unlock(sb); +out_kfree: -+ kfree(a); ++ au_kfree_rcu(a); +out: + AuTraceErr(err); + return err; @@ -21808,7 +22025,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + goto out_unlock; + + err = 0; -+ AuDbg("%pf\n", h_inode->i_op->get_link); ++ AuDbg("%ps\n", h_inode->i_op->get_link); + AuDbgDentry(h_dentry); + ret = vfs_get_link(h_dentry, done); + dput(h_dentry); @@ -21831,7 +22048,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + return (inode->i_mode & (S_IFBLK | S_IFCHR | S_IFIFO | S_IFSOCK)); +} + -+static int aufs_update_time(struct inode *inode, struct timespec *ts, int flags) ++static int aufs_update_time(struct inode *inode, struct timespec64 *ts, ++ int flags) +{ + int err; + aufs_bindex_t bindex; @@ -21956,10 +22174,11 @@ 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 2018-04-06 07:48:44.204604724 +0200 -@@ -0,0 +1,511 @@ ++++ linux/fs/aufs/i_op_del.c 2018-12-27 13:19:17.711749485 +0100 +@@ -0,0 +1,512 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -22108,7 +22327,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c + +/* + * decide the branch where we operate for @dentry. the branch index will be set -+ * @rbcpup. after diciding it, 'pin' it and store the timestamps of the parent ++ * @rbcpup. after deciding it, 'pin' it and store the timestamps of the parent + * dir for reverting. + * when a new whiteout is necessary, create it. + */ @@ -22264,7 +22483,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c + aufs_bindex_t bwh, bindex, btop; + struct inode *inode, *h_dir, *delegated; + struct dentry *parent, *wh_dentry; -+ /* to reuduce stack size */ ++ /* to reduce stack size */ + struct { + struct au_dtime dt; + struct au_pin pin; @@ -22354,7 +22573,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c +out_unlock: + aufs_read_unlock(dentry, AuLock_DW); +out_free: -+ kfree(a); ++ au_kfree_rcu(a); +out: + return err; +} @@ -22366,7 +22585,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c + struct inode *inode; + struct dentry *parent, *wh_dentry, *h_dentry; + struct au_whtmp_rmdir *args; -+ /* to reuduce stack size */ ++ /* to reduce stack size */ + struct { + struct au_dtime dt; + struct au_pin pin; @@ -22464,17 +22683,18 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c +out_unlock: + aufs_read_unlock(dentry, AuLock_DW); +out_free: -+ kfree(a); ++ au_kfree_rcu(a); +out: + AuTraceErr(err); + return err; +} 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 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,1246 @@ ++++ linux/fs/aufs/i_op_ren.c 2018-12-27 13:19:17.711749485 +0100 +@@ -0,0 +1,1249 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -23133,7 +23353,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c + * locking order + * (VFS) + * - src_dir and dir by lock_rename() -+ * - inode if exitsts ++ * - inode if exists + * (aufs) + * - lock all + * + src_dentry and dentry by aufs_read_and_write_lock2() which calls, @@ -23451,6 +23671,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c + goto out; + + a->flags = _flags; ++ BUILD_BUG_ON(sizeof(a->exchange) == sizeof(u8) ++ && RENAME_EXCHANGE > U8_MAX); + a->exchange = _flags & RENAME_EXCHANGE; + a->src_dir = _src_dir; + a->src_dentry = _src_dentry; @@ -23714,14 +23936,14 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c + iput(a->dst_inode); + if (a->thargs) + au_whtmp_rmdir_free(a->thargs); -+ kfree(a); ++ au_kfree_rcu(a); +out: + AuTraceErr(err); + return err; +} diff -urN /usr/share/empty/fs/aufs/Kconfig linux/fs/aufs/Kconfig --- /usr/share/empty/fs/aufs/Kconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/Kconfig 2018-04-06 07:48:44.201271351 +0200 ++++ linux/fs/aufs/Kconfig 2018-06-04 09:08:09.181412645 +0200 @@ -0,0 +1,199 @@ +# SPDX-License-Identifier: GPL-2.0 +config AUFS_FS @@ -23922,12 +24144,203 @@ diff -urN /usr/share/empty/fs/aufs/Kconfig linux/fs/aufs/Kconfig + Automatic configuration for internal use. + When aufs supports Magic SysRq, enabled automatically. +endif +diff -urN /usr/share/empty/fs/aufs/lcnt.h linux/fs/aufs/lcnt.h +--- /usr/share/empty/fs/aufs/lcnt.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux/fs/aufs/lcnt.h 2018-10-23 12:33:35.599375796 +0200 +@@ -0,0 +1,186 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2018 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * simple long counter wrapper ++ */ ++ ++#ifndef __AUFS_LCNT_H__ ++#define __AUFS_LCNT_H__ ++ ++#ifdef __KERNEL__ ++ ++#include "debug.h" ++ ++#define AuLCntATOMIC 1 ++#define AuLCntPCPUCNT 2 ++/* ++ * why does percpu_refcount require extra synchronize_rcu()s in ++ * au_br_do_free() ++ */ ++#define AuLCntPCPUREF 3 ++ ++/* #define AuLCntChosen AuLCntATOMIC */ ++#define AuLCntChosen AuLCntPCPUCNT ++/* #define AuLCntChosen AuLCntPCPUREF */ ++ ++#if AuLCntChosen == AuLCntATOMIC ++#include ++ ++typedef atomic_long_t au_lcnt_t; ++ ++static inline int au_lcnt_init(au_lcnt_t *cnt, void *release __maybe_unused) ++{ ++ atomic_long_set(cnt, 0); ++ return 0; ++} ++ ++static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused) ++{ ++ /* empty */ ++} ++ ++static inline void au_lcnt_fin(au_lcnt_t *cnt __maybe_unused, ++ int do_sync __maybe_unused) ++{ ++ /* empty */ ++} ++ ++static inline void au_lcnt_inc(au_lcnt_t *cnt) ++{ ++ atomic_long_inc(cnt); ++} ++ ++static inline void au_lcnt_dec(au_lcnt_t *cnt) ++{ ++ atomic_long_dec(cnt); ++} ++ ++static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev __maybe_unused) ++{ ++ return atomic_long_read(cnt); ++} ++#endif ++ ++#if AuLCntChosen == AuLCntPCPUCNT ++#include ++ ++typedef struct percpu_counter au_lcnt_t; ++ ++static inline int au_lcnt_init(au_lcnt_t *cnt, void *release __maybe_unused) ++{ ++ return percpu_counter_init(cnt, 0, GFP_NOFS); ++} ++ ++static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused) ++{ ++ /* empty */ ++} ++ ++static inline void au_lcnt_fin(au_lcnt_t *cnt, int do_sync __maybe_unused) ++{ ++ percpu_counter_destroy(cnt); ++} ++ ++static inline void au_lcnt_inc(au_lcnt_t *cnt) ++{ ++ percpu_counter_inc(cnt); ++} ++ ++static inline void au_lcnt_dec(au_lcnt_t *cnt) ++{ ++ percpu_counter_dec(cnt); ++} ++ ++static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev __maybe_unused) ++{ ++ s64 n; ++ ++ n = percpu_counter_sum(cnt); ++ BUG_ON(n < 0); ++ if (LONG_MAX != LLONG_MAX ++ && n > LONG_MAX) ++ AuWarn1("%s\n", "wrap-around"); ++ ++ return n; ++} ++#endif ++ ++#if AuLCntChosen == AuLCntPCPUREF ++#include ++ ++typedef struct percpu_ref au_lcnt_t; ++ ++static inline int au_lcnt_init(au_lcnt_t *cnt, percpu_ref_func_t *release) ++{ ++ if (!release) ++ release = percpu_ref_exit; ++ return percpu_ref_init(cnt, release, /*percpu mode*/0, GFP_NOFS); ++} ++ ++static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused) ++{ ++ synchronize_rcu(); ++} ++ ++static inline void au_lcnt_fin(au_lcnt_t *cnt, int do_sync) ++{ ++ percpu_ref_kill(cnt); ++ if (do_sync) ++ au_lcnt_wait_for_fin(cnt); ++} ++ ++static inline void au_lcnt_inc(au_lcnt_t *cnt) ++{ ++ percpu_ref_get(cnt); ++} ++ ++static inline void au_lcnt_dec(au_lcnt_t *cnt) ++{ ++ percpu_ref_put(cnt); ++} ++ ++/* ++ * avoid calling this func as possible. ++ */ ++static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev) ++{ ++ long l; ++ ++ percpu_ref_switch_to_atomic_sync(cnt); ++ l = atomic_long_read(&cnt->count); ++ if (do_rev) ++ percpu_ref_switch_to_percpu(cnt); ++ ++ /* percpu_ref is initialized by 1 instead of 0 */ ++ return l - 1; ++} ++#endif ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define AuLCntZero(val) do { \ ++ long l = val; \ ++ if (l) \ ++ AuDbg("%s = %ld\n", #val, l); \ ++} while (0) ++#else ++#define AuLCntZero(val) do {} while (0) ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_LCNT_H__ */ diff -urN /usr/share/empty/fs/aufs/loop.c linux/fs/aufs/loop.c --- /usr/share/empty/fs/aufs/loop.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/loop.c 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,147 @@ ++++ linux/fs/aufs/loop.c 2018-12-27 13:19:17.711749485 +0100 +@@ -0,0 +1,148 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -24071,14 +24484,15 @@ diff -urN /usr/share/empty/fs/aufs/loop.c linux/fs/aufs/loop.c +{ + if (backing_file_func) + symbol_put(loop_backing_file); -+ kfree(au_warn_loopback_array); ++ au_kfree_try_rcu(au_warn_loopback_array); +} diff -urN /usr/share/empty/fs/aufs/loop.h linux/fs/aufs/loop.h --- /usr/share/empty/fs/aufs/loop.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/loop.h 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,52 @@ ++++ linux/fs/aufs/loop.h 2018-08-12 23:43:05.460124736 +0200 +@@ -0,0 +1,53 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -24131,7 +24545,7 @@ diff -urN /usr/share/empty/fs/aufs/loop.h linux/fs/aufs/loop.h +#endif /* __AUFS_LOOP_H__ */ diff -urN /usr/share/empty/fs/aufs/magic.mk linux/fs/aufs/magic.mk --- /usr/share/empty/fs/aufs/magic.mk 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/magic.mk 2018-04-06 07:48:44.207938097 +0200 ++++ linux/fs/aufs/magic.mk 2018-06-04 09:08:09.188079511 +0200 @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0 + @@ -24166,7 +24580,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 2018-04-06 07:48:44.201271351 +0200 ++++ linux/fs/aufs/Makefile 2018-06-04 09:08:09.181412645 +0200 @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: GPL-2.0 + @@ -24216,10 +24630,11 @@ diff -urN /usr/share/empty/fs/aufs/Makefile linux/fs/aufs/Makefile +aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o 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 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,266 @@ ++++ linux/fs/aufs/module.c 2018-12-27 13:19:17.711749485 +0100 +@@ -0,0 +1,273 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -24254,7 +24669,7 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c + if (p) { +#if 0 /* unused */ + if (!new_sz) { -+ kfree(p); ++ au_kfree_rcu(p); + p = NULL; + goto out; + } @@ -24278,7 +24693,7 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c + if (q) { + if (p) { + memcpy(q, p, new_sz); -+ kfree(p); ++ au_kfree_try_rcu(p); + } + p = q; + } else @@ -24369,12 +24784,12 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c +/* this module parameter has no meaning when SYSFS is disabled */ +int sysaufs_brs = 1; +MODULE_PARM_DESC(brs, "use /fs/aufs/si_*/brN"); -+module_param_named(brs, sysaufs_brs, int, S_IRUGO); ++module_param_named(brs, sysaufs_brs, int, 0444); + +/* this module parameter has no meaning when USER_NS is disabled */ +bool au_userns; +MODULE_PARM_DESC(allow_userns, "allow unprivileged to mount under userns"); -+module_param_named(allow_userns, au_userns, bool, S_IRUGO); ++module_param_named(allow_userns, au_userns, bool, 0444); + +/* ---------------------------------------------------------------------- */ + @@ -24422,9 +24837,12 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c + err = sysaufs_init(); + if (unlikely(err)) + goto out; -+ err = au_procfs_init(); ++ err = dbgaufs_init(); + if (unlikely(err)) + goto out_sysaufs; ++ err = au_procfs_init(); ++ if (unlikely(err)) ++ goto out_dbgaufs; + err = au_wkq_init(); + if (unlikely(err)) + goto out_procfs; @@ -24462,6 +24880,8 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c + au_wkq_fin(); +out_procfs: + au_procfs_fin(); ++out_dbgaufs: ++ dbgaufs_fin(); +out_sysaufs: + sysaufs_fin(); + au_dy_fin(); @@ -24478,6 +24898,7 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c + au_loopback_fin(); + au_wkq_fin(); + au_procfs_fin(); ++ dbgaufs_fin(); + sysaufs_fin(); + au_dy_fin(); +} @@ -24486,10 +24907,11 @@ 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 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,101 @@ ++++ linux/fs/aufs/module.h 2018-12-27 13:19:17.711749485 +0100 +@@ -0,0 +1,166 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -24515,6 +24937,11 @@ diff -urN /usr/share/empty/fs/aufs/module.h linux/fs/aufs/module.h +#ifdef __KERNEL__ + +#include ++#include "debug.h" ++#include "dentry.h" ++#include "dir.h" ++#include "file.h" ++#include "inode.h" + +struct path; +struct seq_file; @@ -24531,6 +24958,53 @@ diff -urN /usr/share/empty/fs/aufs/module.h linux/fs/aufs/module.h +void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp, + int may_shrink); + ++/* ++ * Comparing the size of the object with sizeof(struct rcu_head) ++ * case 1: object is always larger ++ * --> au_kfree_rcu() or au_kfree_do_rcu() ++ * case 2: object is always smaller ++ * --> au_kfree_small() ++ * case 3: object can be any size ++ * --> au_kfree_try_rcu() ++ */ ++ ++static inline void au_kfree_do_rcu(const void *p) ++{ ++ struct { ++ struct rcu_head rcu; ++ } *a = (void *)p; ++ ++ kfree_rcu(a, rcu); ++} ++ ++#define au_kfree_rcu(_p) do { \ ++ typeof(_p) p = (_p); \ ++ BUILD_BUG_ON(sizeof(*p) < sizeof(struct rcu_head)); \ ++ if (p) \ ++ au_kfree_do_rcu(p); \ ++ } while (0) ++ ++#define au_kfree_do_sz_test(sz) (sz >= sizeof(struct rcu_head)) ++#define au_kfree_sz_test(p) (p && au_kfree_do_sz_test(ksize(p))) ++ ++static inline void au_kfree_try_rcu(const void *p) ++{ ++ if (!p) ++ return; ++ if (au_kfree_sz_test(p)) ++ au_kfree_do_rcu(p); ++ else ++ kfree(p); ++} ++ ++static inline void au_kfree_small(const void *p) ++{ ++ if (!p) ++ return; ++ AuDebugOn(au_kfree_sz_test(p)); ++ kfree(p); ++} ++ +static inline int au_kmidx_sub(size_t sz, size_t new_sz) +{ +#ifndef CONFIG_SLOB @@ -24572,11 +25046,23 @@ diff -urN /usr/share/empty/fs/aufs/module.h linux/fs/aufs/module.h + kmem_cache_create(#type, sizeof(struct type), \ + __alignof__(struct type), AuCacheFlags, ctor) + -+#define AuCacheFuncs(name, index) \ -+static inline struct au_##name *au_cache_alloc_##name(void) \ -+{ return kmem_cache_alloc(au_cache[AuCache_##index], GFP_NOFS); } \ -+static inline void au_cache_free_##name(struct au_##name *p) \ -+{ kmem_cache_free(au_cache[AuCache_##index], p); } ++#define AuCacheFuncs(name, index) \ ++ static inline struct au_##name *au_cache_alloc_##name(void) \ ++ { return kmem_cache_alloc(au_cache[AuCache_##index], GFP_NOFS); } \ ++ static inline void au_cache_free_##name##_norcu(struct au_##name *p) \ ++ { kmem_cache_free(au_cache[AuCache_##index], p); } \ ++ \ ++ static inline void au_cache_free_##name##_rcu_cb(struct rcu_head *rcu) \ ++ { void *p = rcu; \ ++ p -= offsetof(struct au_##name, rcu); \ ++ kmem_cache_free(au_cache[AuCache_##index], p); } \ ++ static inline void au_cache_free_##name##_rcu(struct au_##name *p) \ ++ { BUILD_BUG_ON(sizeof(struct au_##name) < sizeof(struct rcu_head)); \ ++ call_rcu(&p->rcu, au_cache_free_##name##_rcu_cb); } \ ++ \ ++ static inline void au_cache_free_##name(struct au_##name *p) \ ++ { /* au_cache_free_##name##_norcu(p); */ \ ++ au_cache_free_##name##_rcu(p); } + +AuCacheFuncs(dinfo, DINFO); +AuCacheFuncs(icntnr, ICNTNR); @@ -24591,10 +25077,11 @@ 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 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,704 @@ ++++ linux/fs/aufs/mvdown.c 2018-12-27 13:19:17.711749485 +0100 +@@ -0,0 +1,705 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2011-2017 Junjiro R. Okajima ++ * Copyright (C) 2011-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -25292,17 +25779,18 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c + e = copy_to_user(uarg, &args->mvdown, sizeof(args->mvdown)); + if (unlikely(e)) + err = -EFAULT; -+ kfree(args); ++ au_kfree_rcu(args); +out: + AuTraceErr(err); + return err; +} diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c --- /usr/share/empty/fs/aufs/opts.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/opts.c 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,1891 @@ ++++ linux/fs/aufs/opts.c 2018-12-27 13:19:17.711749485 +0100 +@@ -0,0 +1,1877 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -26167,7 +26655,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + mod->path = args[0].from; + p = strchr(mod->path, '='); + if (unlikely(!p)) { -+ pr_err("no permssion %s\n", args[0].from); ++ pr_err("no permission %s\n", args[0].from); + goto out; + } + @@ -26562,7 +27050,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + } + } + -+ kfree(a); ++ au_kfree_rcu(a); + dump_opts(opts); + if (unlikely(err)) + au_opts_free(opts); @@ -26745,7 +27233,8 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + + case Opt_trunc_xino_path: + case Opt_itrunc_xino: -+ err = au_xino_trunc(sb, opt->xino_itrunc.bindex); ++ err = au_xino_trunc(sb, opt->xino_itrunc.bindex, ++ /*idx_begin*/0); + if (!err) + err = 1; + break; @@ -26855,8 +27344,6 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + struct au_opts *opts) +{ + int err; -+ aufs_bindex_t bbot, bindex; -+ struct dentry *root, *parent, *h_root; + + err = 0; + switch (opt->type) { @@ -26867,24 +27354,10 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + break; + + *opt_xino = &opt->xino; -+ au_xino_brid_set(sb, -1); -+ -+ /* safe d_parent access */ -+ parent = opt->xino.file->f_path.dentry->d_parent; -+ root = sb->s_root; -+ bbot = au_sbbot(sb); -+ for (bindex = 0; bindex <= bbot; bindex++) { -+ h_root = au_h_dptr(root, bindex); -+ if (h_root == parent) { -+ au_xino_brid_set(sb, au_sbr_id(sb, bindex)); -+ break; -+ } -+ } + break; + + case Opt_noxino: + au_xino_clr(sb); -+ au_xino_brid_set(sb, -1); + *opt_xino = (void *)-1; + break; + } @@ -27007,7 +27480,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + au_hn_inode_unlock(hdir); + + if (!err && do_free) { -+ kfree(wbr); ++ au_kfree_rcu(wbr); + br->br_wbr = NULL; + } + } @@ -27194,10 +27667,11 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c +} diff -urN /usr/share/empty/fs/aufs/opts.h linux/fs/aufs/opts.h --- /usr/share/empty/fs/aufs/opts.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/opts.h 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,224 @@ ++++ linux/fs/aufs/opts.h 2018-08-12 23:43:05.460124736 +0200 +@@ -0,0 +1,225 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -27422,10 +27896,11 @@ 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 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,515 @@ ++++ linux/fs/aufs/plink.c 2018-10-23 12:33:35.599375796 +0200 +@@ -0,0 +1,516 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -27824,7 +28299,7 @@ diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c + hlist_bl_unlock(hbl); + if (!found) { + cnt = au_hbl_count(hbl); -+#define msg "unexpectedly unblanced or too many pseudo-links" ++#define msg "unexpectedly unbalanced or too many pseudo-links" + if (cnt > AUFS_PLINK_WARN) + AuWarn1(msg ", %d\n", cnt); +#undef msg @@ -27941,10 +28416,11 @@ diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c +} diff -urN /usr/share/empty/fs/aufs/poll.c linux/fs/aufs/poll.c --- /usr/share/empty/fs/aufs/poll.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/poll.c 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,52 @@ ++++ linux/fs/aufs/poll.c 2018-08-12 23:43:05.460124736 +0200 +@@ -0,0 +1,51 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -27967,10 +28443,9 @@ diff -urN /usr/share/empty/fs/aufs/poll.c linux/fs/aufs/poll.c + +#include "aufs.h" + -+__poll_t aufs_poll(struct file *file, poll_table *wait) ++__poll_t aufs_poll(struct file *file, struct poll_table_struct *pt) +{ + __poll_t mask; -+ int err; + struct file *h_file; + struct super_block *sb; + @@ -27980,27 +28455,27 @@ diff -urN /usr/share/empty/fs/aufs/poll.c linux/fs/aufs/poll.c + si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); + + h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); -+ err = PTR_ERR(h_file); -+ if (IS_ERR(h_file)) ++ if (IS_ERR(h_file)) { ++ AuDbg("h_file %ld\n", PTR_ERR(h_file)); + goto out; ++ } + -+ /* it is not an error if h_file has no operation */ -+ mask = DEFAULT_POLLMASK; -+ if (h_file->f_op->poll) -+ mask = h_file->f_op->poll(h_file, wait); ++ mask = vfs_poll(h_file, pt); + fput(h_file); /* instead of au_read_post() */ + +out: + si_read_unlock(sb); -+ AuDbg("mask 0x%x\n", mask); ++ if (mask & EPOLLERR) ++ AuDbg("mask 0x%x\n", mask); + return mask; +} diff -urN /usr/share/empty/fs/aufs/posix_acl.c linux/fs/aufs/posix_acl.c --- /usr/share/empty/fs/aufs/posix_acl.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/posix_acl.c 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,102 @@ ++++ linux/fs/aufs/posix_acl.c 2018-08-12 23:43:05.460124736 +0200 +@@ -0,0 +1,103 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2014-2017 Junjiro R. Okajima ++ * Copyright (C) 2014-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -28103,10 +28578,11 @@ diff -urN /usr/share/empty/fs/aufs/posix_acl.c linux/fs/aufs/posix_acl.c +} diff -urN /usr/share/empty/fs/aufs/procfs.c linux/fs/aufs/procfs.c --- /usr/share/empty/fs/aufs/procfs.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/procfs.c 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,170 @@ ++++ linux/fs/aufs/procfs.c 2018-08-12 23:43:05.460124736 +0200 +@@ -0,0 +1,171 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2010-2017 Junjiro R. Okajima ++ * Copyright (C) 2010-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -28261,7 +28737,7 @@ diff -urN /usr/share/empty/fs/aufs/procfs.c linux/fs/aufs/procfs.c + if (unlikely(!au_procfs_dir)) + goto out; + -+ entry = proc_create(AUFS_PLINK_MAINT_NAME, S_IFREG | S_IWUSR, ++ entry = proc_create(AUFS_PLINK_MAINT_NAME, S_IFREG | 0200, + au_procfs_dir, &au_procfs_plm_fop); + if (unlikely(!entry)) + goto out_dir; @@ -28277,10 +28753,11 @@ diff -urN /usr/share/empty/fs/aufs/procfs.c linux/fs/aufs/procfs.c +} diff -urN /usr/share/empty/fs/aufs/rdu.c linux/fs/aufs/rdu.c --- /usr/share/empty/fs/aufs/rdu.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/rdu.c 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,381 @@ ++++ linux/fs/aufs/rdu.c 2018-08-12 23:43:05.463458173 +0200 +@@ -0,0 +1,382 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -28662,10 +29139,11 @@ diff -urN /usr/share/empty/fs/aufs/rdu.c linux/fs/aufs/rdu.c +#endif diff -urN /usr/share/empty/fs/aufs/rwsem.h linux/fs/aufs/rwsem.h --- /usr/share/empty/fs/aufs/rwsem.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/rwsem.h 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,72 @@ ++++ linux/fs/aufs/rwsem.h 2018-10-23 12:33:35.599375796 +0200 +@@ -0,0 +1,73 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -28692,7 +29170,7 @@ diff -urN /usr/share/empty/fs/aufs/rwsem.h linux/fs/aufs/rwsem.h + +#include "debug.h" + -+/* in the futre, the name 'au_rwsem' will be totally gone */ ++/* in the future, the name 'au_rwsem' will be totally gone */ +#define au_rwsem rw_semaphore + +/* to debug easier, do not make them inlined functions */ @@ -28738,10 +29216,11 @@ diff -urN /usr/share/empty/fs/aufs/rwsem.h linux/fs/aufs/rwsem.h +#endif /* __AUFS_RWSEM_H__ */ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c --- /usr/share/empty/fs/aufs/sbinfo.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/sbinfo.c 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,304 @@ ++++ linux/fs/aufs/sbinfo.c 2018-12-27 13:19:17.711749485 +0100 +@@ -0,0 +1,313 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -28777,20 +29256,23 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c + AuDebugOn(!hlist_bl_empty(sbinfo->si_plink + i)); + AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len)); + -+ AuDebugOn(percpu_counter_sum(&sbinfo->si_ninodes)); -+ percpu_counter_destroy(&sbinfo->si_ninodes); -+ AuDebugOn(percpu_counter_sum(&sbinfo->si_nfiles)); -+ percpu_counter_destroy(&sbinfo->si_nfiles); ++ AuLCntZero(au_lcnt_read(&sbinfo->si_ninodes, /*do_rev*/0)); ++ au_lcnt_fin(&sbinfo->si_ninodes, /*do_sync*/0); ++ AuLCntZero(au_lcnt_read(&sbinfo->si_nfiles, /*do_rev*/0)); ++ au_lcnt_fin(&sbinfo->si_nfiles, /*do_sync*/0); + ++ dbgaufs_si_fin(sbinfo); + au_rw_write_lock(&sbinfo->si_rwsem); + au_br_free(sbinfo); + au_rw_write_unlock(&sbinfo->si_rwsem); + -+ kfree(sbinfo->si_branch); ++ au_kfree_try_rcu(sbinfo->si_branch); + mutex_destroy(&sbinfo->si_xib_mtx); + AuRwDestroy(&sbinfo->si_rwsem); + -+ kfree(sbinfo); ++ au_lcnt_wait_for_fin(&sbinfo->si_ninodes); ++ /* si_nfiles is waited too */ ++ au_kfree_rcu(sbinfo); +} + +int au_si_alloc(struct super_block *sb) @@ -28809,14 +29291,20 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c + goto out_sbinfo; + + err = sysaufs_si_init(sbinfo); ++ if (!err) { ++ dbgaufs_si_null(sbinfo); ++ err = dbgaufs_si_init(sbinfo); ++ if (unlikely(err)) ++ kobject_put(&sbinfo->si_kobj); ++ } + if (unlikely(err)) + goto out_br; + + au_nwt_init(&sbinfo->si_nowait); + au_rw_init_wlock(&sbinfo->si_rwsem); + -+ percpu_counter_init(&sbinfo->si_ninodes, 0, GFP_NOFS); -+ percpu_counter_init(&sbinfo->si_nfiles, 0, GFP_NOFS); ++ au_lcnt_init(&sbinfo->si_ninodes, /*release*/NULL); ++ au_lcnt_init(&sbinfo->si_nfiles, /*release*/NULL); + + sbinfo->si_bbot = -1; + sbinfo->si_last_br_id = AUFS_BRANCH_MAX / 2; @@ -28834,7 +29322,6 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c + sbinfo->si_xino_expire + = msecs_to_jiffies(AUFS_XINO_DEF_SEC * MSEC_PER_SEC); + mutex_init(&sbinfo->si_xib_mtx); -+ sbinfo->si_xino_brid = -1; + /* leave si_xib_last_pindex and si_xib_next_bit */ + + INIT_HLIST_BL_HEAD(&sbinfo->si_aopen); @@ -28861,9 +29348,9 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c + return 0; /* success */ + +out_br: -+ kfree(sbinfo->si_branch); ++ au_kfree_try_rcu(sbinfo->si_branch); +out_sbinfo: -+ kfree(sbinfo); ++ au_kfree_rcu(sbinfo); +out: + return err; +} @@ -29046,10 +29533,11 @@ 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 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,1051 @@ ++++ linux/fs/aufs/super.c 2018-10-23 12:33:35.599375796 +0200 +@@ -0,0 +1,1048 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -29236,6 +29724,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + struct qstr *name; + struct file *f; + struct dentry *d, *h_root; ++ struct au_branch *br; + + AuRwMustAnyLock(&sbinfo->si_rwsem); + @@ -29246,11 +29735,12 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + + /* stop printing the default xino path on the first writable branch */ + h_root = NULL; -+ brid = au_xino_brid(sb); -+ if (brid >= 0) { -+ bindex = au_br_index(sb, brid); -+ h_root = au_hdentry(au_di(sb->s_root), bindex)->hd_dentry; ++ bindex = au_xi_root(sb, f->f_path.dentry); ++ if (bindex >= 0) { ++ br = au_sbr_sb(sb, bindex); ++ h_root = au_br_dentry(br); + } ++ + d = f->f_path.dentry; + name = &d->d_name; + /* safe ->d_parent because the file is unlinked */ @@ -29520,11 +30010,8 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + struct au_sbinfo *sbinfo; + + sbinfo = au_sbi(sb); -+ if (!sbinfo) -+ return; -+ -+ dbgaufs_si_fin(sbinfo); -+ kobject_put(&sbinfo->si_kobj); ++ if (sbinfo) ++ kobject_put(&sbinfo->si_kobj); +} + +/* ---------------------------------------------------------------------- */ @@ -29595,7 +30082,10 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + +struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max) +{ -+ *max = au_ninodes(sb); ++ struct au_sbinfo *sbi; ++ ++ sbi = au_sbi(sb); ++ *max = au_lcnt_read(&sbi->si_ninodes, /*do_rev*/1); + return au_array_alloc(max, au_iarray_cb, sb, &sb->s_inodes); +} + @@ -29793,7 +30283,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + AuDebugOn(sbi->si_iop_array == aufs_iop); + sbi->si_iop_array = aufs_iop; + } -+ pr_info("reset to %pf and %pf\n", ++ pr_info("reset to %ps and %ps\n", + sb->s_d_op, sbi->si_iop_array); + } + @@ -30013,7 +30503,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + au_opts_free(&opts); + if (!err && au_ftest_si(sbinfo, NO_DREVAL)) { + sb->s_d_op = &aufs_dop_noreval; -+ pr_info("%pf\n", sb->s_d_op); ++ pr_info("%ps\n", sb->s_d_op); + au_refresh_dop(root, /*force_reval*/0); + sbinfo->si_iop_array = aufs_iop_nogetattr; + au_refresh_iop(inode, /*force_getattr*/0); @@ -30027,7 +30517,6 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + dput(root); + sb->s_root = NULL; +out_info: -+ dbgaufs_si_fin(sbinfo); + kobject_put(&sbinfo->si_kobj); + sb->s_fs_info = NULL; +out_opts: @@ -30046,7 +30535,6 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + void *raw_data) +{ + struct dentry *root; -+ struct super_block *sb; + + /* all timestamps always follow the ones on the branch */ + /* mnt->mnt_flags |= MNT_NOATIME | MNT_NODIRATIME; */ @@ -30054,11 +30542,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + if (IS_ERR(root)) + goto out; + -+ sb = root->d_sb; -+ si_write_lock(sb, !AuLock_FLUSH); -+ sysaufs_brs_add(sb, 0); -+ si_write_unlock(sb); -+ au_sbilist_add(sb); ++ au_sbilist_add(root->d_sb); + +out: + return root; @@ -30101,10 +30585,11 @@ 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 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,626 @@ ++++ linux/fs/aufs/super.h 2018-10-23 12:33:35.599375796 +0200 +@@ -0,0 +1,589 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -30132,6 +30617,7 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h +#include +#include +#include "hbl.h" ++#include "lcnt.h" +#include "rwsem.h" +#include "wkq.h" + @@ -30190,7 +30676,7 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + struct au_nowait_tasks si_nowait; + + /* -+ * tried sb->s_umount, but failed due to the dependecy between i_mutex. ++ * tried sb->s_umount, but failed due to the dependency between i_mutex. + * rwsem for au_sbinfo is necessary. + */ + struct au_rwsem si_rwsem; @@ -30199,7 +30685,7 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + * dirty approach to protect sb->sb_inodes and ->s_files (gone) from + * remount. + */ -+ struct percpu_counter si_ninodes, si_nfiles; ++ au_lcnt_t si_ninodes, si_nfiles; + + /* branch management */ + unsigned int si_generation; @@ -30236,12 +30722,14 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + /* external inode number (bitmap and translation table) */ + vfs_readf_t si_xread; + vfs_writef_t si_xwrite; ++ loff_t si_ximaxent; /* max entries in a xino */ ++ + struct file *si_xib; + struct mutex si_xib_mtx; /* protect xib members */ + unsigned long *si_xib_buf; + unsigned long si_xib_last_pindex; + int si_xib_next_bit; -+ aufs_bindex_t si_xino_brid; ++ + unsigned long si_xino_jiffy; + unsigned long si_xino_expire; + /* reserved for future use */ @@ -30249,11 +30737,12 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + +#ifdef CONFIG_AUFS_EXPORT + /* i_generation */ ++ /* todo: make xigen file an array to support many inode numbers */ + struct file *si_xigen; + atomic_t si_xigen_next; +#endif + -+ /* dirty trick to suppoer atomic_open */ ++ /* dirty trick to support atomic_open */ + struct hlist_bl_head si_aopen; + + /* vdir parameters */ @@ -30284,7 +30773,7 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + /* + * sysfs and lifetime management. + * this is not a small structure and it may be a waste of memory in case -+ * of sysfs is disabled, particulary when many aufs-es are mounted. ++ * of sysfs is disabled, particularly when many aufs-es are mounted. + * but using sysfs is majority. + */ + struct kobject si_kobj; @@ -30309,7 +30798,7 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h +/* + * set true when refresh_dirs() failed at remount time. + * then try refreshing dirs at access time again. -+ * if it is false, refreshing dirs at access time is unnecesary ++ * if it is false, refreshing dirs at access time is unnecessary + */ +#define AuSi_FAILED_REFRESH_DIR 1 +#define AuSi_FHSM (1 << 1) /* fhsm is active now */ @@ -30450,7 +30939,7 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h +void au_export_init(struct super_block *sb); +void au_xigen_inc(struct inode *inode); +int au_xigen_new(struct inode *inode); -+int au_xigen_set(struct super_block *sb, struct file *base); ++int au_xigen_set(struct super_block *sb, struct path *path); +void au_xigen_clr(struct super_block *sb); + +static inline int au_busy_or_stale(void) @@ -30464,7 +30953,7 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h +AuStubVoid(au_export_init, struct super_block *sb) +AuStubVoid(au_xigen_inc, struct inode *inode) +AuStubInt0(au_xigen_new, struct inode *inode) -+AuStubInt0(au_xigen_set, struct super_block *sb, struct file *base) ++AuStubInt0(au_xigen_set, struct super_block *sb, struct path *path) +AuStubVoid(au_xigen_clr, struct super_block *sb) +AuStub(int, au_busy_or_stale, return -EBUSY, void) +#endif /* CONFIG_AUFS_EXPORT */ @@ -30672,42 +31161,6 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + return au_sbi(sb)->si_generation; +} + -+static inline unsigned long long au_ninodes(struct super_block *sb) -+{ -+ s64 n = percpu_counter_sum(&au_sbi(sb)->si_ninodes); -+ -+ BUG_ON(n < 0); -+ return n; -+} -+ -+static inline void au_ninodes_inc(struct super_block *sb) -+{ -+ percpu_counter_inc(&au_sbi(sb)->si_ninodes); -+} -+ -+static inline void au_ninodes_dec(struct super_block *sb) -+{ -+ percpu_counter_dec(&au_sbi(sb)->si_ninodes); -+} -+ -+static inline unsigned long long au_nfiles(struct super_block *sb) -+{ -+ s64 n = percpu_counter_sum(&au_sbi(sb)->si_nfiles); -+ -+ BUG_ON(n < 0); -+ return n; -+} -+ -+static inline void au_nfiles_inc(struct super_block *sb) -+{ -+ percpu_counter_inc(&au_sbi(sb)->si_nfiles); -+} -+ -+static inline void au_nfiles_dec(struct super_block *sb) -+{ -+ percpu_counter_dec(&au_sbi(sb)->si_nfiles); -+} -+ +static inline struct au_branch *au_sbr(struct super_block *sb, + aufs_bindex_t bindex) +{ @@ -30715,26 +31168,21 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + return au_sbi(sb)->si_branch[0 + bindex]; +} + -+static inline void au_xino_brid_set(struct super_block *sb, aufs_bindex_t brid) -+{ -+ SiMustWriteLock(sb); -+ au_sbi(sb)->si_xino_brid = brid; -+} -+ -+static inline aufs_bindex_t au_xino_brid(struct super_block *sb) ++static inline loff_t au_xi_maxent(struct super_block *sb) +{ + SiMustAnyLock(sb); -+ return au_sbi(sb)->si_xino_brid; ++ return au_sbi(sb)->si_ximaxent; +} + +#endif /* __KERNEL__ */ +#endif /* __AUFS_SUPER_H__ */ diff -urN /usr/share/empty/fs/aufs/sysaufs.c linux/fs/aufs/sysaufs.c --- /usr/share/empty/fs/aufs/sysaufs.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/sysaufs.c 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,104 @@ ++++ linux/fs/aufs/sysaufs.c 2018-08-12 23:43:05.463458173 +0200 +@@ -0,0 +1,93 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -30794,18 +31242,11 @@ diff -urN /usr/share/empty/fs/aufs/sysaufs.c linux/fs/aufs/sysaufs.c + (&sbinfo->si_kobj, &au_sbi_ktype, /*&sysaufs_kset->kobj*/NULL, + SysaufsSiNamePrefix "%lx", sysaufs_si_id(sbinfo)); + -+ dbgaufs_si_null(sbinfo); -+ if (!err) { -+ err = dbgaufs_si_init(sbinfo); -+ if (unlikely(err)) -+ kobject_put(&sbinfo->si_kobj); -+ } + return err; +} + +void sysaufs_fin(void) +{ -+ dbgaufs_fin(); + sysfs_remove_group(&sysaufs_kset->kobj, sysaufs_attr_group); + kset_unregister(sysaufs_kset); +} @@ -30826,23 +31267,19 @@ diff -urN /usr/share/empty/fs/aufs/sysaufs.c linux/fs/aufs/sysaufs.c + if (IS_ERR(sysaufs_kset)) + goto out; + err = sysfs_create_group(&sysaufs_kset->kobj, sysaufs_attr_group); -+ if (unlikely(err)) { ++ if (unlikely(err)) + kset_unregister(sysaufs_kset); -+ goto out; -+ } + -+ err = dbgaufs_init(); -+ if (unlikely(err)) -+ sysaufs_fin(); +out: + return err; +} diff -urN /usr/share/empty/fs/aufs/sysaufs.h linux/fs/aufs/sysaufs.h --- /usr/share/empty/fs/aufs/sysaufs.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/sysaufs.h 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,101 @@ ++++ linux/fs/aufs/sysaufs.h 2018-08-12 23:43:05.463458173 +0200 +@@ -0,0 +1,102 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -30944,10 +31381,11 @@ diff -urN /usr/share/empty/fs/aufs/sysaufs.h linux/fs/aufs/sysaufs.h +#endif /* __SYSAUFS_H__ */ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c --- /usr/share/empty/fs/aufs/sysfs.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/sysfs.c 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,376 @@ ++++ linux/fs/aufs/sysfs.c 2018-12-27 13:19:17.711749485 +0100 +@@ -0,0 +1,373 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -31157,7 +31595,7 @@ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c + if (unlikely(err == PAGE_SIZE)) + err = -EFBIG; + } -+ kfree(seq); ++ au_kfree_rcu(seq); +out_unlock: + si_read_unlock(sb); +out: @@ -31228,7 +31666,7 @@ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c + err = -EFAULT; + +out_seq: -+ kfree(seq); ++ au_kfree_rcu(seq); +out_buf: + free_page((unsigned long)buf); +out: @@ -31261,7 +31699,7 @@ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c + attr = &br_sysfs->attr; + sysfs_attr_init(attr); + attr->name = br_sysfs->name; -+ attr->mode = S_IRUGO; ++ attr->mode = 0444; + br_sysfs++; + } +} @@ -31274,8 +31712,6 @@ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c + int i; + aufs_bindex_t bbot; + -+ dbgaufs_brs_del(sb, bindex); -+ + if (!sysaufs_brs) + return; + @@ -31299,8 +31735,6 @@ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c + struct au_branch *br; + struct au_brsysfs *br_sysfs; + -+ dbgaufs_brs_add(sb, bindex); -+ + if (!sysaufs_brs) + return; + @@ -31324,10 +31758,11 @@ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c +} diff -urN /usr/share/empty/fs/aufs/sysrq.c linux/fs/aufs/sysrq.c --- /usr/share/empty/fs/aufs/sysrq.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/sysrq.c 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,159 @@ ++++ linux/fs/aufs/sysrq.c 2018-10-23 12:33:35.599375796 +0200 +@@ -0,0 +1,160 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -31344,7 +31779,7 @@ diff -urN /usr/share/empty/fs/aufs/sysrq.c linux/fs/aufs/sysrq.c + */ + +/* -+ * magic sysrq hanlder ++ * magic sysrq handler + */ + +/* #include */ @@ -31438,7 +31873,7 @@ diff -urN /usr/share/empty/fs/aufs/sysrq.c linux/fs/aufs/sysrq.c + +/* module parameter */ +static char *aufs_sysrq_key = "a"; -+module_param_named(sysrq, aufs_sysrq_key, charp, S_IRUGO); ++module_param_named(sysrq, aufs_sysrq_key, charp, 0444); +MODULE_PARM_DESC(sysrq, "MagicSysRq key for " AUFS_NAME); + +static void au_sysrq(int key __maybe_unused) @@ -31487,10 +31922,11 @@ diff -urN /usr/share/empty/fs/aufs/sysrq.c linux/fs/aufs/sysrq.c +} diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c --- /usr/share/empty/fs/aufs/vdir.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/vdir.c 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,892 @@ ++++ linux/fs/aufs/vdir.c 2018-12-27 13:19:17.711749485 +0100 +@@ -0,0 +1,895 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -31601,7 +32037,7 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c + struct hlist_node *node; + + hlist_for_each_entry_safe(pos, node, head, wh_hash) -+ kfree(pos); ++ au_kfree_rcu(pos); +} + +static void au_nhash_de_do_free(struct hlist_head *head) @@ -31628,7 +32064,7 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c + nhash_count(head); + free(head++); + } -+ kfree(nhash->nh_head); ++ au_kfree_try_rcu(nhash->nh_head); +} + +void au_nhash_wh_free(struct au_nhash *whlist) @@ -31847,8 +32283,8 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c + + deblk = vdir->vd_deblk; + while (vdir->vd_nblk--) -+ kfree(*deblk++); -+ kfree(vdir->vd_deblk); ++ au_kfree_try_rcu(*deblk++); ++ au_kfree_try_rcu(vdir->vd_deblk); + au_cache_free_vdir(vdir); +} + @@ -31883,7 +32319,7 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c + if (!err) + return vdir; /* success */ + -+ kfree(vdir->vd_deblk); ++ au_kfree_try_rcu(vdir->vd_deblk); + +out_free: + au_cache_free_vdir(vdir); @@ -31898,7 +32334,7 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c + union au_vdir_deblk_p p, deblk_end; + + while (vdir->vd_nblk > 1) { -+ kfree(vdir->vd_deblk[vdir->vd_nblk - 1]); ++ au_kfree_try_rcu(vdir->vd_deblk[vdir->vd_nblk - 1]); + /* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */ + vdir->vd_nblk--; + } @@ -31974,6 +32410,7 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c + if (au_nhash_test_known_wh(&arg->whlist, name, nlen)) + goto out; /* already whiteouted */ + ++ ino = 0; /* just to suppress a warning */ + if (shwh) + arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type, + &ino); @@ -32332,7 +32769,8 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c + +out: + /* smp_mb(); */ -+ AuDbg("valid %d\n", !valid); ++ if (!valid) ++ AuDbg("valid %d\n", !valid); + return valid; +} + @@ -32343,10 +32781,10 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c + struct au_vdir *vdir_cache; + struct au_vdir_de *de; + -+ vdir_cache = au_fvdir_cache(file); + if (!seek_vdir(file, ctx)) + return 0; + ++ vdir_cache = au_fvdir_cache(file); + deblk_sz = vdir_cache->vd_deblk_sz; + while (1) { + deblk_end.deblk = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; @@ -32383,10 +32821,11 @@ 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 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,894 @@ ++++ linux/fs/aufs/vfsub.c 2018-10-23 12:33:35.599375796 +0200 +@@ -0,0 +1,902 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -32497,9 +32936,10 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c + * cf. linux/fs/namei.c:do_last(), lookup_open() and atomic_open(). + */ +int vfsub_atomic_open(struct inode *dir, struct dentry *dentry, -+ struct vfsub_aopen_args *args, struct au_branch *br) ++ struct vfsub_aopen_args *args) +{ + int err; ++ struct au_branch *br = args->br; + struct file *file = args->file; + /* copied from linux/fs/namei.c:atomic_open() */ + struct dentry *const DENTRY_NOT_SET = (void *)-1UL; @@ -32511,31 +32951,37 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c + if (unlikely(err)) + goto out; + -+ args->file->f_path.dentry = DENTRY_NOT_SET; -+ args->file->f_path.mnt = au_br_mnt(br); ++ au_lcnt_inc(&br->br_nfiles); ++ file->f_path.dentry = DENTRY_NOT_SET; ++ file->f_path.mnt = au_br_mnt(br); ++ AuDbg("%ps\n", dir->i_op->atomic_open); + err = dir->i_op->atomic_open(dir, dentry, file, args->open_flag, -+ args->create_mode, args->opened); -+ if (err >= 0) { -+ /* some filesystems don't set FILE_CREATED while succeeded? */ -+ if (*args->opened & FILE_CREATED) -+ fsnotify_create(dir, dentry); -+ } else ++ args->create_mode); ++ if (unlikely(err < 0)) { ++ au_lcnt_dec(&br->br_nfiles); + goto out; ++ } + ++ /* temporary workaround for nfsv4 branch */ ++ if (au_test_nfs(dir->i_sb)) ++ nfs_mark_for_revalidate(dir); + -+ if (!err) { -+ /* todo: call VFS:may_open() here */ -+ err = open_check_o_direct(file); -+ /* todo: ima_file_check() too? */ -+ if (!err && (args->open_flag & __FMODE_EXEC)) -+ err = deny_write_access(file); -+ if (unlikely(err)) -+ /* note that the file is created and still opened */ -+ goto out; ++ if (file->f_mode & FMODE_CREATED) ++ fsnotify_create(dir, dentry); ++ if (!(file->f_mode & FMODE_OPENED)) { ++ au_lcnt_dec(&br->br_nfiles); ++ goto out; + } + -+ au_br_get(br); -+ fsnotify_open(file); ++ /* todo: call VFS:may_open() here */ ++ /* todo: ima_file_check() too? */ ++ if (!err && (args->open_flag & __FMODE_EXEC)) ++ err = deny_write_access(file); ++ if (!err) ++ fsnotify_open(file); ++ else ++ au_lcnt_dec(&br->br_nfiles); ++ /* note that the file is created and still opened */ + +out: + return err; @@ -32972,7 +33418,7 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c +{ + int err; + -+ AuDbg("%pD, ctx{%pf, %llu}\n", file, ctx->actor, ctx->pos); ++ AuDbg("%pD, ctx{%ps, %llu}\n", file, ctx->actor, ctx->pos); + + lockdep_off(); + err = iterate_dir(file, ctx); @@ -33281,10 +33727,11 @@ 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 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,354 @@ ++++ linux/fs/aufs/vfsub.h 2018-12-27 13:19:17.711749485 +0100 +@@ -0,0 +1,355 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -33319,7 +33766,7 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h +/* copied from linux/fs/internal.h */ +/* todo: BAD approach!! */ +extern void __mnt_drop_write(struct vfsmount *); -+extern int open_check_o_direct(struct file *f); ++extern struct file *alloc_empty_file(int, const struct cred *); + +/* ---------------------------------------------------------------------- */ + @@ -33376,15 +33823,15 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h +int vfsub_update_h_iattr(struct path *h_path, int *did); +struct file *vfsub_dentry_open(struct path *path, int flags); +struct file *vfsub_filp_open(const char *path, int oflags, int mode); ++struct au_branch; +struct vfsub_aopen_args { -+ struct file *file; -+ unsigned int open_flag; -+ umode_t create_mode; -+ int *opened; ++ struct file *file; ++ unsigned int open_flag; ++ umode_t create_mode; ++ struct au_branch *br; +}; -+struct au_branch; +int vfsub_atomic_open(struct inode *dir, struct dentry *dentry, -+ struct vfsub_aopen_args *args, struct au_branch *br); ++ struct vfsub_aopen_args *args); +int vfsub_kern_path(const char *name, unsigned int flags, struct path *path); + +struct dentry *vfsub_lookup_one_len_unlocked(const char *name, @@ -33511,8 +33958,8 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h +} +#endif + -+static inline int vfsub_update_time(struct inode *h_inode, struct timespec *ts, -+ int flags) ++static inline int vfsub_update_time(struct inode *h_inode, ++ struct timespec64 *ts, int flags) +{ + return update_time(h_inode, ts, flags); + /* no vfsub_update_h_iattr() since we don't have struct path */ @@ -33556,13 +34003,13 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h + * re-use branch fs's ioctl(FICLONE) while aufs itself doesn't support such + * ioctl. + */ -+static inline int vfsub_clone_file_range(struct file *src, struct file *dst, -+ u64 len) ++static inline loff_t vfsub_clone_file_range(struct file *src, struct file *dst, ++ loff_t len) +{ -+ int err; ++ loff_t err; + + lockdep_off(); -+ err = vfs_clone_file_range(src, 0, dst, 0, len); ++ err = vfs_clone_file_range(src, 0, dst, 0, len, /*remap_flags*/0); + lockdep_on(); + + return err; @@ -33639,10 +34086,11 @@ 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 2018-04-06 07:48:44.207938097 +0200 ++++ linux/fs/aufs/wbr_policy.c 2018-12-27 13:19:17.711749485 +0100 @@ -0,0 +1,830 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -33769,8 +34217,7 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c + goto out; + h_path.dentry = au_h_dptr(dentry, bdst); + h_path.mnt = au_sbr_mnt(dentry->d_sb, bdst); -+ err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path, -+ S_IRWXU | S_IRUGO | S_IXUGO); ++ err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path, 0755); + if (unlikely(err)) + goto out_put; + au_fset_cpdown(*flags, MADE_DIR); @@ -34104,7 +34551,7 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c + + mfs->mfsrr_bytes = bavail; + AuDbg("b%d\n", mfs->mfs_bindex); -+ kfree(st); ++ au_kfree_rcu(st); +} + +static int au_wbr_create_mfs(struct dentry *dentry, unsigned int flags) @@ -34473,10 +34920,11 @@ 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 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,1061 @@ ++++ linux/fs/aufs/whout.c 2018-12-27 13:19:17.711749485 +0100 +@@ -0,0 +1,1062 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -34498,7 +34946,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c + +#include "aufs.h" + -+#define WH_MASK S_IRUGO ++#define WH_MASK 0444 + +/* + * If a directory contains this file, then it is opaque. We start with the @@ -34639,7 +35087,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c + +out_name: + if (name != defname) -+ kfree(name); ++ au_kfree_try_rcu(name); +out: + AuTraceErrPtr(dentry); + return dentry; @@ -34791,10 +35239,10 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c + + err = -EEXIST; + if (d_is_negative(path->dentry)) { -+ int mode = S_IRWXU; ++ int mode = 0700; + + if (au_test_nfs(path->dentry->d_sb)) -+ mode |= S_IXUGO; ++ mode |= 0111; + err = vfsub_mkdir(h_dir, path, mode); + } else if (d_is_dir(path->dentry)) + err = 0; @@ -34823,7 +35271,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c +/* + * returns tri-state, + * minus: error, caller should print the message -+ * zero: succuess ++ * zero: success + * plus: error, caller should NOT print the message + */ +static int au_wh_init_rw_nolink(struct dentry *h_root, struct au_wbr *wbr, @@ -35076,10 +35524,10 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c +out: + if (wbr) + atomic_dec(&wbr->wbr_wh_running); -+ au_br_put(a->br); ++ au_lcnt_dec(&a->br->br_count); + si_write_unlock(a->sb); + au_nwt_done(&au_sbi(a->sb)->si_nowait); -+ kfree(arg); ++ au_kfree_rcu(a); + if (unlikely(err)) + AuIOErr("err %d\n", err); +} @@ -35102,12 +35550,12 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c + */ + arg->sb = sb; + arg->br = br; -+ au_br_get(br); ++ au_lcnt_inc(&br->br_count); + wkq_err = au_wkq_nowait(reinit_br_wh, arg, sb, /*flags*/0); + if (unlikely(wkq_err)) { + atomic_dec(&br->br_wbr->wbr_wh_running); -+ au_br_put(br); -+ kfree(arg); ++ au_lcnt_dec(&br->br_count); ++ au_kfree_rcu(arg); + } + do_dec = 0; + } @@ -35266,7 +35714,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c + wh_dentry = ERR_PTR(err); + if (!err) { + wh_dentry = vfsub_lkup_one(&wh_name, h_parent); -+ kfree(wh_name.name); ++ au_kfree_try_rcu(wh_name.name); + } + return wh_dentry; +} @@ -35384,7 +35832,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c + rdhash = AUFS_RDHASH_DEF; + err = au_nhash_alloc(&whtmp->whlist, rdhash, gfp); + if (unlikely(err)) { -+ kfree(whtmp); ++ au_kfree_rcu(whtmp); + whtmp = ERR_PTR(err); + } + @@ -35395,11 +35843,11 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c +void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp) +{ + if (whtmp->br) -+ au_br_put(whtmp->br); ++ au_lcnt_dec(&whtmp->br->br_count); + dput(whtmp->wh_dentry); + iput(whtmp->dir); + au_nhash_wh_free(&whtmp->whlist); -+ kfree(whtmp); ++ au_kfree_rcu(whtmp); +} + +/* @@ -35528,7 +35976,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c + sb = dir->i_sb; + args->dir = au_igrab(dir); + args->br = au_sbr(sb, bindex); -+ au_br_get(args->br); ++ au_lcnt_inc(&args->br->br_count); + args->wh_dentry = dget(wh_dentry); + wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, sb, /*flags*/0); + if (unlikely(wkq_err)) { @@ -35538,10 +35986,11 @@ 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 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,85 @@ ++++ linux/fs/aufs/whout.h 2018-08-12 23:43:05.463458173 +0200 +@@ -0,0 +1,86 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -35627,10 +36076,11 @@ diff -urN /usr/share/empty/fs/aufs/whout.h linux/fs/aufs/whout.h +#endif /* __AUFS_WHOUT_H__ */ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c --- /usr/share/empty/fs/aufs/wkq.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/wkq.c 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,390 @@ ++++ linux/fs/aufs/wkq.c 2018-12-27 13:19:17.711749485 +0100 +@@ -0,0 +1,392 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -35648,7 +36098,7 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c + +/* + * workqueue for asynchronous/super-io operations -+ * todo: try new dredential scheme ++ * todo: try new credential scheme + */ + +#include @@ -35802,7 +36252,7 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c + +static void au_wkq_lockdep_free(struct au_wkinfo *wkinfo) +{ -+ kfree(wkinfo->hlock); ++ au_kfree_try_rcu(wkinfo->hlock); +} + +static void au_wkq_lockdep_pre(struct au_wkinfo *wkinfo) @@ -35854,7 +36304,7 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c + else { + kobject_put(wkinfo->kobj); + module_put(THIS_MODULE); /* todo: ?? */ -+ kfree(wkinfo); ++ au_kfree_rcu(wkinfo); + } +} + @@ -35877,7 +36327,7 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c + +static void au_wkq_comp_free(struct completion *comp) +{ -+ kfree(comp); ++ au_kfree_rcu(comp); +} + +#else @@ -35904,7 +36354,8 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c + if (au_ftest_wkq(wkinfo->flags, NEST)) { + if (au_wkq_test()) { + AuWarn1("wkq from wkq, unless silly-rename on NFS," -+ " due to a dead dir by UDBA?\n"); ++ " due to a dead dir by UDBA," ++ " or async xino write?\n"); + AuDebugOn(au_ftest_wkq(wkinfo->flags, WAIT)); + } + } else @@ -36021,10 +36472,11 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c +} diff -urN /usr/share/empty/fs/aufs/wkq.h linux/fs/aufs/wkq.h --- /usr/share/empty/fs/aufs/wkq.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/wkq.h 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,93 @@ ++++ linux/fs/aufs/wkq.h 2018-10-23 12:33:35.599375796 +0200 +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -36077,11 +36529,6 @@ diff -urN /usr/share/empty/fs/aufs/wkq.h linux/fs/aufs/wkq.h +#define au_fclr_wkq(flags, name) \ + do { (flags) &= ~AuWkq_##name; } while (0) + -+#ifndef CONFIG_AUFS_HNOTIFY -+#undef AuWkq_NEST -+#define AuWkq_NEST 0 -+#endif -+ +/* wkq.c */ +int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args); +int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, @@ -36118,10 +36565,11 @@ diff -urN /usr/share/empty/fs/aufs/wkq.h linux/fs/aufs/wkq.h +#endif /* __AUFS_WKQ_H__ */ diff -urN /usr/share/empty/fs/aufs/xattr.c linux/fs/aufs/xattr.c --- /usr/share/empty/fs/aufs/xattr.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/xattr.c 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,355 @@ ++++ linux/fs/aufs/xattr.c 2018-12-27 13:19:17.711749485 +0100 +@@ -0,0 +1,356 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2014-2017 Junjiro R. Okajima ++ * Copyright (C) 2014-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -36300,10 +36748,10 @@ diff -urN /usr/share/empty/fs/aufs/xattr.c linux/fs/aufs/xattr.c + AuTraceErr(err); + } + -+ kfree(value); ++ au_kfree_try_rcu(value); + +out_free: -+ kfree(o); ++ au_kfree_try_rcu(o); +out: + if (!unlocked) + inode_unlock_shared(h_isrc); @@ -36477,10 +36925,11 @@ 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 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,1469 @@ ++++ linux/fs/aufs/xino.c 2018-12-27 13:19:17.715082917 +0100 +@@ -0,0 +1,1956 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -36498,248 +36947,265 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + +/* + * external inode number translation table and bitmap ++ * ++ * things to consider ++ * - the lifetime ++ * + au_xino object ++ * + XINO files (xino, xib, xigen) ++ * + dynamic debugfs entries (xiN) ++ * + static debugfs entries (xib, xigen) ++ * + static sysfs entry (xi_path) ++ * - several entry points to handle them. ++ * + mount(2) without xino option (default) ++ * + mount(2) with xino option ++ * + mount(2) with noxino option ++ * + umount(2) ++ * + remount with add/del branches ++ * + remount with xino/noxino options + */ + +#include +#include +#include "aufs.h" + -+static ssize_t xino_fread_wkq(vfs_readf_t func, struct file *file, void *buf, -+ size_t size, loff_t *pos); -+ -+/* todo: unnecessary to support mmap_sem since kernel-space? */ -+ssize_t xino_fread(vfs_readf_t func, struct file *file, void *kbuf, size_t size, -+ loff_t *pos) ++static aufs_bindex_t sbr_find_shared(struct super_block *sb, aufs_bindex_t btop, ++ aufs_bindex_t bbot, ++ struct super_block *h_sb) +{ -+ ssize_t err; -+ mm_segment_t oldfs; -+ union { -+ void *k; -+ char __user *u; -+ } buf; -+ int i; -+ const int prevent_endless = 10; ++ /* todo: try binary-search if the branches are many */ ++ for (; btop <= bbot; btop++) ++ if (h_sb == au_sbr_sb(sb, btop)) ++ return btop; ++ return -1; ++} + -+ i = 0; -+ buf.k = kbuf; -+ oldfs = get_fs(); -+ set_fs(KERNEL_DS); -+ do { -+ err = func(file, buf.u, size, pos); -+ if (err == -EINTR -+ && !au_wkq_test() -+ && fatal_signal_pending(current)) { -+ set_fs(oldfs); -+ err = xino_fread_wkq(func, file, kbuf, size, pos); -+ BUG_ON(err == -EINTR); -+ oldfs = get_fs(); -+ set_fs(KERNEL_DS); -+ } -+ } while (i++ < prevent_endless -+ && (err == -EAGAIN || err == -EINTR)); -+ set_fs(oldfs); ++/* ++ * find another branch who is on the same filesystem of the specified ++ * branch{@btgt}. search until @bbot. ++ */ ++static aufs_bindex_t is_sb_shared(struct super_block *sb, aufs_bindex_t btgt, ++ aufs_bindex_t bbot) ++{ ++ aufs_bindex_t bindex; ++ struct super_block *tgt_sb; + -+#if 0 /* reserved for future use */ -+ if (err > 0) -+ fsnotify_access(file->f_path.dentry); -+#endif ++ tgt_sb = au_sbr_sb(sb, btgt); ++ bindex = sbr_find_shared(sb, /*btop*/0, btgt - 1, tgt_sb); ++ if (bindex < 0) ++ bindex = sbr_find_shared(sb, btgt + 1, bbot, tgt_sb); + -+ return err; ++ return bindex; +} + -+struct xino_fread_args { -+ ssize_t *errp; -+ vfs_readf_t func; -+ struct file *file; -+ void *buf; -+ size_t size; -+ loff_t *pos; -+}; ++/* ---------------------------------------------------------------------- */ + -+static void call_xino_fread(void *args) -+{ -+ struct xino_fread_args *a = args; -+ *a->errp = xino_fread(a->func, a->file, a->buf, a->size, a->pos); -+} ++/* ++ * stop unnecessary notify events at creating xino files ++ */ + -+static ssize_t xino_fread_wkq(vfs_readf_t func, struct file *file, void *buf, -+ size_t size, loff_t *pos) ++aufs_bindex_t au_xi_root(struct super_block *sb, struct dentry *dentry) +{ -+ ssize_t err; -+ int wkq_err; -+ struct xino_fread_args args = { -+ .errp = &err, -+ .func = func, -+ .file = file, -+ .buf = buf, -+ .size = size, -+ .pos = pos -+ }; ++ aufs_bindex_t bfound, bindex, bbot; ++ struct dentry *parent; ++ struct au_branch *br; + -+ wkq_err = au_wkq_wait(call_xino_fread, &args); -+ if (unlikely(wkq_err)) -+ err = wkq_err; ++ bfound = -1; ++ parent = dentry->d_parent; /* safe d_parent access */ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_dentry(br) == parent) { ++ bfound = bindex; ++ break; ++ } ++ } + -+ return err; ++ AuDbg("bfound b%d\n", bfound); ++ return bfound; +} + -+/* ---------------------------------------------------------------------- */ -+ -+static ssize_t xino_fwrite_wkq(vfs_writef_t func, struct file *file, void *buf, -+ size_t size, loff_t *pos); ++struct au_xino_lock_dir { ++ struct au_hinode *hdir; ++ struct dentry *parent; ++ struct inode *dir; ++}; + -+static ssize_t do_xino_fwrite(vfs_writef_t func, struct file *file, void *kbuf, -+ size_t size, loff_t *pos) ++static struct dentry *au_dget_parent_lock(struct dentry *dentry, ++ unsigned int lsc) +{ -+ ssize_t err; -+ mm_segment_t oldfs; -+ union { -+ void *k; -+ const char __user *u; -+ } buf; -+ int i; -+ const int prevent_endless = 10; ++ struct dentry *parent; ++ struct inode *dir; + -+ i = 0; -+ buf.k = kbuf; -+ oldfs = get_fs(); -+ set_fs(KERNEL_DS); -+ do { -+ err = func(file, buf.u, size, pos); -+ if (err == -EINTR -+ && !au_wkq_test() -+ && fatal_signal_pending(current)) { -+ set_fs(oldfs); -+ err = xino_fwrite_wkq(func, file, kbuf, size, pos); -+ BUG_ON(err == -EINTR); -+ oldfs = get_fs(); -+ set_fs(KERNEL_DS); -+ } -+ } while (i++ < prevent_endless -+ && (err == -EAGAIN || err == -EINTR)); -+ set_fs(oldfs); ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ inode_lock_nested(dir, lsc); ++#if 0 /* it should not happen */ ++ spin_lock(&dentry->d_lock); ++ if (unlikely(dentry->d_parent != parent)) { ++ spin_unlock(&dentry->d_lock); ++ inode_unlock(dir); ++ dput(parent); ++ parent = NULL; ++ goto out; ++ } ++ spin_unlock(&dentry->d_lock); + -+#if 0 /* reserved for future use */ -+ if (err > 0) -+ fsnotify_modify(file->f_path.dentry); ++out: +#endif -+ -+ return err; ++ return parent; +} + -+struct do_xino_fwrite_args { -+ ssize_t *errp; -+ vfs_writef_t func; -+ struct file *file; -+ void *buf; -+ size_t size; -+ loff_t *pos; -+}; ++static void au_xino_lock_dir(struct super_block *sb, struct path *xipath, ++ struct au_xino_lock_dir *ldir) ++{ ++ aufs_bindex_t bindex; + -+static void call_do_xino_fwrite(void *args) ++ ldir->hdir = NULL; ++ bindex = au_xi_root(sb, xipath->dentry); ++ if (bindex >= 0) { ++ /* rw branch root */ ++ ldir->hdir = au_hi(d_inode(sb->s_root), bindex); ++ au_hn_inode_lock_nested(ldir->hdir, AuLsc_I_PARENT); ++ } else { ++ /* other */ ++ ldir->parent = au_dget_parent_lock(xipath->dentry, ++ AuLsc_I_PARENT); ++ ldir->dir = d_inode(ldir->parent); ++ } ++} ++ ++static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir) +{ -+ struct do_xino_fwrite_args *a = args; -+ *a->errp = do_xino_fwrite(a->func, a->file, a->buf, a->size, a->pos); ++ if (ldir->hdir) ++ au_hn_inode_unlock(ldir->hdir); ++ else { ++ inode_unlock(ldir->dir); ++ dput(ldir->parent); ++ } +} + -+static ssize_t xino_fwrite_wkq(vfs_writef_t func, struct file *file, void *buf, -+ size_t size, loff_t *pos) ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create and set a new xino file ++ */ ++struct file *au_xino_create(struct super_block *sb, char *fpath, int silent) +{ -+ ssize_t err; -+ int wkq_err; -+ struct do_xino_fwrite_args args = { -+ .errp = &err, -+ .func = func, -+ .file = file, -+ .buf = buf, -+ .size = size, -+ .pos = pos -+ }; ++ struct file *file; ++ struct dentry *h_parent, *d; ++ struct inode *h_dir, *inode; ++ int err; + + /* -+ * it breaks RLIMIT_FSIZE and normal user's limit, -+ * users should care about quota and real 'filesystem full.' ++ * at mount-time, and the xino file is the default path, ++ * hnotify is disabled so we have no notify events to ignore. ++ * when a user specified the xino, we cannot get au_hdir to be ignored. + */ -+ wkq_err = au_wkq_wait(call_do_xino_fwrite, &args); -+ if (unlikely(wkq_err)) -+ err = wkq_err; -+ -+ return err; -+} ++ file = vfsub_filp_open(fpath, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE ++ /* | __FMODE_NONOTIFY */, ++ 0666); ++ if (IS_ERR(file)) { ++ if (!silent) ++ pr_err("open %s(%ld)\n", fpath, PTR_ERR(file)); ++ return file; ++ } + -+ssize_t xino_fwrite(vfs_writef_t func, struct file *file, void *buf, -+ size_t size, loff_t *pos) -+{ -+ ssize_t err; ++ /* keep file count */ ++ err = 0; ++ d = file->f_path.dentry; ++ h_parent = au_dget_parent_lock(d, AuLsc_I_PARENT); ++ /* mnt_want_write() is unnecessary here */ ++ h_dir = d_inode(h_parent); ++ inode = file_inode(file); ++ /* no delegation since it is just created */ ++ if (inode->i_nlink) ++ err = vfsub_unlink(h_dir, &file->f_path, /*delegated*/NULL, ++ /*force*/0); ++ inode_unlock(h_dir); ++ dput(h_parent); ++ if (unlikely(err)) { ++ if (!silent) ++ pr_err("unlink %s(%d)\n", fpath, err); ++ goto out; ++ } + -+ if (rlimit(RLIMIT_FSIZE) == RLIM_INFINITY) { -+ lockdep_off(); -+ err = do_xino_fwrite(func, file, buf, size, pos); -+ lockdep_on(); -+ } else { -+ lockdep_off(); -+ err = xino_fwrite_wkq(func, file, buf, size, pos); -+ lockdep_on(); ++ err = -EINVAL; ++ if (unlikely(sb == d->d_sb)) { ++ if (!silent) ++ pr_err("%s must be outside\n", fpath); ++ goto out; ++ } ++ if (unlikely(au_test_fs_bad_xino(d->d_sb))) { ++ if (!silent) ++ pr_err("xino doesn't support %s(%s)\n", ++ fpath, au_sbtype(d->d_sb)); ++ goto out; + } ++ return file; /* success */ + -+ return err; ++out: ++ fput(file); ++ file = ERR_PTR(err); ++ return file; +} + -+/* ---------------------------------------------------------------------- */ -+ +/* -+ * create a new xinofile at the same place/path as @base_file. ++ * create a new xinofile at the same place/path as @base. + */ -+struct file *au_xino_create2(struct file *base_file, struct file *copy_src) ++struct file *au_xino_create2(struct super_block *sb, struct path *base, ++ struct file *copy_src) +{ + struct file *file; -+ struct dentry *base, *parent; ++ struct dentry *dentry, *parent; + struct inode *dir, *delegated; + struct qstr *name; + struct path path; -+ int err; ++ int err, do_unlock; ++ struct au_xino_lock_dir ldir; + -+ base = base_file->f_path.dentry; -+ parent = base->d_parent; /* dir inode is locked */ ++ do_unlock = 1; ++ au_xino_lock_dir(sb, base, &ldir); ++ dentry = base->dentry; ++ parent = dentry->d_parent; /* dir inode is locked */ + dir = d_inode(parent); + IMustLock(dir); + -+ file = ERR_PTR(-EINVAL); -+ name = &base->d_name; ++ name = &dentry->d_name; + path.dentry = vfsub_lookup_one_len(name->name, parent, name->len); + if (IS_ERR(path.dentry)) { + file = (void *)path.dentry; -+ pr_err("%pd lookup err %ld\n", -+ base, PTR_ERR(path.dentry)); ++ pr_err("%pd lookup err %ld\n", dentry, PTR_ERR(path.dentry)); + goto out; + } + + /* no need to mnt_want_write() since we call dentry_open() later */ -+ err = vfs_create(dir, path.dentry, S_IRUGO | S_IWUGO, NULL); ++ err = vfs_create(dir, path.dentry, 0666, NULL); + if (unlikely(err)) { + file = ERR_PTR(err); -+ pr_err("%pd create err %d\n", base, err); ++ pr_err("%pd create err %d\n", dentry, err); + goto out_dput; + } + -+ path.mnt = base_file->f_path.mnt; ++ 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", base, PTR_ERR(file)); ++ pr_err("%pd open err %ld\n", dentry, PTR_ERR(file)); + goto out_dput; + } + + delegated = NULL; + err = vfsub_unlink(dir, &file->f_path, &delegated, /*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", base, err); ++ pr_err("%pd unlink err %d\n", dentry, err); + goto out_fput; + } + @@ -36747,7 +37213,7 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + /* no one can touch copy_src xino */ + err = au_copy_file(file, copy_src, vfsub_f_size_read(copy_src)); + if (unlikely(err)) { -+ pr_err("%pd copy err %d\n", base, err); ++ pr_err("%pd copy err %d\n", dentry, err); + goto out_fput; + } + } @@ -36759,60 +37225,161 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c +out_dput: + dput(path.dentry); +out: ++ if (do_unlock) ++ au_xino_unlock_dir(&ldir); + return file; +} + -+struct au_xino_lock_dir { -+ struct au_hinode *hdir; -+ struct dentry *parent; -+ struct inode *dir; -+}; ++struct file *au_xino_file1(struct au_xino *xi) ++{ ++ struct file *file; ++ unsigned int u, nfile; + -+static void au_xino_lock_dir(struct super_block *sb, struct file *xino, -+ struct au_xino_lock_dir *ldir) ++ file = NULL; ++ nfile = xi->xi_nfile; ++ for (u = 0; u < nfile; u++) { ++ file = xi->xi_file[u]; ++ if (file) ++ break; ++ } ++ ++ return file; ++} ++ ++static int au_xino_file_set(struct au_xino *xi, int idx, struct file *file) +{ -+ aufs_bindex_t brid, bindex; ++ int err; ++ struct file *f; ++ void *p; + -+ ldir->hdir = NULL; -+ bindex = -1; -+ brid = au_xino_brid(sb); -+ if (brid >= 0) -+ bindex = au_br_index(sb, brid); -+ if (bindex >= 0) { -+ ldir->hdir = au_hi(d_inode(sb->s_root), bindex); -+ au_hn_inode_lock_nested(ldir->hdir, AuLsc_I_PARENT); ++ if (file) ++ get_file(file); ++ ++ err = 0; ++ f = NULL; ++ if (idx < xi->xi_nfile) { ++ f = xi->xi_file[idx]; ++ if (f) ++ fput(f); + } else { -+ ldir->parent = dget_parent(xino->f_path.dentry); -+ ldir->dir = d_inode(ldir->parent); -+ inode_lock_nested(ldir->dir, AuLsc_I_PARENT); ++ p = au_kzrealloc(xi->xi_file, ++ sizeof(*xi->xi_file) * xi->xi_nfile, ++ sizeof(*xi->xi_file) * (idx + 1), ++ GFP_NOFS, /*may_shrink*/0); ++ if (p) { ++ MtxMustLock(&xi->xi_mtx); ++ xi->xi_file = p; ++ xi->xi_nfile = idx + 1; ++ } else { ++ err = -ENOMEM; ++ if (file) ++ fput(file); ++ goto out; ++ } + } ++ xi->xi_file[idx] = file; ++ ++out: ++ return err; +} + -+static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir) ++/* ++ * if @xinew->xi is not set, then create new xigen file. ++ */ ++struct file *au_xi_new(struct super_block *sb, struct au_xi_new *xinew) +{ -+ if (ldir->hdir) -+ au_hn_inode_unlock(ldir->hdir); ++ struct file *file; ++ int err; ++ ++ SiMustAnyLock(sb); ++ ++ file = au_xino_create2(sb, xinew->base, xinew->copy_src); ++ if (IS_ERR(file)) { ++ err = PTR_ERR(file); ++ pr_err("%s[%d], err %d\n", ++ xinew->xi ? "xino" : "xigen", ++ xinew->idx, err); ++ goto out; ++ } ++ ++ if (xinew->xi) ++ err = au_xino_file_set(xinew->xi, xinew->idx, file); + else { -+ inode_unlock(ldir->dir); -+ dput(ldir->parent); ++ BUG(); ++ /* todo: make xigen file an array */ ++ /* err = au_xigen_file_set(sb, xinew->idx, file); */ + } ++ fput(file); ++ if (unlikely(err)) ++ file = ERR_PTR(err); ++ ++out: ++ return file; +} + +/* ---------------------------------------------------------------------- */ + -+/* trucate xino files asynchronously */ -+ -+int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex) ++/* ++ * truncate xino files ++ */ ++static int au_xino_do_trunc(struct super_block *sb, aufs_bindex_t bindex, ++ int idx, struct kstatfs *st) +{ + int err; -+ unsigned long jiffy; + blkcnt_t blocks; -+ aufs_bindex_t bi, bbot; ++ struct file *file, *new_xino; ++ struct au_xi_new xinew = { ++ .idx = idx ++ }; ++ ++ err = 0; ++ xinew.xi = au_sbr(sb, bindex)->br_xino; ++ file = au_xino_file(xinew.xi, idx); ++ if (!file) ++ goto out; ++ ++ xinew.base = &file->f_path; ++ err = vfs_statfs(xinew.base, st); ++ if (unlikely(err)) { ++ AuErr1("statfs err %d, ignored\n", err); ++ err = 0; ++ goto out; ++ } ++ ++ blocks = file_inode(file)->i_blocks; ++ pr_info("begin truncating xino(b%d-%d), ib%llu, %llu/%llu free blks\n", ++ bindex, idx, (u64)blocks, st->f_bfree, st->f_blocks); ++ ++ xinew.copy_src = file; ++ new_xino = au_xi_new(sb, &xinew); ++ if (IS_ERR(new_xino)) { ++ err = PTR_ERR(new_xino); ++ pr_err("xino(b%d-%d), err %d, ignored\n", bindex, idx, err); ++ goto out; ++ } ++ ++ err = vfs_statfs(&new_xino->f_path, st); ++ if (!err) ++ pr_info("end truncating xino(b%d-%d), ib%llu, %llu/%llu free blks\n", ++ bindex, idx, (u64)file_inode(new_xino)->i_blocks, ++ st->f_bfree, st->f_blocks); ++ else { ++ AuErr1("statfs err %d, ignored\n", err); ++ err = 0; ++ } ++ ++out: ++ return err; ++} ++ ++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex, int idx_begin) ++{ ++ int err, i; ++ unsigned long jiffy; ++ aufs_bindex_t bbot; + struct kstatfs *st; + struct au_branch *br; -+ struct file *new_xino, *file; -+ struct super_block *h_sb; -+ struct au_xino_lock_dir ldir; ++ struct au_xino *xi; + + err = -ENOMEM; + st = kmalloc(sizeof(*st), GFP_NOFS); @@ -36823,57 +37390,18 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + bbot = au_sbbot(sb); + if (unlikely(bindex < 0 || bbot < bindex)) + goto out_st; -+ br = au_sbr(sb, bindex); -+ file = br->br_xino.xi_file; -+ if (!file) -+ goto out_st; + -+ err = vfs_statfs(&file->f_path, st); -+ if (unlikely(err)) -+ AuErr1("statfs err %d, ignored\n", err); -+ jiffy = jiffies; -+ blocks = file_inode(file)->i_blocks; -+ pr_info("begin truncating xino(b%d), ib%llu, %llu/%llu free blks\n", -+ bindex, (u64)blocks, st->f_bfree, st->f_blocks); -+ -+ au_xino_lock_dir(sb, file, &ldir); -+ /* mnt_want_write() is unnecessary here */ -+ new_xino = au_xino_create2(file, file); -+ au_xino_unlock_dir(&ldir); -+ err = PTR_ERR(new_xino); -+ if (IS_ERR(new_xino)) { -+ pr_err("err %d, ignored\n", err); -+ goto out_st; -+ } + err = 0; -+ fput(file); -+ br->br_xino.xi_file = new_xino; -+ -+ h_sb = au_br_sb(br); -+ for (bi = 0; bi <= bbot; bi++) { -+ if (unlikely(bi == bindex)) -+ continue; -+ br = au_sbr(sb, bi); -+ if (au_br_sb(br) != h_sb) -+ continue; -+ -+ fput(br->br_xino.xi_file); -+ br->br_xino.xi_file = new_xino; -+ get_file(new_xino); -+ } -+ -+ err = vfs_statfs(&new_xino->f_path, st); -+ if (!err) { -+ pr_info("end truncating xino(b%d), ib%llu, %llu/%llu free blks\n", -+ bindex, (u64)file_inode(new_xino)->i_blocks, -+ st->f_bfree, st->f_blocks); -+ if (file_inode(new_xino)->i_blocks < blocks) -+ au_sbi(sb)->si_xino_jiffy = jiffy; -+ } else -+ AuErr1("statfs err %d, ignored\n", err); ++ jiffy = jiffies; ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ for (i = idx_begin; !err && i < xi->xi_nfile; i++) ++ err = au_xino_do_trunc(sb, bindex, i, st); ++ if (!err) ++ au_sbi(sb)->si_xino_jiffy = jiffy; + +out_st: -+ kfree(st); ++ au_kfree_rcu(st); +out: + return err; +} @@ -36881,6 +37409,7 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c +struct xino_do_trunc_args { + struct super_block *sb; + struct au_branch *br; ++ int idx; +}; + +static void xino_do_trunc(void *_args) @@ -36889,61 +37418,79 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + struct super_block *sb; + struct au_branch *br; + struct inode *dir; -+ int err; ++ int err, idx; + aufs_bindex_t bindex; + + err = 0; + sb = args->sb; + dir = d_inode(sb->s_root); + br = args->br; ++ idx = args->idx; + + si_noflush_write_lock(sb); + ii_read_lock_parent(dir); + bindex = au_br_index(sb, br->br_id); -+ err = au_xino_trunc(sb, bindex); ++ err = au_xino_trunc(sb, bindex, idx); + ii_read_unlock(dir); + if (unlikely(err)) + pr_warn("err b%d, (%d)\n", bindex, err); -+ atomic_dec(&br->br_xino_running); -+ au_br_put(br); ++ atomic_dec(&br->br_xino->xi_truncating); ++ au_lcnt_dec(&br->br_count); + si_write_unlock(sb); + au_nwt_done(&au_sbi(sb)->si_nowait); -+ kfree(args); ++ au_kfree_rcu(args); +} + ++/* ++ * returns the index in the xi_file array whose corresponding file is necessary ++ * to truncate, or -1 which means no need to truncate. ++ */ +static int xino_trunc_test(struct super_block *sb, struct au_branch *br) +{ + int err; ++ unsigned int u; + struct kstatfs st; + struct au_sbinfo *sbinfo; ++ struct au_xino *xi; ++ struct file *file; + + /* todo: si_xino_expire and the ratio should be customizable */ + sbinfo = au_sbi(sb); + if (time_before(jiffies, + sbinfo->si_xino_jiffy + sbinfo->si_xino_expire)) -+ return 0; ++ return -1; + + /* truncation border */ -+ err = vfs_statfs(&br->br_xino.xi_file->f_path, &st); -+ if (unlikely(err)) { -+ AuErr1("statfs err %d, ignored\n", err); -+ return 0; ++ xi = br->br_xino; ++ for (u = 0; u < xi->xi_nfile; u++) { ++ file = au_xino_file(xi, u); ++ if (!file) ++ continue; ++ ++ err = vfs_statfs(&file->f_path, &st); ++ if (unlikely(err)) { ++ AuErr1("statfs err %d, ignored\n", err); ++ return -1; ++ } ++ if (div64_u64(st.f_bfree * 100, st.f_blocks) ++ >= AUFS_XINO_DEF_TRUNC) ++ return u; + } -+ if (div64_u64(st.f_bfree * 100, st.f_blocks) >= AUFS_XINO_DEF_TRUNC) -+ return 0; + -+ return 1; ++ return -1; +} + +static void xino_try_trunc(struct super_block *sb, struct au_branch *br) +{ ++ int idx; + struct xino_do_trunc_args *args; + int wkq_err; + -+ if (!xino_trunc_test(sb, br)) ++ idx = xino_trunc_test(sb, br); ++ if (idx < 0) + return; + -+ if (atomic_inc_return(&br->br_xino_running) > 1) ++ if (atomic_inc_return(&br->br_xino->xi_truncating) > 1) + goto out; + + /* lock and kfree() will be called in trunc_xino() */ @@ -36953,36 +37500,236 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + goto out; + } + -+ au_br_get(br); ++ au_lcnt_inc(&br->br_count); + args->sb = sb; + args->br = br; ++ args->idx = idx; + wkq_err = au_wkq_nowait(xino_do_trunc, args, sb, /*flags*/0); + if (!wkq_err) + return; /* success */ + + pr_err("wkq %d\n", wkq_err); -+ au_br_put(br); -+ kfree(args); ++ au_lcnt_dec(&br->br_count); ++ au_kfree_rcu(args); + +out: -+ atomic_dec(&br->br_xino_running); ++ atomic_dec(&br->br_xino->xi_truncating); +} + +/* ---------------------------------------------------------------------- */ + ++struct au_xi_calc { ++ int idx; ++ loff_t pos; ++}; ++ ++static void au_xi_calc(struct super_block *sb, ino_t h_ino, ++ struct au_xi_calc *calc) ++{ ++ loff_t maxent; ++ ++ maxent = au_xi_maxent(sb); ++ calc->idx = div64_u64_rem(h_ino, maxent, &calc->pos); ++ calc->pos *= sizeof(ino_t); ++} ++ ++static int au_xino_do_new_async(struct super_block *sb, struct au_branch *br, ++ struct au_xi_calc *calc) ++{ ++ int err; ++ struct file *file; ++ struct au_xino *xi = br->br_xino; ++ struct au_xi_new xinew = { ++ .xi = xi ++ }; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (!xi) ++ goto out; ++ ++ mutex_lock(&xi->xi_mtx); ++ file = au_xino_file(xi, calc->idx); ++ if (file) ++ goto out_mtx; ++ ++ file = au_xino_file(xi, /*idx*/-1); ++ AuDebugOn(!file); ++ xinew.idx = calc->idx; ++ xinew.base = &file->f_path; ++ /* xinew.copy_src = NULL; */ ++ file = au_xi_new(sb, &xinew); ++ if (IS_ERR(file)) ++ err = PTR_ERR(file); ++ ++out_mtx: ++ mutex_unlock(&xi->xi_mtx); ++out: ++ return err; ++} ++ ++struct au_xino_do_new_async_args { ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_xi_calc calc; ++ ino_t ino; ++}; ++ ++struct au_xi_writing { ++ struct hlist_bl_node node; ++ ino_t h_ino, ino; ++}; ++ +static int au_xino_do_write(vfs_writef_t write, struct file *file, -+ ino_t h_ino, ino_t ino) ++ struct au_xi_calc *calc, ino_t ino); ++ ++static void au_xino_call_do_new_async(void *args) +{ -+ loff_t pos; ++ struct au_xino_do_new_async_args *a = args; ++ struct au_branch *br; ++ struct super_block *sb; ++ struct au_sbinfo *sbi; ++ struct inode *root; ++ struct file *file; ++ struct au_xi_writing *del, *p; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ int err; ++ ++ br = a->br; ++ sb = a->sb; ++ sbi = au_sbi(sb); ++ si_noflush_read_lock(sb); ++ root = d_inode(sb->s_root); ++ ii_read_lock_child(root); ++ err = au_xino_do_new_async(sb, br, &a->calc); ++ if (unlikely(err)) { ++ AuIOErr("err %d\n", err); ++ goto out; ++ } ++ ++ file = au_xino_file(br->br_xino, a->calc.idx); ++ AuDebugOn(!file); ++ err = au_xino_do_write(sbi->si_xwrite, file, &a->calc, a->ino); ++ if (unlikely(err)) { ++ AuIOErr("err %d\n", err); ++ goto out; ++ } ++ ++ del = NULL; ++ hbl = &br->br_xino->xi_writing; ++ hlist_bl_lock(hbl); ++ au_hbl_for_each(pos, hbl) { ++ p = container_of(pos, struct au_xi_writing, node); ++ if (p->ino == a->ino) { ++ del = p; ++ hlist_bl_del(&p->node); ++ break; ++ } ++ } ++ hlist_bl_unlock(hbl); ++ au_kfree_rcu(del); ++ ++out: ++ au_lcnt_dec(&br->br_count); ++ ii_read_unlock(root); ++ si_read_unlock(sb); ++ au_nwt_done(&sbi->si_nowait); ++ au_kfree_rcu(a); ++} ++ ++/* ++ * create a new xino file asynchronously ++ */ ++static int au_xino_new_async(struct super_block *sb, struct au_branch *br, ++ struct au_xi_calc *calc, ino_t ino) ++{ ++ int err; ++ struct au_xino_do_new_async_args *arg; ++ ++ err = -ENOMEM; ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (unlikely(!arg)) ++ goto out; ++ ++ arg->sb = sb; ++ arg->br = br; ++ arg->calc = *calc; ++ arg->ino = ino; ++ au_lcnt_inc(&br->br_count); ++ err = au_wkq_nowait(au_xino_call_do_new_async, arg, sb, AuWkq_NEST); ++ if (unlikely(err)) { ++ pr_err("wkq %d\n", err); ++ au_lcnt_dec(&br->br_count); ++ au_kfree_rcu(arg); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * read @ino from xinofile for the specified branch{@sb, @bindex} ++ * at the position of @h_ino. ++ */ ++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t *ino) ++{ ++ int err; + ssize_t sz; ++ struct au_xi_calc calc; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ struct au_xino *xi; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_xi_writing *p; ++ ++ *ino = 0; ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return 0; /* no xino */ ++ ++ err = 0; ++ au_xi_calc(sb, h_ino, &calc); ++ xi = au_sbr(sb, bindex)->br_xino; ++ file = au_xino_file(xi, calc.idx); ++ if (!file) { ++ hbl = &xi->xi_writing; ++ hlist_bl_lock(hbl); ++ au_hbl_for_each(pos, hbl) { ++ p = container_of(pos, struct au_xi_writing, node); ++ if (p->h_ino == h_ino) { ++ AuDbg("hi%llu, i%llu, found\n", ++ (u64)p->h_ino, (u64)p->ino); ++ *ino = p->ino; ++ break; ++ } ++ } ++ hlist_bl_unlock(hbl); ++ return 0; ++ } else if (vfsub_f_size_read(file) < calc.pos + sizeof(*ino)) ++ return 0; /* no xino */ + -+ pos = h_ino; -+ if (unlikely(au_loff_max / sizeof(ino) - 1 < pos)) { -+ AuIOErr1("too large hi%lu\n", (unsigned long)h_ino); -+ return -EFBIG; ++ sbinfo = au_sbi(sb); ++ sz = xino_fread(sbinfo->si_xread, file, ino, sizeof(*ino), &calc.pos); ++ if (sz == sizeof(*ino)) ++ return 0; /* success */ ++ ++ err = sz; ++ if (unlikely(sz >= 0)) { ++ err = -EIO; ++ AuIOErr("xino read error (%zd)\n", sz); + } -+ pos *= sizeof(ino); -+ sz = xino_fwrite(write, file, &ino, sizeof(ino), &pos); ++ return err; ++} ++ ++static int au_xino_do_write(vfs_writef_t write, struct file *file, ++ struct au_xi_calc *calc, ino_t ino) ++{ ++ ssize_t sz; ++ ++ sz = xino_fwrite(write, file, &ino, sizeof(ino), &calc->pos); + if (sz == sizeof(ino)) + return 0; /* success */ + @@ -37002,34 +37749,234 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c +{ + int err; + unsigned int mnt_flags; ++ struct au_xi_calc calc; ++ struct file *file; + struct au_branch *br; ++ struct au_xino *xi; ++ struct au_xi_writing *p; + -+ BUILD_BUG_ON(sizeof(long long) != sizeof(au_loff_max) -+ || ((loff_t)-1) > 0); + SiMustAnyLock(sb); + + mnt_flags = au_mntflags(sb); + if (!au_opt_test(mnt_flags, XINO)) + return 0; + ++ au_xi_calc(sb, h_ino, &calc); + br = au_sbr(sb, bindex); -+ err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file, -+ h_ino, ino); ++ xi = br->br_xino; ++ file = au_xino_file(xi, calc.idx); ++ if (!file) { ++ /* store the inum pair into the list */ ++ p = kmalloc(sizeof(*p), GFP_NOFS | __GFP_NOFAIL); ++ p->h_ino = h_ino; ++ p->ino = ino; ++ au_hbl_add(&p->node, &xi->xi_writing); ++ ++ /* create and write a new xino file asynchronously */ ++ err = au_xino_new_async(sb, br, &calc, ino); ++ if (!err) ++ return 0; /* success */ ++ goto out; ++ } ++ ++ err = au_xino_do_write(au_sbi(sb)->si_xwrite, file, &calc, ino); + if (!err) { ++ br = au_sbr(sb, bindex); + if (au_opt_test(mnt_flags, TRUNC_XINO) + && au_test_fs_trunc_xino(au_br_sb(br))) + xino_try_trunc(sb, br); + return 0; /* success */ + } + ++out: + AuIOErr("write failed (%d)\n", err); + return -EIO; +} + -+/* ---------------------------------------------------------------------- */ ++static ssize_t xino_fread_wkq(vfs_readf_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos); ++ ++/* todo: unnecessary to support mmap_sem since kernel-space? */ ++ssize_t xino_fread(vfs_readf_t func, struct file *file, void *kbuf, size_t size, ++ loff_t *pos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ union { ++ void *k; ++ char __user *u; ++ } buf; ++ int i; ++ const int prevent_endless = 10; ++ ++ i = 0; ++ buf.k = kbuf; ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ do { ++ err = func(file, buf.u, size, pos); ++ if (err == -EINTR ++ && !au_wkq_test() ++ && fatal_signal_pending(current)) { ++ set_fs(oldfs); ++ err = xino_fread_wkq(func, file, kbuf, size, pos); ++ BUG_ON(err == -EINTR); ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ } ++ } while (i++ < prevent_endless ++ && (err == -EAGAIN || err == -EINTR)); ++ set_fs(oldfs); ++ ++#if 0 /* reserved for future use */ ++ if (err > 0) ++ fsnotify_access(file->f_path.dentry); ++#endif ++ ++ return err; ++} ++ ++struct xino_fread_args { ++ ssize_t *errp; ++ vfs_readf_t func; ++ struct file *file; ++ void *buf; ++ size_t size; ++ loff_t *pos; ++}; ++ ++static void call_xino_fread(void *args) ++{ ++ struct xino_fread_args *a = args; ++ *a->errp = xino_fread(a->func, a->file, a->buf, a->size, a->pos); ++} ++ ++static ssize_t xino_fread_wkq(vfs_readf_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ int wkq_err; ++ struct xino_fread_args args = { ++ .errp = &err, ++ .func = func, ++ .file = file, ++ .buf = buf, ++ .size = size, ++ .pos = pos ++ }; ++ ++ wkq_err = au_wkq_wait(call_xino_fread, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; + -+/* aufs inode number bitmap */ ++ return err; ++} ++ ++static ssize_t xino_fwrite_wkq(vfs_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos); ++ ++static ssize_t do_xino_fwrite(vfs_writef_t func, struct file *file, void *kbuf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ union { ++ void *k; ++ const char __user *u; ++ } buf; ++ int i; ++ const int prevent_endless = 10; ++ ++ i = 0; ++ buf.k = kbuf; ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ do { ++ err = func(file, buf.u, size, pos); ++ if (err == -EINTR ++ && !au_wkq_test() ++ && fatal_signal_pending(current)) { ++ set_fs(oldfs); ++ err = xino_fwrite_wkq(func, file, kbuf, size, pos); ++ BUG_ON(err == -EINTR); ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ } ++ } while (i++ < prevent_endless ++ && (err == -EAGAIN || err == -EINTR)); ++ set_fs(oldfs); ++ ++#if 0 /* reserved for future use */ ++ if (err > 0) ++ fsnotify_modify(file->f_path.dentry); ++#endif ++ ++ return err; ++} ++ ++struct do_xino_fwrite_args { ++ ssize_t *errp; ++ vfs_writef_t func; ++ struct file *file; ++ void *buf; ++ size_t size; ++ loff_t *pos; ++}; ++ ++static void call_do_xino_fwrite(void *args) ++{ ++ struct do_xino_fwrite_args *a = args; ++ *a->errp = do_xino_fwrite(a->func, a->file, a->buf, a->size, a->pos); ++} ++ ++static ssize_t xino_fwrite_wkq(vfs_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ int wkq_err; ++ struct do_xino_fwrite_args args = { ++ .errp = &err, ++ .func = func, ++ .file = file, ++ .buf = buf, ++ .size = size, ++ .pos = pos ++ }; ++ ++ /* ++ * it breaks RLIMIT_FSIZE and normal user's limit, ++ * users should care about quota and real 'filesystem full.' ++ */ ++ wkq_err = au_wkq_wait(call_do_xino_fwrite, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ ++ssize_t xino_fwrite(vfs_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ ++ if (rlimit(RLIMIT_FSIZE) == RLIM_INFINITY) { ++ lockdep_off(); ++ err = do_xino_fwrite(func, file, buf, size, pos); ++ lockdep_on(); ++ } else { ++ lockdep_off(); ++ err = xino_fwrite_wkq(func, file, buf, size, pos); ++ lockdep_on(); ++ } ++ ++ return err; ++} + ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * inode number bitmap ++ */ +static const int page_bits = (int)PAGE_SIZE * BITS_PER_BYTE; +static ino_t xib_calc_ino(unsigned long pindex, int bit) +{ @@ -37094,8 +38041,6 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + return err; +} + -+/* ---------------------------------------------------------------------- */ -+ +static void au_xib_clear_bit(struct inode *inode) +{ + int err, bit; @@ -37118,310 +38063,11 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + mutex_unlock(&sbinfo->si_xib_mtx); +} + -+/* for s_op->delete_inode() */ -+void au_xino_delete_inode(struct inode *inode, const int unlinked) -+{ -+ int err; -+ unsigned int mnt_flags; -+ aufs_bindex_t bindex, bbot, bi; -+ unsigned char try_trunc; -+ struct au_iinfo *iinfo; -+ struct super_block *sb; -+ struct au_hinode *hi; -+ struct inode *h_inode; -+ struct au_branch *br; -+ vfs_writef_t xwrite; -+ -+ AuDebugOn(au_is_bad_inode(inode)); -+ -+ sb = inode->i_sb; -+ mnt_flags = au_mntflags(sb); -+ if (!au_opt_test(mnt_flags, XINO) -+ || inode->i_ino == AUFS_ROOT_INO) -+ return; -+ -+ if (unlinked) { -+ au_xigen_inc(inode); -+ au_xib_clear_bit(inode); -+ } -+ -+ iinfo = au_ii(inode); -+ bindex = iinfo->ii_btop; -+ if (bindex < 0) -+ return; -+ -+ xwrite = au_sbi(sb)->si_xwrite; -+ try_trunc = !!au_opt_test(mnt_flags, TRUNC_XINO); -+ hi = au_hinode(iinfo, bindex); -+ bbot = iinfo->ii_bbot; -+ for (; bindex <= bbot; bindex++, hi++) { -+ h_inode = hi->hi_inode; -+ if (!h_inode -+ || (!unlinked && h_inode->i_nlink)) -+ continue; -+ -+ /* inode may not be revalidated */ -+ bi = au_br_index(sb, hi->hi_id); -+ if (bi < 0) -+ continue; -+ -+ br = au_sbr(sb, bi); -+ err = au_xino_do_write(xwrite, br->br_xino.xi_file, -+ h_inode->i_ino, /*ino*/0); -+ if (!err && try_trunc -+ && au_test_fs_trunc_xino(au_br_sb(br))) -+ xino_try_trunc(sb, br); -+ } -+} -+ -+/* get an unused inode number from bitmap */ -+ino_t au_xino_new_ino(struct super_block *sb) -+{ -+ ino_t ino; -+ unsigned long *p, pindex, ul, pend; -+ struct au_sbinfo *sbinfo; -+ struct file *file; -+ int free_bit, err; -+ -+ if (!au_opt_test(au_mntflags(sb), XINO)) -+ return iunique(sb, AUFS_FIRST_INO); -+ -+ sbinfo = au_sbi(sb); -+ mutex_lock(&sbinfo->si_xib_mtx); -+ p = sbinfo->si_xib_buf; -+ free_bit = sbinfo->si_xib_next_bit; -+ if (free_bit < page_bits && !test_bit(free_bit, p)) -+ goto out; /* success */ -+ free_bit = find_first_zero_bit(p, page_bits); -+ if (free_bit < page_bits) -+ goto out; /* success */ -+ -+ pindex = sbinfo->si_xib_last_pindex; -+ for (ul = pindex - 1; ul < ULONG_MAX; ul--) { -+ err = xib_pindex(sb, ul); -+ if (unlikely(err)) -+ goto out_err; -+ free_bit = find_first_zero_bit(p, page_bits); -+ if (free_bit < page_bits) -+ goto out; /* success */ -+ } -+ -+ file = sbinfo->si_xib; -+ pend = vfsub_f_size_read(file) / PAGE_SIZE; -+ for (ul = pindex + 1; ul <= pend; ul++) { -+ err = xib_pindex(sb, ul); -+ if (unlikely(err)) -+ goto out_err; -+ free_bit = find_first_zero_bit(p, page_bits); -+ if (free_bit < page_bits) -+ goto out; /* success */ -+ } -+ BUG(); -+ -+out: -+ set_bit(free_bit, p); -+ sbinfo->si_xib_next_bit = free_bit + 1; -+ pindex = sbinfo->si_xib_last_pindex; -+ mutex_unlock(&sbinfo->si_xib_mtx); -+ ino = xib_calc_ino(pindex, free_bit); -+ AuDbg("i%lu\n", (unsigned long)ino); -+ return ino; -+out_err: -+ mutex_unlock(&sbinfo->si_xib_mtx); -+ AuDbg("i0\n"); -+ return 0; -+} -+ -+/* -+ * read @ino from xinofile for the specified branch{@sb, @bindex} -+ * at the position of @h_ino. -+ * if @ino does not exist and @do_new is true, get new one. -+ */ -+int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, -+ ino_t *ino) -+{ -+ int err; -+ ssize_t sz; -+ loff_t pos; -+ struct file *file; -+ struct au_sbinfo *sbinfo; -+ -+ *ino = 0; -+ if (!au_opt_test(au_mntflags(sb), XINO)) -+ return 0; /* no xino */ -+ -+ err = 0; -+ sbinfo = au_sbi(sb); -+ pos = h_ino; -+ if (unlikely(au_loff_max / sizeof(*ino) - 1 < pos)) { -+ AuIOErr1("too large hi%lu\n", (unsigned long)h_ino); -+ return -EFBIG; -+ } -+ pos *= sizeof(*ino); -+ -+ file = au_sbr(sb, bindex)->br_xino.xi_file; -+ if (vfsub_f_size_read(file) < pos + sizeof(*ino)) -+ return 0; /* no ino */ -+ -+ sz = xino_fread(sbinfo->si_xread, file, ino, sizeof(*ino), &pos); -+ if (sz == sizeof(*ino)) -+ return 0; /* success */ -+ -+ err = sz; -+ if (unlikely(sz >= 0)) { -+ err = -EIO; -+ AuIOErr("xino read error (%zd)\n", sz); -+ } -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* create and set a new xino file */ -+ -+struct file *au_xino_create(struct super_block *sb, char *fname, int silent) -+{ -+ struct file *file; -+ struct dentry *h_parent, *d; -+ struct inode *h_dir, *inode; -+ int err; -+ -+ /* -+ * at mount-time, and the xino file is the default path, -+ * hnotify is disabled so we have no notify events to ignore. -+ * when a user specified the xino, we cannot get au_hdir to be ignored. -+ */ -+ file = vfsub_filp_open(fname, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE -+ /* | __FMODE_NONOTIFY */, -+ S_IRUGO | S_IWUGO); -+ if (IS_ERR(file)) { -+ if (!silent) -+ pr_err("open %s(%ld)\n", fname, PTR_ERR(file)); -+ return file; -+ } -+ -+ /* keep file count */ -+ err = 0; -+ inode = file_inode(file); -+ h_parent = dget_parent(file->f_path.dentry); -+ h_dir = d_inode(h_parent); -+ inode_lock_nested(h_dir, AuLsc_I_PARENT); -+ /* mnt_want_write() is unnecessary here */ -+ /* no delegation since it is just created */ -+ if (inode->i_nlink) -+ err = vfsub_unlink(h_dir, &file->f_path, /*delegated*/NULL, -+ /*force*/0); -+ inode_unlock(h_dir); -+ dput(h_parent); -+ if (unlikely(err)) { -+ if (!silent) -+ pr_err("unlink %s(%d)\n", fname, err); -+ goto out; -+ } -+ -+ err = -EINVAL; -+ d = file->f_path.dentry; -+ if (unlikely(sb == d->d_sb)) { -+ if (!silent) -+ pr_err("%s must be outside\n", fname); -+ goto out; -+ } -+ if (unlikely(au_test_fs_bad_xino(d->d_sb))) { -+ if (!silent) -+ pr_err("xino doesn't support %s(%s)\n", -+ fname, au_sbtype(d->d_sb)); -+ goto out; -+ } -+ return file; /* success */ -+ -+out: -+ fput(file); -+ file = ERR_PTR(err); -+ return file; -+} -+ -+/* -+ * find another branch who is on the same filesystem of the specified -+ * branch{@btgt}. search until @bbot. -+ */ -+static int is_sb_shared(struct super_block *sb, aufs_bindex_t btgt, -+ aufs_bindex_t bbot) -+{ -+ aufs_bindex_t bindex; -+ struct super_block *tgt_sb = au_sbr_sb(sb, btgt); -+ -+ for (bindex = 0; bindex < btgt; bindex++) -+ if (unlikely(tgt_sb == au_sbr_sb(sb, bindex))) -+ return bindex; -+ for (bindex++; bindex <= bbot; bindex++) -+ if (unlikely(tgt_sb == au_sbr_sb(sb, bindex))) -+ return bindex; -+ return -1; -+} -+ +/* ---------------------------------------------------------------------- */ + +/* -+ * initialize the xinofile for the specified branch @br -+ * at the place/path where @base_file indicates. -+ * test whether another branch is on the same filesystem or not, -+ * if @do_test is true. ++ * truncate a xino bitmap file + */ -+int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t h_ino, -+ struct file *base_file, int do_test) -+{ -+ int err; -+ ino_t ino; -+ aufs_bindex_t bbot, bindex; -+ struct au_branch *shared_br, *b; -+ struct file *file; -+ struct super_block *tgt_sb; -+ -+ shared_br = NULL; -+ bbot = au_sbbot(sb); -+ if (do_test) { -+ tgt_sb = au_br_sb(br); -+ for (bindex = 0; bindex <= bbot; bindex++) { -+ b = au_sbr(sb, bindex); -+ if (tgt_sb == au_br_sb(b)) { -+ shared_br = b; -+ break; -+ } -+ } -+ } -+ -+ if (!shared_br || !shared_br->br_xino.xi_file) { -+ struct au_xino_lock_dir ldir; -+ -+ au_xino_lock_dir(sb, base_file, &ldir); -+ /* mnt_want_write() is unnecessary here */ -+ file = au_xino_create2(base_file, NULL); -+ au_xino_unlock_dir(&ldir); -+ err = PTR_ERR(file); -+ if (IS_ERR(file)) -+ goto out; -+ br->br_xino.xi_file = file; -+ } else { -+ br->br_xino.xi_file = shared_br->br_xino.xi_file; -+ get_file(br->br_xino.xi_file); -+ } -+ -+ ino = AUFS_ROOT_INO; -+ err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file, -+ h_ino, ino); -+ if (unlikely(err)) { -+ fput(br->br_xino.xi_file); -+ br->br_xino.xi_file = NULL; -+ } -+ -+out: -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* trucate a xino bitmap file */ + +/* todo: slow */ +static int do_xib_restore(struct super_block *sb, struct file *file, void *page) @@ -37469,9 +38115,13 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + +static int xib_restore(struct super_block *sb) +{ -+ int err; ++ int err, i; ++ unsigned int nfile; + aufs_bindex_t bindex, bbot; + void *page; ++ struct au_branch *br; ++ struct au_xino *xi; ++ struct file *file; + + err = -ENOMEM; + page = (void *)__get_free_page(GFP_NOFS); @@ -37481,11 +38131,17 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + err = 0; + bbot = au_sbbot(sb); + for (bindex = 0; !err && bindex <= bbot; bindex++) -+ if (!bindex || is_sb_shared(sb, bindex, bindex - 1) < 0) -+ err = do_xib_restore -+ (sb, au_sbr(sb, bindex)->br_xino.xi_file, page); -+ else -+ AuDbg("b%d\n", bindex); ++ if (!bindex || is_sb_shared(sb, bindex, bindex - 1) < 0) { ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ nfile = xi->xi_nfile; ++ for (i = 0; i < nfile; i++) { ++ file = au_xino_file(xi, i); ++ if (file) ++ err = do_xib_restore(sb, file, page); ++ } ++ } else ++ AuDbg("skip shared b%d\n", bindex); + free_page((unsigned long)page); + +out: @@ -37497,7 +38153,6 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + int err; + ssize_t sz; + loff_t pos; -+ struct au_xino_lock_dir ldir; + struct au_sbinfo *sbinfo; + unsigned long *p; + struct file *file; @@ -37513,10 +38168,7 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + if (vfsub_f_size_read(file) <= PAGE_SIZE) + goto out; + -+ au_xino_lock_dir(sb, file, &ldir); -+ /* mnt_want_write() is unnecessary here */ -+ file = au_xino_create2(sbinfo->si_xib, NULL); -+ au_xino_unlock_dir(&ldir); ++ file = au_xino_create2(sb, &sbinfo->si_xib->f_path, NULL); + err = PTR_ERR(file); + if (IS_ERR(file)) + goto out; @@ -37546,6 +38198,112 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + +/* ---------------------------------------------------------------------- */ + ++struct au_xino *au_xino_alloc(unsigned int nfile) ++{ ++ struct au_xino *xi; ++ ++ xi = kzalloc(sizeof(*xi), GFP_NOFS); ++ if (unlikely(!xi)) ++ goto out; ++ xi->xi_nfile = nfile; ++ xi->xi_file = kcalloc(nfile, sizeof(*xi->xi_file), GFP_NOFS); ++ if (unlikely(!xi->xi_file)) ++ goto out_free; ++ ++ xi->xi_nondir.total = 8; /* initial size */ ++ xi->xi_nondir.array = kcalloc(xi->xi_nondir.total, sizeof(ino_t), ++ GFP_NOFS); ++ if (unlikely(!xi->xi_nondir.array)) ++ goto out_file; ++ ++ spin_lock_init(&xi->xi_nondir.spin); ++ init_waitqueue_head(&xi->xi_nondir.wqh); ++ mutex_init(&xi->xi_mtx); ++ INIT_HLIST_BL_HEAD(&xi->xi_writing); ++ atomic_set(&xi->xi_truncating, 0); ++ kref_init(&xi->xi_kref); ++ goto out; /* success */ ++ ++out_file: ++ au_kfree_try_rcu(xi->xi_file); ++out_free: ++ au_kfree_rcu(xi); ++ xi = NULL; ++out: ++ return xi; ++} ++ ++static int au_xino_init(struct au_branch *br, int idx, struct file *file) ++{ ++ int err; ++ struct au_xino *xi; ++ ++ err = 0; ++ xi = au_xino_alloc(idx + 1); ++ if (unlikely(!xi)) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ if (file) ++ get_file(file); ++ xi->xi_file[idx] = file; ++ AuDebugOn(br->br_xino); ++ br->br_xino = xi; ++ ++out: ++ return err; ++} ++ ++static void au_xino_release(struct kref *kref) ++{ ++ struct au_xino *xi; ++ int i; ++ unsigned long ul; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *n; ++ struct au_xi_writing *p; ++ ++ xi = container_of(kref, struct au_xino, xi_kref); ++ for (i = 0; i < xi->xi_nfile; i++) ++ if (xi->xi_file[i]) ++ fput(xi->xi_file[i]); ++ for (i = xi->xi_nondir.total - 1; i >= 0; i--) ++ AuDebugOn(xi->xi_nondir.array[i]); ++ mutex_destroy(&xi->xi_mtx); ++ hbl = &xi->xi_writing; ++ ul = au_hbl_count(hbl); ++ if (unlikely(ul)) { ++ pr_warn("xi_writing %lu\n", ul); ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry_safe (p, pos, n, hbl, node) { ++ hlist_bl_del(&p->node); ++ au_kfree_rcu(p); ++ } ++ hlist_bl_unlock(hbl); ++ } ++ au_kfree_try_rcu(xi->xi_file); ++ au_kfree_try_rcu(xi->xi_nondir.array); ++ au_kfree_rcu(xi); ++} ++ ++int au_xino_put(struct au_branch *br) ++{ ++ int ret; ++ struct au_xino *xi; ++ ++ ret = 0; ++ xi = br->br_xino; ++ if (xi) { ++ br->br_xino = NULL; ++ ret = kref_put(&xi->xi_kref, au_xino_release); ++ } ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ +/* + * xino mount option handlers + */ @@ -37558,8 +38316,7 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); -+ sbinfo->si_xread = NULL; -+ sbinfo->si_xwrite = NULL; ++ /* unnecessary to clear sbinfo->si_xread and ->si_xwrite */ + if (sbinfo->si_xib) + fput(sbinfo->si_xib); + sbinfo->si_xib = NULL; @@ -37568,17 +38325,18 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + sbinfo->si_xib_buf = NULL; +} + -+static int au_xino_set_xib(struct super_block *sb, struct file *base) ++static int au_xino_set_xib(struct super_block *sb, struct path *path) +{ + int err; + loff_t pos; + struct au_sbinfo *sbinfo; + struct file *file; ++ struct super_block *xi_sb; + + SiMustWriteLock(sb); + + sbinfo = au_sbi(sb); -+ file = au_xino_create2(base, sbinfo->si_xib); ++ file = au_xino_create2(sb, path, sbinfo->si_xib); + err = PTR_ERR(file); + if (IS_ERR(file)) + goto out; @@ -37587,6 +38345,15 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + sbinfo->si_xib = file; + sbinfo->si_xread = vfs_readf(file); + sbinfo->si_xwrite = vfs_writef(file); ++ xi_sb = file_inode(file)->i_sb; ++ sbinfo->si_ximaxent = xi_sb->s_maxbytes; ++ if (unlikely(sbinfo->si_ximaxent < PAGE_SIZE)) { ++ err = -EIO; ++ pr_err("s_maxbytes(%llu) on %s is too small\n", ++ (u64)sbinfo->si_ximaxent, au_sbtype(xi_sb)); ++ goto out_unset; ++ } ++ sbinfo->si_ximaxent /= sizeof(ino_t); + + err = -ENOMEM; + if (!sbinfo->si_xib_buf) @@ -37615,9 +38382,8 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c +out_unset: + fput(sbinfo->si_xib); + sbinfo->si_xib = NULL; -+ sbinfo->si_xread = NULL; -+ sbinfo->si_xwrite = NULL; +out: ++ AuTraceErr(err); + return err; +} + @@ -37630,79 +38396,100 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + bbot = au_sbbot(sb); + for (bindex = 0; bindex <= bbot; bindex++) { + br = au_sbr(sb, bindex); -+ if (!br || !br->br_xino.xi_file) -+ continue; ++ AuDebugOn(!br); ++ au_xino_put(br); ++ } ++} ++ ++static void au_xino_set_br_shared(struct super_block *sb, struct au_branch *br, ++ aufs_bindex_t bshared) ++{ ++ struct au_branch *brshared; + -+ fput(br->br_xino.xi_file); -+ br->br_xino.xi_file = NULL; ++ brshared = au_sbr(sb, bshared); ++ AuDebugOn(!brshared->br_xino); ++ AuDebugOn(!brshared->br_xino->xi_file); ++ if (br->br_xino != brshared->br_xino) { ++ au_xino_get(brshared); ++ au_xino_put(br); ++ br->br_xino = brshared->br_xino; + } +} + -+static int au_xino_set_br(struct super_block *sb, struct file *base) ++struct au_xino_do_set_br { ++ vfs_writef_t writef; ++ struct au_branch *br; ++ ino_t h_ino; ++ aufs_bindex_t bshared; ++}; ++ ++static int au_xino_do_set_br(struct super_block *sb, struct path *path, ++ struct au_xino_do_set_br *args) +{ + int err; -+ ino_t ino; -+ aufs_bindex_t bindex, bbot, bshared; -+ struct { -+ struct file *old, *new; -+ } *fpair, *p; ++ struct au_xi_calc calc; ++ struct file *file; + struct au_branch *br; ++ struct au_xi_new xinew = { ++ .base = path ++ }; ++ ++ br = args->br; ++ xinew.xi = br->br_xino; ++ au_xi_calc(sb, args->h_ino, &calc); ++ xinew.copy_src = au_xino_file(xinew.xi, calc.idx); ++ if (args->bshared >= 0) ++ /* shared xino */ ++ au_xino_set_br_shared(sb, br, args->bshared); ++ else if (!xinew.xi) { ++ /* new xino */ ++ err = au_xino_init(br, calc.idx, xinew.copy_src); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ /* force re-creating */ ++ xinew.xi = br->br_xino; ++ xinew.idx = calc.idx; ++ mutex_lock(&xinew.xi->xi_mtx); ++ file = au_xi_new(sb, &xinew); ++ mutex_unlock(&xinew.xi->xi_mtx); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ AuDebugOn(!file); ++ ++ err = au_xino_do_write(args->writef, file, &calc, AUFS_ROOT_INO); ++ if (unlikely(err)) ++ au_xino_put(br); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_xino_set_br(struct super_block *sb, struct path *path) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_xino_do_set_br args; + struct inode *inode; -+ vfs_writef_t writef; + + SiMustWriteLock(sb); + -+ err = -ENOMEM; + bbot = au_sbbot(sb); -+ fpair = kcalloc(bbot + 1, sizeof(*fpair), GFP_NOFS); -+ if (unlikely(!fpair)) -+ goto out; -+ + inode = d_inode(sb->s_root); -+ ino = AUFS_ROOT_INO; -+ writef = au_sbi(sb)->si_xwrite; -+ for (bindex = 0, p = fpair; bindex <= bbot; bindex++, p++) { -+ bshared = is_sb_shared(sb, bindex, bindex - 1); -+ if (bshared >= 0) { -+ /* shared xino */ -+ *p = fpair[bshared]; -+ get_file(p->new); -+ } -+ -+ if (!p->new) { -+ /* new xino */ -+ br = au_sbr(sb, bindex); -+ p->old = br->br_xino.xi_file; -+ p->new = au_xino_create2(base, br->br_xino.xi_file); -+ err = PTR_ERR(p->new); -+ if (IS_ERR(p->new)) { -+ p->new = NULL; -+ goto out_pair; -+ } -+ } -+ -+ err = au_xino_do_write(writef, p->new, -+ au_h_iptr(inode, bindex)->i_ino, ino); ++ args.writef = au_sbi(sb)->si_xwrite; ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ args.h_ino = au_h_iptr(inode, bindex)->i_ino; ++ args.br = au_sbr(sb, bindex); ++ args.bshared = is_sb_shared(sb, bindex, bindex - 1); ++ err = au_xino_do_set_br(sb, path, &args); + if (unlikely(err)) -+ goto out_pair; -+ } -+ -+ for (bindex = 0, p = fpair; bindex <= bbot; bindex++, p++) { -+ br = au_sbr(sb, bindex); -+ if (br->br_xino.xi_file) -+ fput(br->br_xino.xi_file); -+ get_file(p->new); -+ br->br_xino.xi_file = p->new; ++ break; + } + -+out_pair: -+ for (bindex = 0, p = fpair; bindex <= bbot; bindex++, p++) -+ if (p->new) -+ fput(p->new); -+ else -+ break; -+ kfree(fpair); -+out: ++ AuTraceErr(err); + return err; +} + @@ -37713,32 +38500,37 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + au_xigen_clr(sb); + xino_clear_xib(sb); + xino_clear_br(sb); ++ dbgaufs_brs_del(sb, 0); + sbinfo = au_sbi(sb); + /* lvalue, do not call au_mntflags() */ + au_opt_clr(sbinfo->si_mntflags, XINO); +} + -+int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount) ++int au_xino_set(struct super_block *sb, struct au_opt_xino *xiopt, int remount) +{ + int err, skip; -+ struct dentry *parent, *cur_parent; ++ struct dentry *dentry, *parent, *cur_dentry, *cur_parent; + struct qstr *dname, *cur_name; + struct file *cur_xino; -+ struct inode *dir; + struct au_sbinfo *sbinfo; ++ struct path *path, *cur_path; + + SiMustWriteLock(sb); + + err = 0; + sbinfo = au_sbi(sb); -+ parent = dget_parent(xino->file->f_path.dentry); ++ path = &xiopt->file->f_path; ++ dentry = path->dentry; ++ parent = dget_parent(dentry); + if (remount) { + skip = 0; -+ dname = &xino->file->f_path.dentry->d_name; + cur_xino = sbinfo->si_xib; + if (cur_xino) { -+ cur_parent = dget_parent(cur_xino->f_path.dentry); -+ cur_name = &cur_xino->f_path.dentry->d_name; ++ cur_path = &cur_xino->f_path; ++ cur_dentry = cur_path->dentry; ++ cur_parent = dget_parent(cur_dentry); ++ cur_name = &cur_dentry->d_name; ++ dname = &dentry->d_name; + skip = (cur_parent == parent + && au_qstreq(dname, cur_name)); + dput(cur_parent); @@ -37748,30 +38540,26 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + } + + au_opt_set(sbinfo->si_mntflags, XINO); -+ dir = d_inode(parent); -+ inode_lock_nested(dir, AuLsc_I_PARENT); -+ /* mnt_want_write() is unnecessary here */ -+ err = au_xino_set_xib(sb, xino->file); ++ err = au_xino_set_xib(sb, path); ++ /* si_x{read,write} are set */ + if (!err) -+ err = au_xigen_set(sb, xino->file); -+ if (!err) -+ err = au_xino_set_br(sb, xino->file); -+ inode_unlock(dir); ++ err = au_xigen_set(sb, path); + if (!err) ++ err = au_xino_set_br(sb, path); ++ if (!err) { ++ dbgaufs_brs_add(sb, 0, /*topdown*/1); + goto out; /* success */ ++ } + + /* reset all */ -+ AuIOErr("failed creating xino(%d).\n", err); -+ au_xigen_clr(sb); -+ xino_clear_xib(sb); ++ AuIOErr("failed setting xino(%d).\n", err); ++ au_xino_clr(sb); + +out: + dput(parent); + return err; +} + -+/* ---------------------------------------------------------------------- */ -+ +/* + * create a xinofile at the default place/path. + */ @@ -37809,8 +38597,6 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + strcat(p, "/" AUFS_XINO_FNAME); + AuDbg("%s\n", p); + file = au_xino_create(sb, p, /*silent*/0); -+ if (!IS_ERR(file)) -+ au_xino_brid_set(sb, br->br_id); + } + free_page((unsigned long)page); + } else { @@ -37824,8 +38610,6 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + fput(file); + file = ERR_PTR(-EINVAL); + } -+ if (!IS_ERR(file)) -+ au_xino_brid_set(sb, -1); + } + +out: @@ -37834,50 +38618,165 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + +/* ---------------------------------------------------------------------- */ + -+int au_xino_path(struct seq_file *seq, struct file *file) ++/* ++ * initialize the xinofile for the specified branch @br ++ * at the place/path where @base_file indicates. ++ * test whether another branch is on the same filesystem or not, ++ * if found then share the xinofile with another branch. ++ */ ++int au_xino_init_br(struct super_block *sb, struct au_branch *br, ino_t h_ino, ++ struct path *base) +{ + int err; ++ struct au_xino_do_set_br args = { ++ .h_ino = h_ino, ++ .br = br ++ }; + -+ err = au_seq_path(seq, &file->f_path); ++ args.writef = au_sbi(sb)->si_xwrite; ++ args.bshared = sbr_find_shared(sb, /*btop*/0, au_sbbot(sb), ++ au_br_sb(br)); ++ err = au_xino_do_set_br(sb, base, &args); + if (unlikely(err)) -+ goto out; -+ -+#define Deleted "\\040(deleted)" -+ seq->count -= sizeof(Deleted) - 1; -+ AuDebugOn(memcmp(seq->buf + seq->count, Deleted, -+ sizeof(Deleted) - 1)); -+#undef Deleted ++ au_xino_put(br); + -+out: + return err; +} + +/* ---------------------------------------------------------------------- */ + -+void au_xinondir_leave(struct super_block *sb, aufs_bindex_t bindex, -+ ino_t h_ino, int idx) ++/* ++ * get an unused inode number from bitmap ++ */ ++ino_t au_xino_new_ino(struct super_block *sb) +{ -+ struct au_xino_file *xino; ++ ino_t ino; ++ unsigned long *p, pindex, ul, pend; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ int free_bit, err; + -+ AuDebugOn(!au_opt_test(au_mntflags(sb), XINO)); -+ xino = &au_sbr(sb, bindex)->br_xino; -+ AuDebugOn(idx < 0 || xino->xi_nondir.total <= idx); ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return iunique(sb, AUFS_FIRST_INO); ++ ++ sbinfo = au_sbi(sb); ++ mutex_lock(&sbinfo->si_xib_mtx); ++ p = sbinfo->si_xib_buf; ++ free_bit = sbinfo->si_xib_next_bit; ++ if (free_bit < page_bits && !test_bit(free_bit, p)) ++ goto out; /* success */ ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ ++ pindex = sbinfo->si_xib_last_pindex; ++ for (ul = pindex - 1; ul < ULONG_MAX; ul--) { ++ err = xib_pindex(sb, ul); ++ if (unlikely(err)) ++ goto out_err; ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ } ++ ++ file = sbinfo->si_xib; ++ pend = vfsub_f_size_read(file) / PAGE_SIZE; ++ for (ul = pindex + 1; ul <= pend; ul++) { ++ err = xib_pindex(sb, ul); ++ if (unlikely(err)) ++ goto out_err; ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ } ++ BUG(); ++ ++out: ++ set_bit(free_bit, p); ++ sbinfo->si_xib_next_bit = free_bit + 1; ++ pindex = sbinfo->si_xib_last_pindex; ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ ino = xib_calc_ino(pindex, free_bit); ++ AuDbg("i%lu\n", (unsigned long)ino); ++ return ino; ++out_err: ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ AuDbg("i0\n"); ++ return 0; ++} ++ ++/* for s_op->delete_inode() */ ++void au_xino_delete_inode(struct inode *inode, const int unlinked) ++{ ++ int err; ++ unsigned int mnt_flags; ++ aufs_bindex_t bindex, bbot, bi; ++ unsigned char try_trunc; ++ struct au_iinfo *iinfo; ++ struct super_block *sb; ++ struct au_hinode *hi; ++ struct inode *h_inode; ++ struct au_branch *br; ++ vfs_writef_t xwrite; ++ struct au_xi_calc calc; ++ struct file *file; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ ++ sb = inode->i_sb; ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, XINO) ++ || inode->i_ino == AUFS_ROOT_INO) ++ return; ++ ++ if (unlinked) { ++ au_xigen_inc(inode); ++ au_xib_clear_bit(inode); ++ } + -+ spin_lock(&xino->xi_nondir.spin); -+ AuDebugOn(xino->xi_nondir.array[idx] != h_ino); -+ xino->xi_nondir.array[idx] = 0; -+ spin_unlock(&xino->xi_nondir.spin); -+ wake_up_all(&xino->xi_nondir.wqh); ++ iinfo = au_ii(inode); ++ bindex = iinfo->ii_btop; ++ if (bindex < 0) ++ return; ++ ++ xwrite = au_sbi(sb)->si_xwrite; ++ try_trunc = !!au_opt_test(mnt_flags, TRUNC_XINO); ++ hi = au_hinode(iinfo, bindex); ++ bbot = iinfo->ii_bbot; ++ for (; bindex <= bbot; bindex++, hi++) { ++ h_inode = hi->hi_inode; ++ if (!h_inode ++ || (!unlinked && h_inode->i_nlink)) ++ continue; ++ ++ /* inode may not be revalidated */ ++ bi = au_br_index(sb, hi->hi_id); ++ if (bi < 0) ++ continue; ++ ++ br = au_sbr(sb, bi); ++ au_xi_calc(sb, h_inode->i_ino, &calc); ++ file = au_xino_file(br->br_xino, calc.idx); ++ if (IS_ERR_OR_NULL(file)) ++ continue; ++ ++ err = au_xino_do_write(xwrite, file, &calc, /*ino*/0); ++ if (!err && try_trunc ++ && au_test_fs_trunc_xino(au_br_sb(br))) ++ xino_try_trunc(sb, br); ++ } +} + -+static int au_xinondir_find(struct au_xino_file *xino, ino_t h_ino) ++/* ---------------------------------------------------------------------- */ ++ ++static int au_xinondir_find(struct au_xino *xi, ino_t h_ino) +{ + int found, total, i; + + found = -1; -+ total = xino->xi_nondir.total; ++ total = xi->xi_nondir.total; + for (i = 0; i < total; i++) { -+ if (xino->xi_nondir.array[i] != h_ino) ++ if (xi->xi_nondir.array[i] != h_ino) + continue; + found = i; + break; @@ -37886,7 +38785,7 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + return found; +} + -+static int au_xinondir_expand(struct au_xino_file *xino) ++static int au_xinondir_expand(struct au_xino *xi) +{ + int err, sz; + ino_t *p; @@ -37894,15 +38793,15 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + BUILD_BUG_ON(KMALLOC_MAX_SIZE > INT_MAX); + + err = -ENOMEM; -+ sz = xino->xi_nondir.total * sizeof(ino_t); ++ sz = xi->xi_nondir.total * sizeof(ino_t); + if (unlikely(sz > KMALLOC_MAX_SIZE / 2)) + goto out; -+ p = au_kzrealloc(xino->xi_nondir.array, sz, sz << 1, GFP_ATOMIC, ++ p = au_kzrealloc(xi->xi_nondir.array, sz, sz << 1, GFP_ATOMIC, + /*may_shrink*/0); + if (p) { -+ xino->xi_nondir.array = p; -+ xino->xi_nondir.total <<= 1; -+ AuDbg("xi_nondir.total %d\n", xino->xi_nondir.total); ++ xi->xi_nondir.array = p; ++ xi->xi_nondir.total <<= 1; ++ AuDbg("xi_nondir.total %d\n", xi->xi_nondir.total); + err = 0; + } + @@ -37910,50 +38809,87 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + return err; +} + ++void au_xinondir_leave(struct super_block *sb, aufs_bindex_t bindex, ++ ino_t h_ino, int idx) ++{ ++ struct au_xino *xi; ++ ++ AuDebugOn(!au_opt_test(au_mntflags(sb), XINO)); ++ xi = au_sbr(sb, bindex)->br_xino; ++ AuDebugOn(idx < 0 || xi->xi_nondir.total <= idx); ++ ++ spin_lock(&xi->xi_nondir.spin); ++ AuDebugOn(xi->xi_nondir.array[idx] != h_ino); ++ xi->xi_nondir.array[idx] = 0; ++ spin_unlock(&xi->xi_nondir.spin); ++ wake_up_all(&xi->xi_nondir.wqh); ++} ++ +int au_xinondir_enter(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, + int *idx) +{ + int err, found, empty; -+ struct au_xino_file *xino; ++ struct au_xino *xi; + + err = 0; + *idx = -1; + if (!au_opt_test(au_mntflags(sb), XINO)) + goto out; /* no xino */ + -+ xino = &au_sbr(sb, bindex)->br_xino; ++ xi = au_sbr(sb, bindex)->br_xino; + +again: -+ spin_lock(&xino->xi_nondir.spin); -+ found = au_xinondir_find(xino, h_ino); ++ spin_lock(&xi->xi_nondir.spin); ++ found = au_xinondir_find(xi, h_ino); + if (found == -1) { -+ empty = au_xinondir_find(xino, /*h_ino*/0); ++ empty = au_xinondir_find(xi, /*h_ino*/0); + if (empty == -1) { -+ empty = xino->xi_nondir.total; -+ err = au_xinondir_expand(xino); ++ empty = xi->xi_nondir.total; ++ err = au_xinondir_expand(xi); + if (unlikely(err)) + goto out_unlock; + } -+ xino->xi_nondir.array[empty] = h_ino; ++ xi->xi_nondir.array[empty] = h_ino; + *idx = empty; + } else { -+ spin_unlock(&xino->xi_nondir.spin); -+ wait_event(xino->xi_nondir.wqh, -+ xino->xi_nondir.array[found] != h_ino); ++ spin_unlock(&xi->xi_nondir.spin); ++ wait_event(xi->xi_nondir.wqh, ++ xi->xi_nondir.array[found] != h_ino); + goto again; + } + +out_unlock: -+ spin_unlock(&xino->xi_nondir.spin); ++ spin_unlock(&xi->xi_nondir.spin); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_xino_path(struct seq_file *seq, struct file *file) ++{ ++ int err; ++ ++ err = au_seq_path(seq, &file->f_path); ++ if (unlikely(err)) ++ goto out; ++ ++#define Deleted "\\040(deleted)" ++ seq->count -= sizeof(Deleted) - 1; ++ AuDebugOn(memcmp(seq->buf + seq->count, Deleted, ++ sizeof(Deleted) - 1)); ++#undef Deleted ++ +out: + return err; +} 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 2018-04-06 07:48:44.207938097 +0200 -@@ -0,0 +1,447 @@ ++++ linux/include/uapi/linux/aufs_type.h 2018-12-27 13:19:17.715082917 +0100 +@@ -0,0 +1,448 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2017 Junjiro R. Okajima ++ * Copyright (C) 2005-2018 Junjiro R. Okajima + * + * This program, aufs is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by @@ -37993,7 +38929,7 @@ diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/lin + +#include + -+#define AUFS_VERSION "4.x-rcN-20180312" ++#define AUFS_VERSION "4.x-rcN-20181217" + +/* todo? move this to linux-2.6.19/include/magic.h */ +#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') @@ -38403,10 +39339,10 @@ SPDX-License-Identifier: GPL-2.0 aufs4.x-rcN loopback patch diff --git a/drivers/block/loop.c b/drivers/block/loop.c -index 962b2d6..d17f695 100644 +index 470dd02..20dc3ec 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c -@@ -600,6 +600,15 @@ static inline void loop_update_dio(struct loop_device *lo) +@@ -625,6 +625,15 @@ static inline void loop_update_dio(struct loop_device *lo) lo->use_dio); } @@ -38422,15 +39358,15 @@ index 962b2d6..d17f695 100644 static void loop_reread_partitions(struct loop_device *lo, struct block_device *bdev) { -@@ -634,6 +643,7 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, +@@ -689,6 +698,7 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, unsigned int arg) { struct file *file, *old_file; + struct file *f, *virt_file = NULL, *old_virt_file; - struct inode *inode; int error; -@@ -650,9 +660,16 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, + error = -ENXIO; +@@ -704,12 +714,19 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, file = fget(arg); if (!file) goto out; @@ -38441,13 +39377,16 @@ index 962b2d6..d17f695 100644 + get_file(file); + } - inode = file->f_mapping->host; + error = loop_validate_file(file, bdev); + if (error) + goto out_putf; + old_file = lo->lo_backing_file; + old_virt_file = lo->lo_backing_virt_file; error = -EINVAL; -@@ -667,6 +684,7 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, +@@ -721,6 +738,7 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, blk_mq_freeze_queue(lo->lo_queue); mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask); lo->lo_backing_file = file; @@ -38455,7 +39394,7 @@ index 962b2d6..d17f695 100644 lo->old_gfp_mask = mapping_gfp_mask(file->f_mapping); mapping_set_gfp_mask(file->f_mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); -@@ -674,12 +692,16 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, +@@ -728,12 +746,16 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, blk_mq_unfreeze_queue(lo->lo_queue); fput(old_file); @@ -38472,16 +39411,16 @@ index 962b2d6..d17f695 100644 out: return error; } -@@ -873,7 +895,7 @@ static int loop_prepare_queue(struct loop_device *lo) +@@ -921,7 +943,7 @@ static int loop_prepare_queue(struct loop_device *lo) static int loop_set_fd(struct loop_device *lo, fmode_t mode, struct block_device *bdev, unsigned int arg) { -- struct file *file, *f; +- struct file *file; + struct file *file, *f, *virt_file = NULL; struct inode *inode; struct address_space *mapping; int lo_flags = 0; -@@ -887,6 +909,12 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, +@@ -935,6 +957,12 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, file = fget(arg); if (!file) goto out; @@ -38494,7 +39433,7 @@ index 962b2d6..d17f695 100644 error = -EBUSY; if (lo->lo_state != Lo_unbound) -@@ -935,6 +963,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, +@@ -967,6 +995,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, lo->lo_device = bdev; lo->lo_flags = lo_flags; lo->lo_backing_file = file; @@ -38502,7 +39441,7 @@ index 962b2d6..d17f695 100644 lo->transfer = NULL; lo->ioctl = NULL; lo->lo_sizelimit = 0; -@@ -968,6 +997,8 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, +@@ -1000,6 +1029,8 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, out_putf: fput(file); @@ -38511,7 +39450,7 @@ index 962b2d6..d17f695 100644 out: /* This is safe: open() is still holding a reference. */ module_put(THIS_MODULE); -@@ -1014,6 +1045,7 @@ loop_init_xfer(struct loop_device *lo, struct loop_func_table *xfer, +@@ -1046,6 +1077,7 @@ loop_init_xfer(struct loop_device *lo, struct loop_func_table *xfer, static int loop_clr_fd(struct loop_device *lo) { struct file *filp = lo->lo_backing_file; @@ -38519,7 +39458,7 @@ index 962b2d6..d17f695 100644 gfp_t gfp = lo->old_gfp_mask; struct block_device *bdev = lo->lo_device; -@@ -1045,6 +1077,7 @@ static int loop_clr_fd(struct loop_device *lo) +@@ -1077,6 +1109,7 @@ static int loop_clr_fd(struct loop_device *lo) spin_lock_irq(&lo->lo_lock); lo->lo_state = Lo_rundown; lo->lo_backing_file = NULL; @@ -38527,7 +39466,7 @@ index 962b2d6..d17f695 100644 spin_unlock_irq(&lo->lo_lock); loop_release_xfer(lo); -@@ -1092,6 +1125,8 @@ static int loop_clr_fd(struct loop_device *lo) +@@ -1125,6 +1158,8 @@ static int loop_clr_fd(struct loop_device *lo) * bd_mutex which is usually taken before lo_ctl_mutex. */ fput(filp); @@ -38537,7 +39476,7 @@ index 962b2d6..d17f695 100644 } diff --git a/drivers/block/loop.h b/drivers/block/loop.h -index 0f45416..101f193 100644 +index 4d42c7a..a4974ee 100644 --- a/drivers/block/loop.h +++ b/drivers/block/loop.h @@ -46,7 +46,7 @@ struct loop_device { @@ -38550,10 +39489,10 @@ index 0f45416..101f193 100644 void *key_data; diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c -index 0d4ea929..af293c2 100644 +index 5309874..1a334cf 100644 --- a/fs/aufs/f_op.c +++ b/fs/aufs/f_op.c -@@ -358,7 +358,7 @@ static ssize_t aufs_read_iter(struct kiocb *kio, struct iov_iter *iov_iter) +@@ -359,7 +359,7 @@ static ssize_t aufs_read_iter(struct kiocb *kio, struct iov_iter *iov_iter) if (IS_ERR(h_file)) goto out; @@ -38563,12 +39502,12 @@ index 0d4ea929..af293c2 100644 if (file->f_mapping != h_file->f_mapping) { file->f_mapping = h_file->f_mapping; diff --git a/fs/aufs/loop.c b/fs/aufs/loop.c -index 3b217c2..0f5ab22 100644 +index 3f3577d..3b44158 100644 --- a/fs/aufs/loop.c +++ b/fs/aufs/loop.c @@ -133,3 +133,19 @@ void au_loopback_fin(void) symbol_put(loop_backing_file); - kfree(au_warn_loopback_array); + au_kfree_try_rcu(au_warn_loopback_array); } + +/* ---------------------------------------------------------------------- */ @@ -38587,7 +39526,7 @@ index 3b217c2..0f5ab22 100644 + return f; +} diff --git a/fs/aufs/loop.h b/fs/aufs/loop.h -index 7d7bf34..ba7c188 100644 +index 05d703d..6bb23c8 100644 --- a/fs/aufs/loop.h +++ b/fs/aufs/loop.h @@ -26,7 +26,11 @@ void au_warn_loopback(struct super_block *h_sb); @@ -38612,10 +39551,10 @@ index 7d7bf34..ba7c188 100644 #endif /* __KERNEL__ */ diff --git a/fs/aufs/super.c b/fs/aufs/super.c -index eef60a6..e03a658 100644 +index 777503e..7130061 100644 --- a/fs/aufs/super.c +++ b/fs/aufs/super.c -@@ -843,7 +843,10 @@ static const struct super_operations aufs_sop = { +@@ -845,7 +845,10 @@ static const struct super_operations aufs_sop = { .statfs = aufs_statfs, .put_super = aufs_put_super, .sync_fs = aufs_sync_fs, @@ -38628,10 +39567,10 @@ index eef60a6..e03a658 100644 /* ---------------------------------------------------------------------- */ diff --git a/include/linux/fs.h b/include/linux/fs.h -index 383ab06..e899b15 100644 +index 0e44705..59fb8ae 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h -@@ -1849,6 +1849,10 @@ struct super_operations { +@@ -1931,6 +1931,10 @@ struct super_operations { struct shrink_control *); long (*free_cached_objects)(struct super_block *, struct shrink_control *);