From e8a21f5750ec96ccb306bdc60c627ba1e9f05944 Mon Sep 17 00:00:00 2001 From: Rmys Date: Sun, 22 May 2022 18:32:33 +0300 Subject: [PATCH] kernel-5.15.41 --- .../kernel/files/configs/kernel-x86_64-config | 45 +- .../files/patches/aufs5/aufs5-base.patch | 241 + .../files/patches/aufs5/aufs5-kbuild.patch | 24 + .../files/patches/aufs5/aufs5-loopback.patch | 244 + .../files/patches/aufs5/aufs5-mmap.patch | 419 + .../patches/aufs5/aufs5-standalone.patch | 251 + .../patches/aufs5/aufs5.15.36-20220509.patch | 38475 ++++++++++++++++ .../files/patches/aufs5/tmpfs-idr.patch | 221 + .../kernel/files/patches/aufs5/vfs-ino.patch | 24 + .../files/patches/linux/patch-5.15.41.xz | Bin 0 -> 1725572 bytes kernel/kernel/pspec.xml | 28 +- 11 files changed, 39943 insertions(+), 29 deletions(-) create mode 100644 kernel/kernel/files/patches/aufs5/aufs5-base.patch create mode 100644 kernel/kernel/files/patches/aufs5/aufs5-kbuild.patch create mode 100644 kernel/kernel/files/patches/aufs5/aufs5-loopback.patch create mode 100644 kernel/kernel/files/patches/aufs5/aufs5-mmap.patch create mode 100644 kernel/kernel/files/patches/aufs5/aufs5-standalone.patch create mode 100644 kernel/kernel/files/patches/aufs5/aufs5.15.36-20220509.patch create mode 100644 kernel/kernel/files/patches/aufs5/tmpfs-idr.patch create mode 100644 kernel/kernel/files/patches/aufs5/vfs-ino.patch create mode 100644 kernel/kernel/files/patches/linux/patch-5.15.41.xz diff --git a/kernel/kernel/files/configs/kernel-x86_64-config b/kernel/kernel/files/configs/kernel-x86_64-config index 12144798..3533498d 100644 --- a/kernel/kernel/files/configs/kernel-x86_64-config +++ b/kernel/kernel/files/configs/kernel-x86_64-config @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86_64 5.15.37 Kernel Configuration +# Linux/x86_64 5.15.41 Kernel Configuration # CONFIG_CC_VERSION_TEXT="gcc (Pisi Linux) 10.3.0" CONFIG_CC_IS_GCC=y @@ -2681,8 +2681,8 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_SPI_ATTRS=m CONFIG_SCSI_FC_ATTRS=m CONFIG_SCSI_ISCSI_ATTRS=m -CONFIG_SCSI_SAS_ATTRS=y -CONFIG_SCSI_SAS_LIBSAS=y +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SAS_LIBSAS=m CONFIG_SCSI_SAS_ATA=y CONFIG_SCSI_SAS_HOST_SMP=y CONFIG_SCSI_SRP_ATTRS=m @@ -2714,11 +2714,11 @@ CONFIG_AIC79XX_RESET_DELAY_MS=15000 # CONFIG_AIC79XX_DEBUG_ENABLE is not set CONFIG_AIC79XX_DEBUG_MASK=0 CONFIG_AIC79XX_REG_PRETTY_PRINT=y -CONFIG_SCSI_AIC94XX=y +CONFIG_SCSI_AIC94XX=m CONFIG_AIC94XX_DEBUG=y CONFIG_SCSI_MVSAS=m CONFIG_SCSI_MVSAS_DEBUG=y -# CONFIG_SCSI_MVSAS_TASKLET is not set +CONFIG_SCSI_MVSAS_TASKLET=y CONFIG_SCSI_MVUMI=m CONFIG_SCSI_DPT_I2O=m CONFIG_SCSI_ADVANSYS=m @@ -2733,7 +2733,7 @@ CONFIG_SCSI_MPT3SAS=m CONFIG_SCSI_MPT2SAS_MAX_SGE=128 CONFIG_SCSI_MPT3SAS_MAX_SGE=128 CONFIG_SCSI_MPT2SAS=m -# CONFIG_SCSI_MPI3MR is not set +CONFIG_SCSI_MPI3MR=m CONFIG_SCSI_SMARTPQI=m CONFIG_SCSI_UFSHCD=m CONFIG_SCSI_UFSHCD_PCI=m @@ -2787,7 +2787,7 @@ CONFIG_QEDI=m CONFIG_QEDF=m CONFIG_SCSI_LPFC=m # CONFIG_SCSI_LPFC_DEBUG_FS is not set -# CONFIG_SCSI_EFCT is not set +CONFIG_SCSI_EFCT=m CONFIG_SCSI_DC395x=m CONFIG_SCSI_AM53C974=m CONFIG_SCSI_WD719X=y @@ -2823,8 +2823,8 @@ CONFIG_SATA_PMP=y # CONFIG_SATA_AHCI=y CONFIG_SATA_MOBILE_LPM_POLICY=0 -CONFIG_SATA_AHCI_PLATFORM=y -# CONFIG_SATA_INIC162X is not set +CONFIG_SATA_AHCI_PLATFORM=m +CONFIG_SATA_INIC162X=m CONFIG_SATA_ACARD_AHCI=m CONFIG_SATA_SIL24=m CONFIG_ATA_SFF=y @@ -3141,6 +3141,7 @@ CONFIG_ATL1=m CONFIG_ATL1E=m CONFIG_ATL1C=m CONFIG_ALX=m +CONFIG_CX_ECAT=m CONFIG_NET_VENDOR_BROADCOM=y CONFIG_B44=m CONFIG_B44_PCI_AUTOSELECT=y @@ -3159,8 +3160,6 @@ CONFIG_BNXT_SRIOV=y CONFIG_BNXT_FLOWER_OFFLOAD=y CONFIG_BNXT_DCB=y CONFIG_BNXT_HWMON=y -CONFIG_NET_VENDOR_BROCADE=y -CONFIG_BNA=m CONFIG_NET_VENDOR_CADENCE=y CONFIG_MACB=m CONFIG_MACB_USE_HWSTAMP=y @@ -3186,7 +3185,6 @@ CONFIG_CHELSIO_INLINE_CRYPTO=y CONFIG_NET_VENDOR_CISCO=y CONFIG_ENIC=m CONFIG_NET_VENDOR_CORTINA=y -CONFIG_CX_ECAT=m # CONFIG_DNET is not set CONFIG_NET_VENDOR_DEC=y CONFIG_NET_TULIP=y @@ -3242,8 +3240,6 @@ CONFIG_I40EVF=m CONFIG_ICE=m CONFIG_FM10K=m CONFIG_IGC=m -CONFIG_NET_VENDOR_MICROSOFT=y -# CONFIG_MICROSOFT_MANA is not set CONFIG_JME=m CONFIG_NET_VENDOR_LITEX=y CONFIG_NET_VENDOR_MARVELL=y @@ -3297,10 +3293,14 @@ CONFIG_ENC28J60=m CONFIG_ENCX24J600=m CONFIG_LAN743X=m CONFIG_NET_VENDOR_MICROSEMI=y +CONFIG_NET_VENDOR_MICROSOFT=y +# CONFIG_MICROSOFT_MANA is not set CONFIG_NET_VENDOR_MYRI=y CONFIG_MYRI10GE=m CONFIG_MYRI10GE_DCA=y CONFIG_FEALNX=m +CONFIG_NET_VENDOR_NI=y +CONFIG_NI_XGE_MANAGEMENT_ENET=m CONFIG_NET_VENDOR_NATSEMI=y CONFIG_NATSEMI=m CONFIG_NS83820=m @@ -3313,8 +3313,6 @@ CONFIG_NFP=m # CONFIG_NFP_APP_FLOWER is not set CONFIG_NFP_APP_ABM_NIC=y # CONFIG_NFP_DEBUG is not set -CONFIG_NET_VENDOR_NI=y -CONFIG_NI_XGE_MANAGEMENT_ENET=m CONFIG_NET_VENDOR_8390=y CONFIG_PCMCIA_AXNET=m CONFIG_NE2K_PCI=m @@ -3343,6 +3341,8 @@ CONFIG_QED_RDMA=y CONFIG_QED_ISCSI=y CONFIG_QED_FCOE=y CONFIG_QED_OOO=y +CONFIG_NET_VENDOR_BROCADE=y +CONFIG_BNA=m CONFIG_NET_VENDOR_QUALCOMM=y CONFIG_QCOM_EMAC=m CONFIG_RMNET=m @@ -3363,6 +3363,11 @@ CONFIG_ROCKER=m CONFIG_NET_VENDOR_SAMSUNG=y CONFIG_SXGBE_ETH=m CONFIG_NET_VENDOR_SEEQ=y +CONFIG_NET_VENDOR_SILAN=y +CONFIG_SC92031=m +CONFIG_NET_VENDOR_SIS=y +CONFIG_SIS900=m +CONFIG_SIS190=m CONFIG_NET_VENDOR_SOLARFLARE=y CONFIG_SFC=m CONFIG_SFC_MTD=y @@ -3371,11 +3376,6 @@ CONFIG_SFC_SRIOV=y CONFIG_SFC_MCDI_LOGGING=y CONFIG_SFC_FALCON=m CONFIG_SFC_FALCON_MTD=y -CONFIG_NET_VENDOR_SILAN=y -CONFIG_SC92031=m -CONFIG_NET_VENDOR_SIS=y -CONFIG_SIS900=m -CONFIG_SIS190=m CONFIG_NET_VENDOR_SMSC=y CONFIG_PCMCIA_SMC91C92=m CONFIG_EPIC100=m @@ -9912,8 +9912,6 @@ CONFIG_INIT_STACK_NONE=y # CONFIG_GCC_PLUGIN_STACKLEAK is not set # CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set # CONFIG_INIT_ON_FREE_DEFAULT_ON is not set -CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y -# CONFIG_ZERO_CALL_USED_REGS is not set # end of Memory initialization # end of Kernel hardening options # end of Security options @@ -10373,7 +10371,6 @@ CONFIG_HAVE_ARCH_KGDB=y CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y # CONFIG_UBSAN is not set CONFIG_HAVE_ARCH_KCSAN=y -# CONFIG_KCSAN is not set # end of Generic Kernel Debugging Instruments CONFIG_DEBUG_KERNEL=y diff --git a/kernel/kernel/files/patches/aufs5/aufs5-base.patch b/kernel/kernel/files/patches/aufs5/aufs5-base.patch new file mode 100644 index 00000000..42ebd271 --- /dev/null +++ b/kernel/kernel/files/patches/aufs5/aufs5-base.patch @@ -0,0 +1,241 @@ +SPDX-License-Identifier: GPL-2.0 +aufs5.15.36 base patch + +diff --git a/MAINTAINERS b/MAINTAINERS +index c8103e57a70b..e1b9eaca78fd 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -3122,6 +3122,19 @@ F: include/uapi/linux/audit.h + F: kernel/audit* + F: lib/*audit.c + ++AUFS (advanced multi layered unification filesystem) FILESYSTEM ++M: "J. R. Okajima" ++L: aufs-users@lists.sourceforge.net (members only) ++L: linux-unionfs@vger.kernel.org ++S: Supported ++W: http://aufs.sourceforge.net ++T: git://github.com/sfjro/aufs4-linux.git ++F: Documentation/ABI/testing/debugfs-aufs ++F: Documentation/ABI/testing/sysfs-aufs ++F: Documentation/filesystems/aufs/ ++F: fs/aufs/ ++F: include/uapi/linux/aufs_type.h ++ + AUXILIARY DISPLAY DRIVERS + M: Miguel Ojeda + S: Maintained +diff --git a/drivers/block/loop.c b/drivers/block/loop.c +index 8cba10aafadb..7a9e40b97831 100644 +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -799,6 +799,24 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, + return error; + } + ++/* ++ * for AUFS ++ * no get/put for file. ++ */ ++struct file *loop_backing_file(struct super_block *sb) ++{ ++ struct file *ret; ++ struct loop_device *l; ++ ++ ret = NULL; ++ if (MAJOR(sb->s_dev) == LOOP_MAJOR) { ++ l = sb->s_bdev->bd_disk->private_data; ++ ret = l->lo_backing_file; ++ } ++ return ret; ++} ++EXPORT_SYMBOL_GPL(loop_backing_file); ++ + /* loop sysfs attributes */ + + static ssize_t loop_attr_show(struct device *dev, char *page, +diff --git a/fs/dcache.c b/fs/dcache.c +index cf871a81f4fd..bc5095b734f5 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -1320,7 +1320,7 @@ enum d_walk_ret { + * + * 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 *)) + { + struct dentry *this_parent; +diff --git a/fs/fcntl.c b/fs/fcntl.c +index 9c6c6a3e2de5..02382fa9bd34 100644 +--- a/fs/fcntl.c ++++ b/fs/fcntl.c +@@ -33,7 +33,7 @@ + + #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME) + +-static int setfl(int fd, struct file * filp, unsigned long arg) ++int setfl(int fd, struct file *filp, unsigned long arg) + { + struct inode * inode = file_inode(filp); + int error = 0; +@@ -64,6 +64,8 @@ static int setfl(int fd, struct file * filp, unsigned long arg) + + if (filp->f_op->check_flags) + error = filp->f_op->check_flags(arg); ++ if (!error && filp->f_op->setfl) ++ error = filp->f_op->setfl(filp, arg); + if (error) + return error; + +diff --git a/fs/namespace.c b/fs/namespace.c +index b696543adab8..c45740054bc7 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -808,6 +808,12 @@ static inline int check_mnt(struct mount *mnt) + return mnt->mnt_ns == current->nsproxy->mnt_ns; + } + ++/* for aufs, CONFIG_AUFS_BR_FUSE */ ++int is_current_mnt_ns(struct vfsmount *mnt) ++{ ++ return check_mnt(real_mount(mnt)); ++} ++ + /* + * vfsmount lock must be held for write + */ +diff --git a/fs/splice.c b/fs/splice.c +index 5dbce4dcc1a7..3e6ba363b777 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -759,8 +759,8 @@ static int warn_unsupported(struct file *file, const char *op) + /* + * Attempt to initiate a splice from pipe to file. + */ +-static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, +- loff_t *ppos, size_t len, unsigned int flags) ++long do_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags) + { + if (unlikely(!out->f_op->splice_write)) + return warn_unsupported(out, "write"); +@@ -770,9 +770,9 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + /* + * Attempt to initiate a splice from a file to a pipe. + */ +-static long do_splice_to(struct file *in, loff_t *ppos, +- struct pipe_inode_info *pipe, size_t len, +- unsigned int flags) ++long do_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) + { + unsigned int p_space; + int ret; +diff --git a/include/linux/fs.h b/include/linux/fs.h +index 56eba723477e..e60d8ad85400 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1381,6 +1381,7 @@ extern void fasync_free(struct fasync_struct *); + /* can be called from interrupts */ + extern void kill_fasync(struct fasync_struct **, int, int); + ++extern int setfl(int fd, struct file *filp, unsigned long arg); + 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); +@@ -2092,6 +2093,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); ++ int (*setfl)(struct file *, unsigned long); + 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); +@@ -2615,6 +2617,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 timespec64 *, int); ++extern int update_time(struct inode *, struct timespec64 *, int); + + /* /sys/fs */ + extern struct kobject *fs_kobj; +@@ -2778,6 +2781,7 @@ static inline bool sb_is_blkdev_sb(struct super_block *sb) + } + + void emergency_thaw_all(void); ++extern int __sync_filesystem(struct super_block *, int); + extern int sync_filesystem(struct super_block *); + 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 9fe165beb0f9..e47f7e15eeaf 100644 +--- a/include/linux/lockdep.h ++++ b/include/linux/lockdep.h +@@ -248,6 +248,8 @@ static inline int lockdep_match_key(struct lockdep_map *lock, + return lock->key == key; + } + ++struct lock_class *lockdep_hlock_class(struct held_lock *hlock); ++ + /* + * Acquire a lock. + * +diff --git a/include/linux/mnt_namespace.h b/include/linux/mnt_namespace.h +index 8f882f5881e8..6b9808f09843 100644 +--- a/include/linux/mnt_namespace.h ++++ b/include/linux/mnt_namespace.h +@@ -7,12 +7,15 @@ struct mnt_namespace; + struct fs_struct; + struct user_namespace; + struct ns_common; ++struct vfsmount; + + extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *, + struct user_namespace *, struct fs_struct *); + extern void put_mnt_ns(struct mnt_namespace *ns); + extern struct ns_common *from_mnt_ns(struct mnt_namespace *); + ++extern int is_current_mnt_ns(struct vfsmount *mnt); ++ + extern const struct file_operations proc_mounts_operations; + extern const struct file_operations proc_mountinfo_operations; + extern const struct file_operations proc_mountstats_operations; +diff --git a/include/linux/splice.h b/include/linux/splice.h +index a55179fd60fc..8e21c53cf883 100644 +--- a/include/linux/splice.h ++++ b/include/linux/splice.h +@@ -93,4 +93,10 @@ extern void splice_shrink_spd(struct splice_pipe_desc *); + + extern const struct pipe_buf_operations page_cache_pipe_buf_ops; + extern const struct pipe_buf_operations default_pipe_buf_ops; ++ ++extern long do_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags); ++extern long do_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags); + #endif +diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c +index a30702b847ba..ce380d0abdf0 100644 +--- a/kernel/locking/lockdep.c ++++ b/kernel/locking/lockdep.c +@@ -187,7 +187,7 @@ unsigned long max_lock_class_idx; + struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; + DECLARE_BITMAP(lock_classes_in_use, 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) + { + unsigned int class_idx = hlock->class_idx; + +@@ -208,6 +208,7 @@ static inline struct lock_class *hlock_class(struct held_lock *hlock) + */ + return lock_classes + class_idx; + } ++#define hlock_class(hlock) lockdep_hlock_class(hlock) + + #ifdef CONFIG_LOCK_STAT + static DEFINE_PER_CPU(struct lock_class_stats[MAX_LOCKDEP_KEYS], cpu_lock_stats); diff --git a/kernel/kernel/files/patches/aufs5/aufs5-kbuild.patch b/kernel/kernel/files/patches/aufs5/aufs5-kbuild.patch new file mode 100644 index 00000000..79c3f92c --- /dev/null +++ b/kernel/kernel/files/patches/aufs5/aufs5-kbuild.patch @@ -0,0 +1,24 @@ +SPDX-License-Identifier: GPL-2.0 +aufs5.15.36 kbuild patch + +diff --git a/fs/Kconfig b/fs/Kconfig +index a6313a969bc5..aca4b89d41a1 100644 +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -312,6 +312,7 @@ source "fs/sysv/Kconfig" + source "fs/ufs/Kconfig" + source "fs/erofs/Kconfig" + source "fs/vboxsf/Kconfig" ++source "fs/aufs/Kconfig" + + endif # MISC_FILESYSTEMS + +diff --git a/fs/Makefile b/fs/Makefile +index 84c5e4cdfee5..b4fcdad8412e 100644 +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -138,3 +138,4 @@ obj-$(CONFIG_EFIVAR_FS) += efivarfs/ + obj-$(CONFIG_EROFS_FS) += erofs/ + obj-$(CONFIG_VBOXSF_FS) += vboxsf/ + obj-$(CONFIG_ZONEFS_FS) += zonefs/ ++obj-$(CONFIG_AUFS_FS) += aufs/ diff --git a/kernel/kernel/files/patches/aufs5/aufs5-loopback.patch b/kernel/kernel/files/patches/aufs5/aufs5-loopback.patch new file mode 100644 index 00000000..1011fb54 --- /dev/null +++ b/kernel/kernel/files/patches/aufs5/aufs5-loopback.patch @@ -0,0 +1,244 @@ +SPDX-License-Identifier: GPL-2.0 +aufs5.15.36 loopback patch + +diff --git a/drivers/block/loop.c b/drivers/block/loop.c +index 7a9e40b97831..5ed06240cc9c 100644 +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -673,6 +673,15 @@ static inline void loop_update_dio(struct loop_device *lo) + lo->use_dio); + } + ++static struct file *loop_real_file(struct file *file) ++{ ++ struct file *f = NULL; ++ ++ if (file->f_path.dentry->d_sb->s_op->real_loop) ++ f = file->f_path.dentry->d_sb->s_op->real_loop(file); ++ return f; ++} ++ + static void loop_reread_partitions(struct loop_device *lo) + { + int rc; +@@ -730,6 +739,7 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, + { + struct file *file = fget(arg); + struct file *old_file; ++ struct file *f, *virt_file = NULL, *old_virt_file; + int error; + bool partscan; + bool is_loop; +@@ -749,11 +759,19 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, + if (!(lo->lo_flags & LO_FLAGS_READ_ONLY)) + goto out_err; + ++ f = loop_real_file(file); ++ if (f) { ++ virt_file = file; ++ file = f; ++ get_file(file); ++ } ++ + error = loop_validate_file(file, bdev); + if (error) + goto out_err; + + old_file = lo->lo_backing_file; ++ old_virt_file = lo->lo_backing_virt_file; + + error = -EINVAL; + +@@ -766,6 +784,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; ++ lo->lo_backing_virt_file = virt_file; + 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)); +@@ -788,6 +807,8 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, + * dependency. + */ + fput(old_file); ++ if (old_virt_file) ++ fput(old_virt_file); + if (partscan) + loop_reread_partitions(lo); + return 0; +@@ -796,6 +817,8 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, + loop_global_unlock(lo, is_loop); + out_putf: + fput(file); ++ if (virt_file) ++ fput(virt_file); + return error; + } + +@@ -1201,6 +1224,7 @@ static int loop_configure(struct loop_device *lo, fmode_t mode, + const struct loop_config *config) + { + struct file *file = fget(config->fd); ++ struct file *f, *virt_file = NULL; + struct inode *inode; + struct address_space *mapping; + int error; +@@ -1216,6 +1240,13 @@ static int loop_configure(struct loop_device *lo, fmode_t mode, + /* This is safe, since we have a reference from open(). */ + __module_get(THIS_MODULE); + ++ f = loop_real_file(file); ++ if (f) { ++ virt_file = file; ++ file = f; ++ get_file(file); ++ } ++ + /* + * If we don't hold exclusive handle for the device, upgrade to it + * here to avoid changing device under exclusive owner. +@@ -1281,6 +1312,7 @@ static int loop_configure(struct loop_device *lo, fmode_t mode, + lo->use_dio = lo->lo_flags & LO_FLAGS_DIRECT_IO; + lo->lo_device = bdev; + lo->lo_backing_file = file; ++ lo->lo_backing_virt_file = virt_file; + lo->old_gfp_mask = mapping_gfp_mask(mapping); + mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); + +@@ -1331,6 +1363,8 @@ static int loop_configure(struct loop_device *lo, fmode_t mode, + bd_abort_claiming(bdev, loop_configure); + out_putf: + fput(file); ++ if (virt_file) ++ fput(virt_file); + /* This is safe: open() is still holding a reference. */ + module_put(THIS_MODULE); + return error; +@@ -1339,6 +1373,7 @@ static int loop_configure(struct loop_device *lo, fmode_t mode, + static int __loop_clr_fd(struct loop_device *lo, bool release) + { + struct file *filp = NULL; ++ struct file *virt_filp = lo->lo_backing_virt_file; + gfp_t gfp = lo->old_gfp_mask; + struct block_device *bdev = lo->lo_device; + int err = 0; +@@ -1390,6 +1425,7 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) + + spin_lock_irq(&lo->lo_lock); + lo->lo_backing_file = NULL; ++ lo->lo_backing_virt_file = NULL; + spin_unlock_irq(&lo->lo_lock); + + loop_release_xfer(lo); +@@ -1470,6 +1506,8 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) + */ + if (filp) + fput(filp); ++ if (virt_filp) ++ fput(virt_filp); + return err; + } + +diff --git a/drivers/block/loop.h b/drivers/block/loop.h +index 04c88dd6eabd..0ff3ba22ee17 100644 +--- a/drivers/block/loop.h ++++ b/drivers/block/loop.h +@@ -46,7 +46,7 @@ struct loop_device { + int (*ioctl)(struct loop_device *, int cmd, + unsigned long arg); + +- struct file * lo_backing_file; ++ struct file *lo_backing_file, *lo_backing_virt_file; + struct block_device *lo_device; + void *key_data; + +diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c +index 99ceca144044..e49dfe855032 100644 +--- a/fs/aufs/f_op.c ++++ b/fs/aufs/f_op.c +@@ -304,7 +304,7 @@ static ssize_t aufs_read_iter(struct kiocb *kio, struct iov_iter *iov_iter) + if (IS_ERR(h_file)) + goto out; + +- if (au_test_loopback_kthread()) { ++ if (0 && au_test_loopback_kthread()) { + au_warn_loopback(h_file->f_path.dentry->d_sb); + 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 74347bd75b38..5ef888a1d53f 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); + au_kfree_try_rcu(au_warn_loopback_array); + } ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* support the loopback block device insude aufs */ ++ ++struct file *aufs_real_loop(struct file *file) ++{ ++ struct file *f; ++ ++ BUG_ON(!au_test_aufs(file->f_path.dentry->d_sb)); ++ fi_read_lock(file); ++ f = au_hf_top(file); ++ fi_read_unlock(file); ++ AuDebugOn(!f); ++ return f; ++} +diff --git a/fs/aufs/loop.h b/fs/aufs/loop.h +index 7293bee427f9..3345c098d0d4 100644 +--- a/fs/aufs/loop.h ++++ b/fs/aufs/loop.h +@@ -26,6 +26,8 @@ void au_warn_loopback(struct super_block *h_sb); + + int au_loopback_init(void); + void au_loopback_fin(void); ++ ++struct file *aufs_real_loop(struct file *file); + #else + AuStub(struct file *, loop_backing_file, return NULL, struct super_block *sb) + +@@ -36,6 +38,8 @@ AuStubVoid(au_warn_loopback, struct super_block *h_sb) + + AuStubInt0(au_loopback_init, void) + AuStubVoid(au_loopback_fin, void) ++ ++AuStub(struct file *, aufs_real_loop, return NULL, struct file *file) + #endif /* BLK_DEV_LOOP */ + + #endif /* __KERNEL__ */ +diff --git a/fs/aufs/super.c b/fs/aufs/super.c +index 90043afec51c..0835f6da42d9 100644 +--- a/fs/aufs/super.c ++++ b/fs/aufs/super.c +@@ -758,7 +758,10 @@ const struct super_operations aufs_sop = { + .show_options = aufs_show_options, + .statfs = aufs_statfs, + .put_super = aufs_put_super, +- .sync_fs = aufs_sync_fs ++ .sync_fs = aufs_sync_fs, ++#ifdef CONFIG_AUFS_BDEV_LOOP ++ .real_loop = aufs_real_loop ++#endif + }; + + /* ---------------------------------------------------------------------- */ +diff --git a/include/linux/fs.h b/include/linux/fs.h +index e60d8ad85400..2ac5317f9b79 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -2226,6 +2226,10 @@ struct super_operations { + struct shrink_control *); + long (*free_cached_objects)(struct super_block *, + struct shrink_control *); ++#if IS_ENABLED(CONFIG_BLK_DEV_LOOP) || IS_ENABLED(CONFIG_BLK_DEV_LOOP_MODULE) ++ /* and aufs */ ++ struct file *(*real_loop)(struct file *); ++#endif + }; + + /* diff --git a/kernel/kernel/files/patches/aufs5/aufs5-mmap.patch b/kernel/kernel/files/patches/aufs5/aufs5-mmap.patch new file mode 100644 index 00000000..a8b2040c --- /dev/null +++ b/kernel/kernel/files/patches/aufs5/aufs5-mmap.patch @@ -0,0 +1,419 @@ +SPDX-License-Identifier: GPL-2.0 +aufs5.15.36 mmap patch + +diff --git a/fs/proc/base.c b/fs/proc/base.c +index 1f394095eb88..93f2479ef319 100644 +--- a/fs/proc/base.c ++++ b/fs/proc/base.c +@@ -2189,7 +2189,7 @@ static int map_files_get_link(struct dentry *dentry, struct path *path) + rc = -ENOENT; + vma = find_exact_vma(mm, vm_start, vm_end); + if (vma && vma->vm_file) { +- *path = vma->vm_file->f_path; ++ *path = vma_pr_or_file(vma)->f_path; + path_get(path); + rc = 0; + } +diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c +index 13452b32e2bd..38acccfef9d4 100644 +--- a/fs/proc/nommu.c ++++ b/fs/proc/nommu.c +@@ -40,7 +40,10 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region) + file = region->vm_file; + + if (file) { +- struct inode *inode = file_inode(region->vm_file); ++ struct inode *inode; ++ ++ file = vmr_pr_or_file(region); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + } +diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c +index 79ca4d69dfd6..3d3067c8d868 100644 +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -280,7 +280,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma) + const char *name = NULL; + + if (file) { +- struct inode *inode = file_inode(vma->vm_file); ++ struct inode *inode; ++ ++ file = vma_pr_or_file(vma); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT; +@@ -1888,7 +1891,7 @@ static int show_numa_map(struct seq_file *m, void *v) + struct proc_maps_private *proc_priv = &numa_priv->proc_maps; + struct vm_area_struct *vma = v; + struct numa_maps *md = &numa_priv->md; +- struct file *file = vma->vm_file; ++ struct file *file = vma_pr_or_file(vma); + struct mm_struct *mm = vma->vm_mm; + struct mempolicy *pol; + char buffer[64]; +diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c +index a6d21fc0033c..02c2de31196e 100644 +--- a/fs/proc/task_nommu.c ++++ b/fs/proc/task_nommu.c +@@ -155,7 +155,10 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma) + file = vma->vm_file; + + if (file) { +- struct inode *inode = file_inode(vma->vm_file); ++ struct inode *inode; ++ ++ file = vma_pr_or_file(vma); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT; +diff --git a/include/linux/mm.h b/include/linux/mm.h +index 90c2d7f3c7a8..ab1b20fa5837 100644 +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -1813,6 +1813,43 @@ static inline void unmap_shared_mapping_range(struct address_space *mapping, + unmap_mapping_range(mapping, holebegin, holelen, 0); + } + ++#if IS_ENABLED(CONFIG_AUFS_FS) ++extern void vma_do_file_update_time(struct vm_area_struct *, const char[], int); ++extern struct file *vma_do_pr_or_file(struct vm_area_struct *, const char[], ++ int); ++extern void vma_do_get_file(struct vm_area_struct *, const char[], int); ++extern void vma_do_fput(struct vm_area_struct *, const char[], int); ++ ++#define vma_file_update_time(vma) vma_do_file_update_time(vma, __func__, \ ++ __LINE__) ++#define vma_pr_or_file(vma) vma_do_pr_or_file(vma, __func__, \ ++ __LINE__) ++#define vma_get_file(vma) vma_do_get_file(vma, __func__, __LINE__) ++#define vma_fput(vma) vma_do_fput(vma, __func__, __LINE__) ++ ++#ifndef CONFIG_MMU ++extern struct file *vmr_do_pr_or_file(struct vm_region *, const char[], int); ++extern void vmr_do_fput(struct vm_region *, const char[], int); ++ ++#define vmr_pr_or_file(region) vmr_do_pr_or_file(region, __func__, \ ++ __LINE__) ++#define vmr_fput(region) vmr_do_fput(region, __func__, __LINE__) ++#endif /* !CONFIG_MMU */ ++ ++#else ++ ++#define vma_file_update_time(vma) file_update_time((vma)->vm_file) ++#define vma_pr_or_file(vma) (vma)->vm_file ++#define vma_get_file(vma) get_file((vma)->vm_file) ++#define vma_fput(vma) fput((vma)->vm_file) ++ ++#ifndef CONFIG_MMU ++#define vmr_pr_or_file(region) (region)->vm_file ++#define vmr_fput(region) fput((region)->vm_file) ++#endif /* !CONFIG_MMU */ ++ ++#endif /* CONFIG_AUFS_FS */ ++ + extern int access_process_vm(struct task_struct *tsk, unsigned long addr, + void *buf, int len, unsigned int gup_flags); + extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, +diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h +index 7f8ee09c711f..8fea872e08f7 100644 +--- a/include/linux/mm_types.h ++++ b/include/linux/mm_types.h +@@ -294,6 +294,9 @@ struct vm_region { + unsigned long vm_top; /* region allocated to here */ + unsigned long vm_pgoff; /* the offset in vm_file corresponding to vm_start */ + struct file *vm_file; /* the backing file or NULL */ ++#if IS_ENABLED(CONFIG_AUFS_FS) ++ struct file *vm_prfile; /* the virtual backing file or NULL */ ++#endif + + int vm_usage; /* region usage count (access under nommu_region_sem) */ + bool vm_icache_flushed : 1; /* true if the icache has been flushed for +@@ -373,6 +376,9 @@ struct vm_area_struct { + unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE + units */ + struct file * vm_file; /* File we map to (can be NULL). */ ++#if IS_ENABLED(CONFIG_AUFS_FS) ++ struct file *vm_prfile; /* shadow of vm_file */ ++#endif + void * vm_private_data; /* was vm_pte (shared mem) */ + + #ifdef CONFIG_SWAP +diff --git a/kernel/fork.c b/kernel/fork.c +index 89475c994ca9..82f46f8f4090 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -573,7 +573,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, + if (file) { + struct address_space *mapping = file->f_mapping; + +- get_file(file); ++ vma_get_file(tmp); + i_mmap_lock_write(mapping); + if (tmp->vm_flags & VM_SHARED) + mapping_allow_writable(mapping); +diff --git a/mm/Makefile b/mm/Makefile +index fc60a40ce954..d45773672730 100644 +--- a/mm/Makefile ++++ b/mm/Makefile +@@ -130,3 +130,4 @@ obj-$(CONFIG_PAGE_REPORTING) += page_reporting.o + obj-$(CONFIG_IO_MAPPING) += io-mapping.o + obj-$(CONFIG_HAVE_BOOTMEM_INFO_NODE) += bootmem_info.o + obj-$(CONFIG_GENERIC_IOREMAP) += ioremap.o ++obj-$(CONFIG_AUFS_FS:m=y) += prfile.o +diff --git a/mm/filemap.c b/mm/filemap.c +index 1293c3409e42..42b012b99f4e 100644 +--- a/mm/filemap.c ++++ b/mm/filemap.c +@@ -3353,7 +3353,7 @@ vm_fault_t filemap_page_mkwrite(struct vm_fault *vmf) + vm_fault_t ret = VM_FAULT_LOCKED; + + sb_start_pagefault(mapping->host->i_sb); +- file_update_time(vmf->vma->vm_file); ++ vma_file_update_time(vmf->vma); + lock_page(page); + if (page->mapping != mapping) { + unlock_page(page); +diff --git a/mm/mmap.c b/mm/mmap.c +index 6bb553ed5c55..3f9d6d155171 100644 +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -183,7 +183,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)); + vm_area_free(vma); + return next; +@@ -952,7 +952,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); +- fput(file); ++ vma_fput(vma); + } + if (next->anon_vma) + anon_vma_merge(vma, next); +@@ -1873,7 +1873,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr, + return addr; + + unmap_and_free_vma: +- fput(vma->vm_file); ++ vma_fput(vma); + vma->vm_file = NULL; + + /* Undo any partial mapping done by a device driver. */ +@@ -2723,7 +2723,7 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, + goto out_free_mpol; + + if (new->vm_file) +- get_file(new->vm_file); ++ vma_get_file(new); + + if (new->vm_ops && new->vm_ops->open) + new->vm_ops->open(new); +@@ -2742,7 +2742,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) +- fput(new->vm_file); ++ vma_fput(new); + unlink_anon_vmas(new); + out_free_mpol: + mpol_put(vma_policy(new)); +@@ -2938,6 +2938,9 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, + unsigned long populate = 0; + unsigned long ret = -EINVAL; + struct file *file; ++#if IS_ENABLED(CONFIG_AUFS_FS) ++ struct file *prfile; ++#endif + + pr_warn_once("%s (%d) uses deprecated remap_file_pages() syscall. See Documentation/vm/remap_file_pages.rst.\n", + current->comm, current->pid); +@@ -2993,10 +2996,34 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, + if (vma->vm_flags & VM_LOCKED) + flags |= MAP_LOCKED; + ++#if IS_ENABLED(CONFIG_AUFS_FS) ++ vma_get_file(vma); ++ file = vma->vm_file; ++ prfile = vma->vm_prfile; ++ ret = do_mmap(vma->vm_file, start, size, ++ prot, flags, pgoff, &populate, NULL); ++ if (!IS_ERR_VALUE(ret) && file && prfile) { ++ struct vm_area_struct *new_vma; ++ ++ new_vma = find_vma(mm, ret); ++ if (!new_vma->vm_prfile) ++ new_vma->vm_prfile = prfile; ++ if (new_vma != vma) ++ get_file(prfile); ++ } ++ /* ++ * two fput()s instead of vma_fput(vma), ++ * coz vma may not be available anymore. ++ */ ++ fput(file); ++ if (prfile) ++ fput(prfile); ++#else + file = get_file(vma->vm_file); + ret = do_mmap(vma->vm_file, start, size, + prot, flags, pgoff, &populate, NULL); + fput(file); ++#endif /* CONFIG_AUFS_FS */ + out: + mmap_write_unlock(mm); + if (populate) +@@ -3277,7 +3304,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, + if (anon_vma_clone(new_vma, vma)) + goto out_free_mempol; + if (new_vma->vm_file) +- get_file(new_vma->vm_file); ++ vma_get_file(new_vma); + if (new_vma->vm_ops && new_vma->vm_ops->open) + new_vma->vm_ops->open(new_vma); + vma_link(mm, new_vma, prev, rb_link, rb_parent); +diff --git a/mm/nommu.c b/mm/nommu.c +index 02d2427b8f9e..a7419302ab4e 100644 +--- a/mm/nommu.c ++++ b/mm/nommu.c +@@ -523,7 +523,7 @@ static void __put_nommu_region(struct vm_region *region) + up_write(&nommu_region_sem); + + if (region->vm_file) +- fput(region->vm_file); ++ vmr_fput(region); + + /* IO memory and memory shared directly out of the pagecache + * from ramfs/tmpfs mustn't be released here */ +@@ -655,7 +655,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); + vm_area_free(vma); + } +@@ -1175,7 +1175,7 @@ unsigned long do_mmap(struct file *file, + goto error_just_free; + } + } +- fput(region->vm_file); ++ vmr_fput(region); + kmem_cache_free(vm_region_jar, region); + region = pregion; + result = start; +@@ -1252,10 +1252,10 @@ unsigned long do_mmap(struct file *file, + up_write(&nommu_region_sem); + error: + if (region->vm_file) +- fput(region->vm_file); ++ vmr_fput(region); + kmem_cache_free(vm_region_jar, region); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + vm_area_free(vma); + return ret; + +diff --git a/mm/prfile.c b/mm/prfile.c +new file mode 100644 +index 000000000000..511543ab1b41 +--- /dev/null ++++ b/mm/prfile.c +@@ -0,0 +1,86 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Mainly for aufs which mmap(2) different file and wants to print different ++ * path in /proc/PID/maps. ++ * Call these functions via macros defined in linux/mm.h. ++ * ++ * See Documentation/filesystems/aufs/design/06mmap.txt ++ * ++ * Copyright (c) 2014-2021 Junjro R. Okajima ++ * Copyright (c) 2014 Ian Campbell ++ */ ++ ++#include ++#include ++#include ++ ++/* #define PRFILE_TRACE */ ++static inline void prfile_trace(struct file *f, struct file *pr, ++ const char func[], int line, const char func2[]) ++{ ++#ifdef PRFILE_TRACE ++ if (pr) ++ pr_info("%s:%d: %s, %pD2\n", func, line, func2, f); ++#endif ++} ++ ++void vma_do_file_update_time(struct vm_area_struct *vma, const char func[], ++ int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ file_update_time(f); ++ if (f && pr) ++ file_update_time(pr); ++} ++ ++struct file *vma_do_pr_or_file(struct vm_area_struct *vma, const char func[], ++ int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ return (f && pr) ? pr : f; ++} ++ ++void vma_do_get_file(struct vm_area_struct *vma, const char func[], int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ get_file(f); ++ if (f && pr) ++ get_file(pr); ++} ++ ++void vma_do_fput(struct vm_area_struct *vma, const char func[], int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ fput(f); ++ if (f && pr) ++ fput(pr); ++} ++ ++#ifndef CONFIG_MMU ++struct file *vmr_do_pr_or_file(struct vm_region *region, const char func[], ++ int line) ++{ ++ struct file *f = region->vm_file, *pr = region->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ return (f && pr) ? pr : f; ++} ++ ++void vmr_do_fput(struct vm_region *region, const char func[], int line) ++{ ++ struct file *f = region->vm_file, *pr = region->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ fput(f); ++ if (f && pr) ++ fput(pr); ++} ++#endif /* !CONFIG_MMU */ diff --git a/kernel/kernel/files/patches/aufs5/aufs5-standalone.patch b/kernel/kernel/files/patches/aufs5/aufs5-standalone.patch new file mode 100644 index 00000000..63d24760 --- /dev/null +++ b/kernel/kernel/files/patches/aufs5/aufs5-standalone.patch @@ -0,0 +1,251 @@ +SPDX-License-Identifier: GPL-2.0 +aufs5.15.36 standalone patch + +diff --git a/fs/dcache.c b/fs/dcache.c +index bc5095b734f5..9508bd57a3bc 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -1425,6 +1425,7 @@ void d_walk(struct dentry *parent, void *data, + seq = 1; + goto again; + } ++EXPORT_SYMBOL_GPL(d_walk); + + struct check_mount { + struct vfsmount *mnt; +@@ -2970,6 +2971,7 @@ void d_exchange(struct dentry *dentry1, struct dentry *dentry2) + + write_sequnlock(&rename_lock); + } ++EXPORT_SYMBOL_GPL(d_exchange); + + /** + * d_ancestor - search for an ancestor +diff --git a/fs/exec.c b/fs/exec.c +index 29e865c59854..3ea36fa14622 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -111,6 +111,7 @@ bool path_noexec(const struct path *path) + return (path->mnt->mnt_flags & MNT_NOEXEC) || + (path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC); + } ++EXPORT_SYMBOL_GPL(path_noexec); + + #ifdef CONFIG_USELIB + /* +diff --git a/fs/fcntl.c b/fs/fcntl.c +index 02382fa9bd34..3418c60b9014 100644 +--- a/fs/fcntl.c ++++ b/fs/fcntl.c +@@ -86,6 +86,7 @@ int setfl(int fd, struct file *filp, unsigned long arg) + out: + return error; + } ++EXPORT_SYMBOL_GPL(setfl); + + static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, + int force) +diff -Nurp a/fs/file_table.c b/fs/file_table.c +--- a/fs/file_table.c 2022-03-20 22:14:17.000000000 +0200 ++++ b/fs/file_table.c 2022-04-08 20:24:23.624148779 +0300 +@@ -198,6 +198,7 @@ over: + } + return ERR_PTR(-ENFILE); + } ++EXPORT_SYMBOL_GPL(alloc_empty_file); + + /* + * Variant of alloc_empty_file() that doesn't check and modify nr_files. +diff --git a/fs/namespace.c b/fs/namespace.c +index c45740054bc7..d3d750635610 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -439,6 +439,7 @@ void __mnt_drop_write(struct vfsmount *mnt) + mnt_dec_writers(real_mount(mnt)); + preempt_enable(); + } ++EXPORT_SYMBOL_GPL(__mnt_drop_write); + + /** + * mnt_drop_write - give up write access to a mount +@@ -813,6 +814,7 @@ int is_current_mnt_ns(struct vfsmount *mnt) + { + return check_mnt(real_mount(mnt)); + } ++EXPORT_SYMBOL_GPL(is_current_mnt_ns); + + /* + * vfsmount lock must be held for write +@@ -2011,6 +2013,7 @@ int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg, + } + return 0; + } ++EXPORT_SYMBOL_GPL(iterate_mounts); + + static void lock_mnt_tree(struct mount *mnt) + { +diff --git a/fs/notify/group.c b/fs/notify/group.c +index fb89c351295d..460ad19c2570 100644 +--- a/fs/notify/group.c ++++ b/fs/notify/group.c +@@ -100,6 +100,7 @@ void fsnotify_get_group(struct fsnotify_group *group) + { + refcount_inc(&group->refcnt); + } ++EXPORT_SYMBOL_GPL(fsnotify_get_group); + + /* + * Drop a reference to a group. Free it if it's through. +diff --git a/fs/open.c b/fs/open.c +index e0df1536eb69..81b2d7c83add 100644 +--- a/fs/open.c ++++ b/fs/open.c +@@ -65,6 +65,7 @@ int do_truncate(struct user_namespace *mnt_userns, struct dentry *dentry, + inode_unlock(dentry->d_inode); + return ret; + } ++EXPORT_SYMBOL_GPL(do_truncate); + + long vfs_truncate(const struct path *path, loff_t length) + { +diff --git a/fs/read_write.c b/fs/read_write.c +index af057c57bdc6..76017f8331fb 100644 +--- a/fs/read_write.c ++++ b/fs/read_write.c +@@ -492,6 +492,7 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) + inc_syscr(current); + return ret; + } ++EXPORT_SYMBOL_GPL(vfs_read); + + static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) + { +@@ -602,6 +603,7 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ + file_end_write(file); + return ret; + } ++EXPORT_SYMBOL_GPL(vfs_write); + + /* file_ppos returns &file->f_pos or NULL if file is stream */ + static inline loff_t *file_ppos(struct file *file) +diff --git a/fs/splice.c b/fs/splice.c +index 3e6ba363b777..7c1be373eb7c 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -766,6 +766,7 @@ long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + return warn_unsupported(out, "write"); + return out->f_op->splice_write(pipe, out, ppos, len, flags); + } ++EXPORT_SYMBOL_GPL(do_splice_from); + + /* + * Attempt to initiate a splice from a file to a pipe. +@@ -795,6 +796,7 @@ long do_splice_to(struct file *in, loff_t *ppos, + return warn_unsupported(in, "read"); + return in->f_op->splice_read(in, ppos, pipe, len, flags); + } ++EXPORT_SYMBOL_GPL(do_splice_to); + + /** + * splice_direct_to_actor - splices data directly between two non-pipes +diff --git a/fs/xattr.c b/fs/xattr.c +index 5c8c5175b385..ff7e9ff774b7 100644 +--- a/fs/xattr.c ++++ b/fs/xattr.c +@@ -384,6 +384,7 @@ vfs_getxattr_alloc(struct user_namespace *mnt_userns, struct dentry *dentry, + *xattr_value = value; + return error; + } ++EXPORT_SYMBOL_GPL(vfs_getxattr_alloc); + + 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 ce380d0abdf0..409c7d1a6803 100644 +--- a/kernel/locking/lockdep.c ++++ b/kernel/locking/lockdep.c +@@ -208,6 +208,7 @@ inline struct lock_class *lockdep_hlock_class(struct held_lock *hlock) + */ + return lock_classes + class_idx; + } ++EXPORT_SYMBOL_GPL(lockdep_hlock_class); + #define hlock_class(hlock) lockdep_hlock_class(hlock) + + #ifdef CONFIG_LOCK_STAT +diff --git a/kernel/task_work.c b/kernel/task_work.c +index 1698fbe6f0e1..081b05acadf8 100644 +--- a/kernel/task_work.c ++++ b/kernel/task_work.c +@@ -167,3 +167,4 @@ void task_work_run(void) + } while (work); + } + } ++EXPORT_SYMBOL_GPL(task_work_run); +diff --git a/security/security.c b/security/security.c +index da631339e969..894203de3bcb 100644 +--- a/security/security.c ++++ b/security/security.c +@@ -1160,6 +1160,7 @@ int security_path_rmdir(const struct path *dir, struct dentry *dentry) + return 0; + return call_int_hook(path_rmdir, 0, dir, dentry); + } ++EXPORT_SYMBOL_GPL(security_path_rmdir); + + int security_path_unlink(const struct path *dir, struct dentry *dentry) + { +@@ -1176,6 +1177,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); + } ++EXPORT_SYMBOL_GPL(security_path_symlink); + + int security_path_link(struct dentry *old_dentry, const struct path *new_dir, + struct dentry *new_dentry) +@@ -1184,6 +1186,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); + } ++EXPORT_SYMBOL_GPL(security_path_link); + + int security_path_rename(const struct path *old_dir, struct dentry *old_dentry, + const struct path *new_dir, struct dentry *new_dentry, +@@ -1211,6 +1214,7 @@ int security_path_truncate(const struct path *path) + return 0; + return call_int_hook(path_truncate, 0, path); + } ++EXPORT_SYMBOL_GPL(security_path_truncate); + + int security_path_chmod(const struct path *path, umode_t mode) + { +@@ -1218,6 +1222,7 @@ int security_path_chmod(const struct path *path, umode_t mode) + return 0; + return call_int_hook(path_chmod, 0, path, mode); + } ++EXPORT_SYMBOL_GPL(security_path_chmod); + + int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid) + { +@@ -1225,6 +1230,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); + } ++EXPORT_SYMBOL_GPL(security_path_chown); + + int security_path_chroot(const struct path *path) + { +@@ -1325,6 +1331,7 @@ int security_inode_permission(struct inode *inode, int mask) + return 0; + return call_int_hook(inode_permission, 0, inode, mask); + } ++EXPORT_SYMBOL_GPL(security_inode_permission); + + int security_inode_setattr(struct dentry *dentry, struct iattr *attr) + { +@@ -1522,6 +1529,7 @@ int security_file_permission(struct file *file, int mask) + + return fsnotify_perm(file, mask); + } ++EXPORT_SYMBOL_GPL(security_file_permission); + + int security_file_alloc(struct file *file) + { diff --git a/kernel/kernel/files/patches/aufs5/aufs5.15.36-20220509.patch b/kernel/kernel/files/patches/aufs5/aufs5.15.36-20220509.patch new file mode 100644 index 00000000..034b926d --- /dev/null +++ b/kernel/kernel/files/patches/aufs5/aufs5.15.36-20220509.patch @@ -0,0 +1,38475 @@ +diff -Naur null/Documentation/ABI/testing/debugfs-aufs linux-5.15.36/Documentation/ABI/testing/debugfs-aufs +--- /dev/null ++++ linux-5.15.36/Documentation/ABI/testing/debugfs-aufs 2022-05-10 16:51:39.862744220 +0300 +@@ -0,0 +1,55 @@ ++What: /debug/aufs/si_/ ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ Under /debug/aufs, a directory named si_ is created ++ per aufs mount, where is a unique id generated ++ internally. ++ ++What: /debug/aufs/si_/plink ++Date: Apr 2013 ++Contact: J. R. Okajima ++Description: ++ It has three lines and shows the information about the ++ pseudo-link. The first line is a single number ++ representing a number of buckets. The second line is a ++ number of pseudo-links per buckets (separated by a ++ blank). The last line is a single number representing a ++ total number of psedo-links. ++ When the aufs mount option 'noplink' is specified, it ++ will show "1\n0\n0\n". ++ ++What: /debug/aufs/si_/xib ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the consumed blocks by xib (External Inode Number ++ Bitmap), its block size and file size. ++ When the aufs mount option 'noxino' is specified, it ++ will be empty. About XINO files, see the aufs manual. ++ ++What: /debug/aufs/si_/xi ++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. ++ 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 ++Contact: J. R. Okajima ++Description: ++ It shows the consumed blocks by xigen (External Inode ++ Generation Table), its block size and file size. ++ If CONFIG_AUFS_EXPORT is disabled, this entry will not ++ be created. ++ When the aufs mount option 'noxino' is specified, it ++ will be empty. About XINO files, see the aufs manual. +diff -Naur null/Documentation/ABI/testing/sysfs-aufs linux-5.15.36/Documentation/ABI/testing/sysfs-aufs +--- /dev/null ++++ linux-5.15.36/Documentation/ABI/testing/sysfs-aufs 2022-05-10 16:51:39.863744220 +0300 +@@ -0,0 +1,31 @@ ++What: /sys/fs/aufs/si_/ ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ Under /sys/fs/aufs, a directory named si_ is created ++ per aufs mount, where is a unique id generated ++ internally. ++ ++What: /sys/fs/aufs/si_/br ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the abolute path of a member directory (which ++ is called branch) in aufs, and its permission. ++ ++What: /sys/fs/aufs/si_/brid ++Date: July 2013 ++Contact: J. R. Okajima ++Description: ++ It shows the id of a member directory (which is called ++ branch) in aufs. ++ ++What: /sys/fs/aufs/si_/xi_path ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the abolute path of XINO (External Inode Number ++ Bitmap, Translation Table and Generation Table) file ++ even if it is the default path. ++ When the aufs mount option 'noxino' is specified, it ++ will be empty. About XINO files, see the aufs manual. +diff -Naur null/Documentation/filesystems/aufs/design/01intro.txt linux-5.15.36/Documentation/filesystems/aufs/design/01intro.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/01intro.txt 2022-05-10 16:51:39.863744220 +0300 +@@ -0,0 +1,171 @@ ++ ++# Copyright (C) 2005-2021 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 ++# 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 . ++ ++Introduction ++---------------------------------------- ++ ++aufs [ei ju: ef es] | /ey-yoo-ef-es/ | [a u f s] ++1. abbrev. for "advanced multi-layered unification filesystem". ++2. abbrev. for "another unionfs". ++3. abbrev. for "auf das" in German which means "on the" in English. ++ Ex. "Butter aufs Brot"(G) means "butter onto bread"(E). ++ But "Filesystem aufs Filesystem" is hard to understand. ++4. abbrev. for "African Urban Fashion Show". ++ ++AUFS is a filesystem with features: ++- multi layered stackable unification filesystem, the member directory ++ is called as a branch. ++- branch permission and attribute, 'readonly', 'real-readonly', ++ 'readwrite', 'whiteout-able', 'link-able whiteout', etc. and their ++ combination. ++- internal "file copy-on-write". ++- logical deletion, whiteout. ++- dynamic branch manipulation, adding, deleting and changing permission. ++- allow bypassing aufs, user's direct branch access. ++- external inode number translation table and bitmap which maintains the ++ persistent aufs inode number. ++- seekable directory, including NFS readdir. ++- file mapping, mmap and sharing pages. ++- pseudo-link, hardlink over branches. ++- loopback mounted filesystem as a branch. ++- several policies to select one among multiple writable branches. ++- revert a single systemcall when an error occurs in aufs. ++- and more... ++ ++ ++Multi Layered Stackable Unification Filesystem ++---------------------------------------------------------------------- ++Most people already knows what it is. ++It is a filesystem which unifies several directories and provides a ++merged single directory. When users access a file, the access will be ++passed/re-directed/converted (sorry, I am not sure which English word is ++correct) to the real file on the member filesystem. The member ++filesystem is called 'lower filesystem' or 'branch' and has a mode ++'readonly' and 'readwrite.' And the deletion for a file on the lower ++readonly branch is handled by creating 'whiteout' on the upper writable ++branch. ++ ++On LKML, there have been discussions about UnionMount (Jan Blunck, ++Bharata B Rao and Valerie Aurora) and Unionfs (Erez Zadok). They took ++different approaches to implement the merged-view. ++The former tries putting it into VFS, and the latter implements as a ++separate filesystem. ++(If I misunderstand about these implementations, please let me know and ++I shall correct it. Because it is a long time ago when I read their ++source files last time). ++ ++UnionMount's approach will be able to small, but may be hard to share ++branches between several UnionMount since the whiteout in it is ++implemented in the inode on branch filesystem and always ++shared. According to Bharata's post, readdir does not seems to be ++finished yet. ++There are several missing features known in this implementations such as ++- for users, the inode number may change silently. eg. copy-up. ++- link(2) may break by copy-up. ++- read(2) may get an obsoleted filedata (fstat(2) too). ++- fcntl(F_SETLK) may be broken by copy-up. ++- unnecessary copy-up may happen, for example mmap(MAP_PRIVATE) after ++ open(O_RDWR). ++ ++In linux-3.18, "overlay" filesystem (formerly known as "overlayfs") was ++merged into mainline. This is another implementation of UnionMount as a ++separated filesystem. All the limitations and known problems which ++UnionMount are equally inherited to "overlay" filesystem. ++ ++Unionfs has a longer history. When I started implementing a stackable ++filesystem (Aug 2005), it already existed. It has virtual super_block, ++inode, dentry and file objects and they have an array pointing lower ++same kind objects. After contributing many patches for Unionfs, I ++re-started my project AUFS (Jun 2006). ++ ++In AUFS, the structure of filesystem resembles to Unionfs, but I ++implemented my own ideas, approaches and enhancements and it became ++totally different one. ++ ++Comparing DM snapshot and fs based implementation ++- the number of bytes to be copied between devices is much smaller. ++- the type of filesystem must be one and only. ++- the fs must be writable, no readonly fs, even for the lower original ++ device. so the compression fs will not be usable. but if we use ++ loopback mount, we may address this issue. ++ for instance, ++ mount /cdrom/squashfs.img /sq ++ losetup /sq/ext2.img ++ losetup /somewhere/cow ++ dmsetup "snapshot /dev/loop0 /dev/loop1 ..." ++- it will be difficult (or needs more operations) to extract the ++ difference between the original device and COW. ++- DM snapshot-merge may help a lot when users try merging. in the ++ fs-layer union, users will use rsync(1). ++ ++You may want to read my old paper "Filesystems in LiveCD" ++(http://aufs.sourceforge.net/aufs2/report/sq/sq.pdf). ++ ++ ++Several characters/aspects/persona of aufs ++---------------------------------------------------------------------- ++ ++Aufs has several characters, aspects or persona. ++1. a filesystem, callee of VFS helper ++2. sub-VFS, caller of VFS helper for branches ++3. a virtual filesystem which maintains persistent inode number ++4. reader/writer of files on branches such like an application ++ ++1. Callee of VFS Helper ++As an ordinary linux filesystem, aufs is a callee of VFS. For instance, ++unlink(2) from an application reaches sys_unlink() kernel function and ++then vfs_unlink() is called. vfs_unlink() is one of VFS helper and it ++calls filesystem specific unlink operation. Actually aufs implements the ++unlink operation but it behaves like a redirector. ++ ++2. Caller of VFS Helper for Branches ++aufs_unlink() passes the unlink request to the branch filesystem as if ++it were called from VFS. So the called unlink operation of the branch ++filesystem acts as usual. As a caller of VFS helper, aufs should handle ++every necessary pre/post operation for the branch filesystem. ++- acquire the lock for the parent dir on a branch ++- lookup in a branch ++- revalidate dentry on a branch ++- mnt_want_write() for a branch ++- vfs_unlink() for a branch ++- mnt_drop_write() for a branch ++- release the lock on a branch ++ ++3. Persistent Inode Number ++One of the most important issue for a filesystem is to maintain inode ++numbers. This is particularly important to support exporting a ++filesystem via NFS. Aufs is a virtual filesystem which doesn't have a ++backend block device for its own. But some storage is necessary to ++keep and maintain the inode numbers. It may be a large space and may not ++suit to keep in memory. Aufs rents some space from its first writable ++branch filesystem (by default) and creates file(s) on it. These files ++are created by aufs internally and removed soon (currently) keeping ++opened. ++Note: Because these files are removed, they are totally gone after ++ unmounting aufs. It means the inode numbers are not persistent ++ across unmount or reboot. I have a plan to make them really ++ persistent which will be important for aufs on NFS server. ++ ++4. Read/Write Files Internally (copy-on-write) ++Because a branch can be readonly, when you write a file on it, aufs will ++"copy-up" it to the upper writable branch internally. And then write the ++originally requested thing to the file. Generally kernel doesn't ++open/read/write file actively. In aufs, even a single write may cause a ++internal "file copy". This behaviour is very similar to cp(1) command. ++ ++Some people may think it is better to pass such work to user space ++helper, instead of doing in kernel space. Actually I am still thinking ++about it. But currently I have implemented it in kernel space. +diff -Naur null/Documentation/filesystems/aufs/design/02struct.txt linux-5.15.36/Documentation/filesystems/aufs/design/02struct.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/02struct.txt 2022-05-10 16:51:39.863744220 +0300 +@@ -0,0 +1,258 @@ ++ ++# Copyright (C) 2005-2021 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 ++# 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 . ++ ++Basic Aufs Internal Structure ++ ++Superblock/Inode/Dentry/File Objects ++---------------------------------------------------------------------- ++As like an ordinary filesystem, aufs has its own ++superblock/inode/dentry/file objects. All these objects have a ++dynamically allocated array and store the same kind of pointers to the ++lower filesystem, branch. ++For example, when you build a union with one readwrite branch and one ++readonly, mounted /au, /rw and /ro respectively. ++- /au = /rw + /ro ++- /ro/fileA exists but /rw/fileA ++ ++Aufs lookup operation finds /ro/fileA and gets dentry for that. These ++pointers are stored in a aufs dentry. The array in aufs dentry will be, ++- [0] = NULL (because /rw/fileA doesn't exist) ++- [1] = /ro/fileA ++ ++This style of an array is essentially same to the aufs ++superblock/inode/dentry/file objects. ++ ++Because aufs supports manipulating branches, ie. add/delete/change ++branches dynamically, these objects has its own generation. When ++branches are changed, the generation in aufs superblock is ++incremented. And a generation in other object are compared when it is ++accessed. When a generation in other objects are obsoleted, aufs ++refreshes the internal array. ++ ++ ++Superblock ++---------------------------------------------------------------------- ++Additionally aufs superblock has some data for policies to select one ++among multiple writable branches, XIB files, pseudo-links and kobject. ++See below in detail. ++About the policies which supports copy-down a directory, see ++wbr_policy.txt too. ++ ++ ++Branch and XINO(External Inode Number Translation Table) ++---------------------------------------------------------------------- ++Every branch has its own xino (external inode number translation table) ++file. The xino file is created and unlinked by aufs internally. When two ++members of a union exist on the same filesystem, they share the single ++xino file. ++The struct of a xino file is simple, just a sequence of aufs inode ++numbers which is indexed by the lower inode number. ++In the above sample, assume the inode number of /ro/fileA is i111 and ++aufs assigns the inode number i999 for fileA. Then aufs writes 999 as ++4(8) bytes at 111 * 4(8) bytes offset in the xino file. ++ ++When the inode numbers are not contiguous, the xino file will be sparse ++which has a hole in it and doesn't consume as much disk space as it ++might appear. If your branch filesystem consumes disk space for such ++holes, then you should specify 'xino=' option at mounting aufs. ++ ++Aufs has a mount option to free the disk blocks for such holes in XINO ++files on tmpfs or ramdisk. But it is not so effective actually. If you ++meet a problem of disk shortage due to XINO files, then you should try ++"tmpfs-ino.patch" (and "vfs-ino.patch" too) in aufs4-standalone.git. ++The patch localizes the assignment inumbers per tmpfs-mount and avoid ++the holes in XINO files. ++ ++Also a writable branch has three kinds of "whiteout bases". All these ++are existed when the branch is joined to aufs, and their names are ++whiteout-ed doubly, so that users will never see their names in aufs ++hierarchy. ++1. a regular file which will be hardlinked to all whiteouts. ++2. a directory to store a pseudo-link. ++3. a directory to store an "orphan"-ed file temporary. ++ ++1. Whiteout Base ++ When you remove a file on a readonly branch, aufs handles it as a ++ logical deletion and creates a whiteout on the upper writable branch ++ as a hardlink of this file in order not to consume inode on the ++ writable branch. ++2. Pseudo-link Dir ++ See below, Pseudo-link. ++3. Step-Parent Dir ++ When "fileC" exists on the lower readonly branch only and it is ++ opened and removed with its parent dir, and then user writes ++ something into it, then aufs copies-up fileC to this ++ directory. Because there is no other dir to store fileC. After ++ creating a file under this dir, the file is unlinked. ++ ++Because aufs supports manipulating branches, ie. add/delete/change ++dynamically, a branch has its own id. When the branch order changes, ++aufs finds the new index by searching the branch id. ++ ++ ++Pseudo-link ++---------------------------------------------------------------------- ++Assume "fileA" exists on the lower readonly branch only and it is ++hardlinked to "fileB" on the branch. When you write something to fileA, ++aufs copies-up it to the upper writable branch. Additionally aufs ++creates a hardlink under the Pseudo-link Directory of the writable ++branch. The inode of a pseudo-link is kept in aufs super_block as a ++simple list. If fileB is read after unlinking fileA, aufs returns ++filedata from the pseudo-link instead of the lower readonly ++branch. Because the pseudo-link is based upon the inode, to keep the ++inode number by xino (see above) is essentially necessary. ++ ++All the hardlinks under the Pseudo-link Directory of the writable branch ++should be restored in a proper location later. Aufs provides a utility ++to do this. The userspace helpers executed at remounting and unmounting ++aufs by default. ++During this utility is running, it puts aufs into the pseudo-link ++maintenance mode. In this mode, only the process which began the ++maintenance mode (and its child processes) is allowed to operate in ++aufs. Some other processes which are not related to the pseudo-link will ++be allowed to run too, but the rest have to return an error or wait ++until the maintenance mode ends. If a process already acquires an inode ++mutex (in VFS), it has to return an error. ++ ++ ++XIB(external inode number bitmap) ++---------------------------------------------------------------------- ++Addition to the xino file per a branch, aufs has an external inode number ++bitmap in a superblock object. It is also an internal file such like a ++xino file. ++It is a simple bitmap to mark whether the aufs inode number is in-use or ++not. ++To reduce the file I/O, aufs prepares a single memory page to cache xib. ++ ++As well as XINO files, aufs has a feature to truncate/refresh XIB to ++reduce the number of consumed disk blocks for these files. ++ ++ ++Virtual or Vertical Dir, and Readdir in Userspace ++---------------------------------------------------------------------- ++In order to support multiple layers (branches), aufs readdir operation ++constructs a virtual dir block on memory. For readdir, aufs calls ++vfs_readdir() internally for each dir on branches, merges their entries ++with eliminating the whiteout-ed ones, and sets it to file (dir) ++object. So the file object has its entry list until it is closed. The ++entry list will be updated when the file position is zero and becomes ++obsoleted. This decision is made in aufs automatically. ++ ++The dynamically allocated memory block for the name of entries has a ++unit of 512 bytes (by default) and stores the names contiguously (no ++padding). Another block for each entry is handled by kmem_cache too. ++During building dir blocks, aufs creates hash list and judging whether ++the entry is whiteouted by its upper branch or already listed. ++The merged result is cached in the corresponding inode object and ++maintained by a customizable life-time option. ++ ++Some people may call it can be a security hole or invite DoS attack ++since the opened and once readdir-ed dir (file object) holds its entry ++list and becomes a pressure for system memory. But I'd say it is similar ++to files under /proc or /sys. The virtual files in them also holds a ++memory page (generally) while they are opened. When an idea to reduce ++memory for them is introduced, it will be applied to aufs too. ++For those who really hate this situation, I've developed readdir(3) ++library which operates this merging in userspace. You just need to set ++LD_PRELOAD environment variable, and aufs will not consume no memory in ++kernel space for readdir(3). ++ ++ ++Workqueue ++---------------------------------------------------------------------- ++Aufs sometimes requires privilege access to a branch. For instance, ++in copy-up/down operation. When a user process is going to make changes ++to a file which exists in the lower readonly branch only, and the mode ++of one of ancestor directories may not be writable by a user ++process. Here aufs copy-up the file with its ancestors and they may ++require privilege to set its owner/group/mode/etc. ++This is a typical case of a application character of aufs (see ++Introduction). ++ ++Aufs uses workqueue synchronously for this case. It creates its own ++workqueue. The workqueue is a kernel thread and has privilege. Aufs ++passes the request to call mkdir or write (for example), and wait for ++its completion. This approach solves a problem of a signal handler ++simply. ++If aufs didn't adopt the workqueue and changed the privilege of the ++process, then the process may receive the unexpected SIGXFSZ or other ++signals. ++ ++Also aufs uses the system global workqueue ("events" kernel thread) too ++for asynchronous tasks, such like handling inotify/fsnotify, re-creating a ++whiteout base and etc. This is unrelated to a privilege. ++Most of aufs operation tries acquiring a rw_semaphore for aufs ++superblock at the beginning, at the same time waits for the completion ++of all queued asynchronous tasks. ++ ++ ++Whiteout ++---------------------------------------------------------------------- ++The whiteout in aufs is very similar to Unionfs's. That is represented ++by its filename. UnionMount takes an approach of a file mode, but I am ++afraid several utilities (find(1) or something) will have to support it. ++ ++Basically the whiteout represents "logical deletion" which stops aufs to ++lookup further, but also it represents "dir is opaque" which also stop ++further lookup. ++ ++In aufs, rmdir(2) and rename(2) for dir uses whiteout alternatively. ++In order to make several functions in a single systemcall to be ++revertible, aufs adopts an approach to rename a directory to a temporary ++unique whiteouted name. ++For example, in rename(2) dir where the target dir already existed, aufs ++renames the target dir to a temporary unique whiteouted name before the ++actual rename on a branch, and then handles other actions (make it opaque, ++update the attributes, etc). If an error happens in these actions, aufs ++simply renames the whiteouted name back and returns an error. If all are ++succeeded, aufs registers a function to remove the whiteouted unique ++temporary name completely and asynchronously to the system global ++workqueue. ++ ++ ++Copy-up ++---------------------------------------------------------------------- ++It is a well-known feature or concept. ++When user modifies a file on a readonly branch, aufs operate "copy-up" ++internally and makes change to the new file on the upper writable branch. ++When the trigger systemcall does not update the timestamps of the parent ++dir, aufs reverts it after copy-up. ++ ++ ++Move-down (aufs3.9 and later) ++---------------------------------------------------------------------- ++"Copy-up" is one of the essential feature in aufs. It copies a file from ++the lower readonly branch to the upper writable branch when a user ++changes something about the file. ++"Move-down" is an opposite action of copy-up. Basically this action is ++ran manually instead of automatically and internally. ++For desgin and implementation, aufs has to consider these issues. ++- whiteout for the file may exist on the lower branch. ++- ancestor directories may not exist on the lower branch. ++- diropq for the ancestor directories may exist on the upper branch. ++- free space on the lower branch will reduce. ++- another access to the file may happen during moving-down, including ++ UDBA (see "Revalidate Dentry and UDBA"). ++- the file should not be hard-linked nor pseudo-linked. they should be ++ handled by auplink utility later. ++ ++Sometimes users want to move-down a file from the upper writable branch ++to the lower readonly or writable branch. For instance, ++- the free space of the upper writable branch is going to run out. ++- create a new intermediate branch between the upper and lower branch. ++- etc. ++ ++For this purpose, use "aumvdown" command in aufs-util.git. +diff -Naur null/Documentation/filesystems/aufs/design/03atomic_open.txt linux-5.15.36/Documentation/filesystems/aufs/design/03atomic_open.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/03atomic_open.txt 2022-05-10 16:51:39.863744220 +0300 +@@ -0,0 +1,85 @@ ++ ++# Copyright (C) 2015-2021 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 ++# 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 . ++ ++Support for a branch who has its ->atomic_open() ++---------------------------------------------------------------------- ++The filesystems who implement its ->atomic_open() are not majority. For ++example NFSv4 does, and aufs should call NFSv4 ->atomic_open, ++particularly for open(O_CREAT|O_EXCL, 0400) case. Other than ++->atomic_open(), NFSv4 returns an error for this open(2). While I am not ++sure whether all filesystems who have ->atomic_open() behave like this, ++but NFSv4 surely returns the error. ++ ++In order to support ->atomic_open() for aufs, there are a few ++approaches. ++ ++A. Introduce aufs_atomic_open() ++ - calls one of VFS:do_last(), lookup_open() or atomic_open() for ++ branch fs. ++B. Introduce aufs_atomic_open() calling create, open and chmod. this is ++ an aufs user Pip Cet's approach ++ - calls aufs_create(), VFS finish_open() and notify_change(). ++ - pass fake-mode to finish_open(), and then correct the mode by ++ notify_change(). ++C. Extend aufs_open() to call branch fs's ->atomic_open() ++ - no aufs_atomic_open(). ++ - aufs_lookup() registers the TID to an aufs internal object. ++ - aufs_create() does nothing when the matching TID is registered, but ++ registers the mode. ++ - aufs_open() calls branch fs's ->atomic_open() when the matching ++ TID is registered. ++D. Extend aufs_open() to re-try branch fs's ->open() with superuser's ++ credential ++ - no aufs_atomic_open(). ++ - aufs_create() registers the TID to an internal object. this info ++ represents "this process created this file just now." ++ - when aufs gets EACCES from branch fs's ->open(), then confirm the ++ registered TID and re-try open() with superuser's credential. ++ ++Pros and cons for each approach. ++ ++A. ++ - straightforward but highly depends upon VFS internal. ++ - the atomic behavaiour is kept. ++ - some of parameters such as nameidata are hard to reproduce for ++ branch fs. ++ - large overhead. ++B. ++ - easy to implement. ++ - the atomic behavaiour is lost. ++C. ++ - the atomic behavaiour is kept. ++ - dirty and tricky. ++ - VFS checks whether the file is created correctly after calling ++ ->create(), which means this approach doesn't work. ++D. ++ - easy to implement. ++ - the atomic behavaiour is lost. ++ - to open a file with superuser's credential and give it to a user ++ process is a bad idea, since the file object keeps the credential ++ in it. It may affect LSM or something. This approach doesn't work ++ either. ++ ++The approach A is ideal, but it hard to implement. So here is a ++variation of A, which is to be implemented. ++ ++A-1. Introduce aufs_atomic_open() ++ - calls branch fs ->atomic_open() if exists. otherwise calls ++ vfs_create() and finish_open(). ++ - the demerit is that the several checks after branch fs ++ ->atomic_open() are lost. in the ordinary case, the checks are ++ done by VFS:do_last(), lookup_open() and atomic_open(). some can ++ be implemented in aufs, but not all I am afraid. +diff -Naur null/Documentation/filesystems/aufs/design/03lookup.txt linux-5.15.36/Documentation/filesystems/aufs/design/03lookup.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/03lookup.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,113 @@ ++ ++# Copyright (C) 2005-2021 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 ++# 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 . ++ ++Lookup in a Branch ++---------------------------------------------------------------------- ++Since aufs has a character of sub-VFS (see Introduction), it operates ++lookup for branches as VFS does. It may be a heavy work. But almost all ++lookup operation in aufs is the simplest case, ie. lookup only an entry ++directly connected to its parent. Digging down the directory hierarchy ++is unnecessary. VFS has a function lookup_one_len() for that use, and ++aufs calls it. ++ ++When a branch is a remote filesystem, aufs basically relies upon its ++->d_revalidate(), also aufs forces the hardest revalidate tests for ++them. ++For d_revalidate, aufs implements three levels of revalidate tests. See ++"Revalidate Dentry and UDBA" in detail. ++ ++ ++Test Only the Highest One for the Directory Permission (dirperm1 option) ++---------------------------------------------------------------------- ++Let's try case study. ++- aufs has two branches, upper readwrite and lower readonly. ++ /au = /rw + /ro ++- "dirA" exists under /ro, but /rw. and its mode is 0700. ++- user invoked "chmod a+rx /au/dirA" ++- the internal copy-up is activated and "/rw/dirA" is created and its ++ permission bits are set to world readable. ++- then "/au/dirA" becomes world readable? ++ ++In this case, /ro/dirA is still 0700 since it exists in readonly branch, ++or it may be a natively readonly filesystem. If aufs respects the lower ++branch, it should not respond readdir request from other users. But user ++allowed it by chmod. Should really aufs rejects showing the entries ++under /ro/dirA? ++ ++To be honest, I don't have a good solution for this case. So aufs ++implements 'dirperm1' and 'nodirperm1' mount options, and leave it to ++users. ++When dirperm1 is specified, aufs checks only the highest one for the ++directory permission, and shows the entries. Otherwise, as usual, checks ++every dir existing on all branches and rejects the request. ++ ++As a side effect, dirperm1 option improves the performance of aufs ++because the number of permission check is reduced when the number of ++branch is many. ++ ++ ++Revalidate Dentry and UDBA (User's Direct Branch Access) ++---------------------------------------------------------------------- ++Generally VFS helpers re-validate a dentry as a part of lookup. ++0. digging down the directory hierarchy. ++1. lock the parent dir by its i_mutex. ++2. lookup the final (child) entry. ++3. revalidate it. ++4. call the actual operation (create, unlink, etc.) ++5. unlock the parent dir ++ ++If the filesystem implements its ->d_revalidate() (step 3), then it is ++called. Actually aufs implements it and checks the dentry on a branch is ++still valid. ++But it is not enough. Because aufs has to release the lock for the ++parent dir on a branch at the end of ->lookup() (step 2) and ++->d_revalidate() (step 3) while the i_mutex of the aufs dir is still ++held by VFS. ++If the file on a branch is changed directly, eg. bypassing aufs, after ++aufs released the lock, then the subsequent operation may cause ++something unpleasant result. ++ ++This situation is a result of VFS architecture, ->lookup() and ++->d_revalidate() is separated. But I never say it is wrong. It is a good ++design from VFS's point of view. It is just not suitable for sub-VFS ++character in aufs. ++ ++Aufs supports such case by three level of revalidation which is ++selectable by user. ++1. Simple Revalidate ++ Addition to the native flow in VFS's, confirm the child-parent ++ relationship on the branch just after locking the parent dir on the ++ branch in the "actual operation" (step 4). When this validation ++ fails, aufs returns EBUSY. ->d_revalidate() (step 3) in aufs still ++ checks the validation of the dentry on branches. ++2. Monitor Changes Internally by Inotify/Fsnotify ++ Addition to above, in the "actual operation" (step 4) aufs re-lookup ++ the dentry on the branch, and returns EBUSY if it finds different ++ dentry. ++ Additionally, aufs sets the inotify/fsnotify watch for every dir on branches ++ during it is in cache. When the event is notified, aufs registers a ++ function to kernel 'events' thread by schedule_work(). And the ++ function sets some special status to the cached aufs dentry and inode ++ private data. If they are not cached, then aufs has nothing to ++ do. When the same file is accessed through aufs (step 0-3) later, ++ aufs will detect the status and refresh all necessary data. ++ In this mode, aufs has to ignore the event which is fired by aufs ++ itself. ++3. No Extra Validation ++ This is the simplest test and doesn't add any additional revalidation ++ test, and skip the revalidation in step 4. It is useful and improves ++ aufs performance when system surely hide the aufs branches from user, ++ by over-mounting something (or another method). +diff -Naur null/Documentation/filesystems/aufs/design/04branch.txt linux-5.15.36/Documentation/filesystems/aufs/design/04branch.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/04branch.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,74 @@ ++ ++# Copyright (C) 2005-2021 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 ++# 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 . ++ ++Branch Manipulation ++ ++Since aufs supports dynamic branch manipulation, ie. add/remove a branch ++and changing its permission/attribute, there are a lot of works to do. ++ ++ ++Add a Branch ++---------------------------------------------------------------------- ++o Confirm the adding dir exists outside of aufs, including loopback ++ mount, and its various attributes. ++o Initialize the xino file and whiteout bases if necessary. ++ See struct.txt. ++ ++o Check the owner/group/mode of the directory ++ When the owner/group/mode of the adding directory differs from the ++ existing branch, aufs issues a warning because it may impose a ++ security risk. ++ For example, when a upper writable branch has a world writable empty ++ top directory, a malicious user can create any files on the writable ++ branch directly, like copy-up and modify manually. If something like ++ /etc/{passwd,shadow} exists on the lower readonly branch but the upper ++ writable branch, and the writable branch is world-writable, then a ++ malicious guy may create /etc/passwd on the writable branch directly ++ and the infected file will be valid in aufs. ++ I am afraid it can be a security issue, but aufs can do nothing except ++ producing a warning. ++ ++ ++Delete a Branch ++---------------------------------------------------------------------- ++o Confirm the deleting branch is not busy ++ To be general, there is one merit to adopt "remount" interface to ++ manipulate branches. It is to discard caches. At deleting a branch, ++ aufs checks the still cached (and connected) dentries and inodes. If ++ there are any, then they are all in-use. An inode without its ++ corresponding dentry can be alive alone (for example, inotify/fsnotify case). ++ ++ For the cached one, aufs checks whether the same named entry exists on ++ other branches. ++ If the cached one is a directory, because aufs provides a merged view ++ to users, as long as one dir is left on any branch aufs can show the ++ dir to users. In this case, the branch can be removed from aufs. ++ Otherwise aufs rejects deleting the branch. ++ ++ If any file on the deleting branch is opened by aufs, then aufs ++ rejects deleting. ++ ++ ++Modify the Permission of a Branch ++---------------------------------------------------------------------- ++o Re-initialize or remove the xino file and whiteout bases if necessary. ++ See struct.txt. ++ ++o rw --> ro: Confirm the modifying branch is not busy ++ Aufs rejects the request if any of these conditions are true. ++ - a file on the branch is mmap-ed. ++ - a regular file on the branch is opened for write and there is no ++ same named entry on the upper branch. +diff -Naur null/Documentation/filesystems/aufs/design/05wbr_policy.txt linux-5.15.36/Documentation/filesystems/aufs/design/05wbr_policy.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/05wbr_policy.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,64 @@ ++ ++# Copyright (C) 2005-2021 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 ++# 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 . ++ ++Policies to Select One among Multiple Writable Branches ++---------------------------------------------------------------------- ++When the number of writable branch is more than one, aufs has to decide ++the target branch for file creation or copy-up. By default, the highest ++writable branch which has the parent (or ancestor) dir of the target ++file is chosen (top-down-parent policy). ++By user's request, aufs implements some other policies to select the ++writable branch, for file creation several policies, round-robin, ++most-free-space, and other policies. For copy-up, top-down-parent, ++bottom-up-parent, bottom-up and others. ++ ++As expected, the round-robin policy selects the branch in circular. When ++you have two writable branches and creates 10 new files, 5 files will be ++created for each branch. mkdir(2) systemcall is an exception. When you ++create 10 new directories, all will be created on the same branch. ++And the most-free-space policy selects the one which has most free ++space among the writable branches. The amount of free space will be ++checked by aufs internally, and users can specify its time interval. ++ ++The policies for copy-up is more simple, ++top-down-parent is equivalent to the same named on in create policy, ++bottom-up-parent selects the writable branch where the parent dir ++exists and the nearest upper one from the copyup-source, ++bottom-up selects the nearest upper writable branch from the ++copyup-source, regardless the existence of the parent dir. ++ ++There are some rules or exceptions to apply these policies. ++- If there is a readonly branch above the policy-selected branch and ++ the parent dir is marked as opaque (a variation of whiteout), or the ++ target (creating) file is whiteout-ed on the upper readonly branch, ++ then the result of the policy is ignored and the target file will be ++ created on the nearest upper writable branch than the readonly branch. ++- If there is a writable branch above the policy-selected branch and ++ the parent dir is marked as opaque or the target file is whiteouted ++ on the branch, then the result of the policy is ignored and the target ++ file will be created on the highest one among the upper writable ++ branches who has diropq or whiteout. In case of whiteout, aufs removes ++ it as usual. ++- link(2) and rename(2) systemcalls are exceptions in every policy. ++ They try selecting the branch where the source exists as possible ++ since copyup a large file will take long time. If it can't be, ++ ie. the branch where the source exists is readonly, then they will ++ follow the copyup policy. ++- There is an exception for rename(2) when the target exists. ++ If the rename target exists, aufs compares the index of the branches ++ where the source and the target exists and selects the higher ++ one. If the selected branch is readonly, then aufs follows the ++ copyup policy. +diff -Naur null/Documentation/filesystems/aufs/design/06dirren.dot linux-5.15.36/Documentation/filesystems/aufs/design/06dirren.dot +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/06dirren.dot 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,31 @@ ++ ++// to view this graph, run dot(1) command in GRAPHVIZ. ++ ++digraph G { ++node [shape=box]; ++whinfo [label="detailed info file\n(lower_brid_root-hinum, h_inum, namelen, old name)"]; ++ ++node [shape=oval]; ++ ++aufs_rename -> whinfo [label="store/remove"]; ++ ++node [shape=oval]; ++inode_list [label="h_inum list in branch\ncache"]; ++ ++node [shape=box]; ++whinode [label="h_inum list file"]; ++ ++node [shape=oval]; ++brmgmt [label="br_add/del/mod/umount"]; ++ ++brmgmt -> inode_list [label="create/remove"]; ++brmgmt -> whinode [label="load/store"]; ++ ++inode_list -> whinode [style=dashed,dir=both]; ++ ++aufs_rename -> inode_list [label="add/del"]; ++ ++aufs_lookup -> inode_list [label="search"]; ++ ++aufs_lookup -> whinfo [label="load/remove"]; ++} +diff -Naur null/Documentation/filesystems/aufs/design/06dirren.txt linux-5.15.36/Documentation/filesystems/aufs/design/06dirren.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/06dirren.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,102 @@ ++ ++# Copyright (C) 2017-2021 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 ++# 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 . ++ ++Special handling for renaming a directory (DIRREN) ++---------------------------------------------------------------------- ++First, let's assume we have a simple usecase. ++ ++- /u = /rw + /ro ++- /rw/dirA exists ++- /ro/dirA and /ro/dirA/file exist too ++- there is no dirB on both branches ++- a user issues rename("dirA", "dirB") ++ ++Now, what should aufs behave against this rename(2)? ++There are a few possible cases. ++ ++A. returns EROFS. ++ since dirA exists on a readonly branch which cannot be renamed. ++B. returns EXDEV. ++ it is possible to copy-up dirA (only the dir itself), but the child ++ entries ("file" in this case) should not be. it must be a bad ++ approach to copy-up recursively. ++C. returns a success. ++ even the branch /ro is readonly, aufs tries renaming it. Obviously it ++ is a violation of aufs' policy. ++D. construct an extra information which indicates that /ro/dirA should ++ be handled as the name of dirB. ++ overlayfs has a similar feature called REDIRECT. ++ ++Until now, aufs implements the case B only which returns EXDEV, and ++expects the userspace application behaves like mv(1) which tries ++issueing rename(2) recursively. ++ ++A new aufs feature called DIRREN is introduced which implements the case ++D. There are several "extra information" added. ++ ++1. detailed info per renamed directory ++ path: /rw/dirB/$AUFS_WH_DR_INFO_PFX. ++2. the inode-number list of directories on a branch ++ path: /rw/dirB/$AUFS_WH_DR_BRHINO ++ ++The filename of "detailed info per directory" represents the lower ++branch, and its format is ++- a type of the branch id ++ one of these. ++ + uuid (not implemented yet) ++ + fsid ++ + dev ++- the inode-number of the branch root dir ++ ++And it contains these info in a single regular file. ++- magic number ++- branch's inode-number of the logically renamed dir ++- the name of the before-renamed dir ++ ++The "detailed info per directory" file is created in aufs rename(2), and ++loaded in any lookup. ++The info is considered in lookup for the matching case only. Here ++"matching" means that the root of branch (in the info filename) is same ++to the current looking-up branch. After looking-up the before-renamed ++name, the inode-number is compared. And the matched dentry is used. ++ ++The "inode-number list of directories" is a regular file which contains ++simply the inode-numbers on the branch. The file is created or updated ++in removing the branch, and loaded in adding the branch. Its lifetime is ++equal to the branch. ++The list is refered in lookup, and when the current target inode is ++found in the list, the aufs tries loading the "detailed info per ++directory" and get the changed and valid name of the dir. ++ ++Theoretically these "extra informaiton" may be able to be put into XATTR ++in the dir inode. But aufs doesn't choose this way because ++1. XATTR may not be supported by the branch (or its configuration) ++2. XATTR may have its size limit. ++3. XATTR may be less easy to convert than a regular file, when the ++ format of the info is changed in the future. ++At the same time, I agree that the regular file approach is much slower ++than XATTR approach. So, in the future, aufs may take the XATTR or other ++better approach. ++ ++This DIRREN feature is enabled by aufs configuration, and is activated ++by a new mount option. ++ ++For the more complicated case, there is a work with UDBA option, which ++is to dected the direct access to the branches (by-passing aufs) and to ++maintain the cashes in aufs. Since a single cached aufs dentry may ++contains two names, before- and after-rename, the name comparision in ++UDBA handler may not work correctly. In this case, the behaviour will be ++equivalen to udba=reval case. +diff -Naur null/Documentation/filesystems/aufs/design/06fhsm.txt linux-5.15.36/Documentation/filesystems/aufs/design/06fhsm.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/06fhsm.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,120 @@ ++ ++# Copyright (C) 2011-2021 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 ++# 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, write to the Free Software ++# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ ++ ++File-based Hierarchical Storage Management (FHSM) ++---------------------------------------------------------------------- ++Hierarchical Storage Management (or HSM) is a well-known feature in the ++storage world. Aufs provides this feature as file-based with multiple ++writable branches, based upon the principle of "Colder, the Lower". ++Here the word "colder" means that the less used files, and "lower" means ++that the position in the order of the stacked branches vertically. ++These multiple writable branches are prioritized, ie. the topmost one ++should be the fastest drive and be used heavily. ++ ++o Characters in aufs FHSM story ++- aufs itself and a new branch attribute. ++- a new ioctl interface to move-down and to establish a connection with ++ the daemon ("move-down" is a converse of "copy-up"). ++- userspace tool and daemon. ++ ++The userspace daemon establishes a connection with aufs and waits for ++the notification. The notified information is very similar to struct ++statfs containing the number of consumed blocks and inodes. ++When the consumed blocks/inodes of a branch exceeds the user-specified ++upper watermark, the daemon activates its move-down process until the ++consumed blocks/inodes reaches the user-specified lower watermark. ++ ++The actual move-down is done by aufs based upon the request from ++user-space since we need to maintain the inode number and the internal ++pointer arrays in aufs. ++ ++Currently aufs FHSM handles the regular files only. Additionally they ++must not be hard-linked nor pseudo-linked. ++ ++ ++o Cowork of aufs and the user-space daemon ++ During the userspace daemon established the connection, aufs sends a ++ small notification to it whenever aufs writes something into the ++ writable branch. But it may cost high since aufs issues statfs(2) ++ internally. So user can specify a new option to cache the ++ info. Actually the notification is controlled by these factors. ++ + the specified cache time. ++ + classified as "force" by aufs internally. ++ Until the specified time expires, aufs doesn't send the info ++ except the forced cases. When aufs decide forcing, the info is always ++ notified to userspace. ++ For example, the number of free inodes is generally large enough and ++ the shortage of it happens rarely. So aufs doesn't force the ++ notification when creating a new file, directory and others. This is ++ the typical case which aufs doesn't force. ++ When aufs writes the actual filedata and the files consumes any of new ++ blocks, the aufs forces notifying. ++ ++ ++o Interfaces in aufs ++- New branch attribute. ++ + fhsm ++ Specifies that the branch is managed by FHSM feature. In other word, ++ participant in the FHSM. ++ When nofhsm is set to the branch, it will not be the source/target ++ branch of the move-down operation. This attribute is set ++ independently from coo and moo attributes, and if you want full ++ FHSM, you should specify them as well. ++- New mount option. ++ + fhsm_sec ++ Specifies a second to suppress many less important info to be ++ notified. ++- New ioctl. ++ + AUFS_CTL_FHSM_FD ++ create a new file descriptor which userspace can read the notification ++ (a subset of struct statfs) from aufs. ++- Module parameter 'brs' ++ It has to be set to 1. Otherwise the new mount option 'fhsm' will not ++ be set. ++- mount helpers /sbin/mount.aufs and /sbin/umount.aufs ++ When there are two or more branches with fhsm attributes, ++ /sbin/mount.aufs invokes the user-space daemon and /sbin/umount.aufs ++ terminates it. As a result of remounting and branch-manipulation, the ++ number of branches with fhsm attribute can be one. In this case, ++ /sbin/mount.aufs will terminate the user-space daemon. ++ ++ ++Finally the operation is done as these steps in kernel-space. ++- make sure that, ++ + no one else is using the file. ++ + the file is not hard-linked. ++ + the file is not pseudo-linked. ++ + the file is a regular file. ++ + the parent dir is not opaqued. ++- find the target writable branch. ++- make sure the file is not whiteout-ed by the upper (than the target) ++ branch. ++- make the parent dir on the target branch. ++- mutex lock the inode on the branch. ++- unlink the whiteout on the target branch (if exists). ++- lookup and create the whiteout-ed temporary name on the target branch. ++- copy the file as the whiteout-ed temporary name on the target branch. ++- rename the whiteout-ed temporary name to the original name. ++- unlink the file on the source branch. ++- maintain the internal pointer array and the external inode number ++ table (XINO). ++- maintain the timestamps and other attributes of the parent dir and the ++ file. ++ ++And of course, in every step, an error may happen. So the operation ++should restore the original file state after an error happens. +diff -Naur null/Documentation/filesystems/aufs/design/06mmap.txt linux-5.15.36/Documentation/filesystems/aufs/design/06mmap.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/06mmap.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,72 @@ ++ ++# Copyright (C) 2005-2021 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 ++# 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 . ++ ++mmap(2) -- File Memory Mapping ++---------------------------------------------------------------------- ++In aufs, the file-mapped pages are handled by a branch fs directly, no ++interaction with aufs. It means aufs_mmap() calls the branch fs's ++->mmap(). ++This approach is simple and good, but there is one problem. ++Under /proc, several entries show the mmapped files by its path (with ++device and inode number), and the printed path will be the path on the ++branch fs's instead of virtual aufs's. ++This is not a problem in most cases, but some utilities lsof(1) (and its ++user) may expect the path on aufs. ++ ++To address this issue, aufs adds a new member called vm_prfile in struct ++vm_area_struct (and struct vm_region). The original vm_file points to ++the file on the branch fs in order to handle everything correctly as ++usual. The new vm_prfile points to a virtual file in aufs, and the ++show-functions in procfs refers to vm_prfile if it is set. ++Also we need to maintain several other places where touching vm_file ++such like ++- fork()/clone() copies vma and the reference count of vm_file is ++ incremented. ++- merging vma maintains the ref count too. ++ ++This is not a good approach. It just fakes the printed path. But it ++leaves all behaviour around f_mapping unchanged. This is surely an ++advantage. ++Actually aufs had adopted another complicated approach which calls ++generic_file_mmap() and handles struct vm_operations_struct. In this ++approach, aufs met a hard problem and I could not solve it without ++switching the approach. ++ ++There may be one more another approach which is ++- bind-mount the branch-root onto the aufs-root internally ++- grab the new vfsmount (ie. struct mount) ++- lazy-umount the branch-root internally ++- in open(2) the aufs-file, open the branch-file with the hidden ++ vfsmount (instead of the original branch's vfsmount) ++- ideally this "bind-mount and lazy-umount" should be done atomically, ++ but it may be possible from userspace by the mount helper. ++ ++Adding the internal hidden vfsmount and using it in opening a file, the ++file path under /proc will be printed correctly. This approach looks ++smarter, but is not possible I am afraid. ++- aufs-root may be bind-mount later. when it happens, another hidden ++ vfsmount will be required. ++- it is hard to get the chance to bind-mount and lazy-umount ++ + in kernel-space, FS can have vfsmount in open(2) via ++ file->f_path, and aufs can know its vfsmount. But several locks are ++ already acquired, and if aufs tries to bind-mount and lazy-umount ++ here, then it may cause a deadlock. ++ + in user-space, bind-mount doesn't invoke the mount helper. ++- since /proc shows dev and ino, aufs has to give vma these info. it ++ means a new member vm_prinode will be necessary. this is essentially ++ equivalent to vm_prfile described above. ++ ++I have to give up this "looks-smater" approach. +diff -Naur null/Documentation/filesystems/aufs/design/06xattr.txt linux-5.15.36/Documentation/filesystems/aufs/design/06xattr.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/06xattr.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,96 @@ ++ ++# Copyright (C) 2014-2021 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 ++# 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, write to the Free Software ++# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ ++ ++Listing XATTR/EA and getting the value ++---------------------------------------------------------------------- ++For the inode standard attributes (owner, group, timestamps, etc.), aufs ++shows the values from the topmost existing file. This behaviour is good ++for the non-dir entries since the bahaviour exactly matches the shown ++information. But for the directories, aufs considers all the same named ++entries on the lower branches. Which means, if one of the lower entry ++rejects readdir call, then aufs returns an error even if the topmost ++entry allows it. This behaviour is necessary to respect the branch fs's ++security, but can make users confused since the user-visible standard ++attributes don't match the behaviour. ++To address this issue, aufs has a mount option called dirperm1 which ++checks the permission for the topmost entry only, and ignores the lower ++entry's permission. ++ ++A similar issue can happen around XATTR. ++getxattr(2) and listxattr(2) families behave as if dirperm1 option is ++always set. Otherwise these very unpleasant situation would happen. ++- listxattr(2) may return the duplicated entries. ++- users may not be able to remove or reset the XATTR forever, ++ ++ ++XATTR/EA support in the internal (copy,move)-(up,down) ++---------------------------------------------------------------------- ++Generally the extended attributes of inode are categorized as these. ++- "security" for LSM and capability. ++- "system" for posix ACL, 'acl' mount option is required for the branch ++ fs generally. ++- "trusted" for userspace, CAP_SYS_ADMIN is required. ++- "user" for userspace, 'user_xattr' mount option is required for the ++ branch fs generally. ++ ++Moreover there are some other categories. Aufs handles these rather ++unpopular categories as the ordinary ones, ie. there is no special ++condition nor exception. ++ ++In copy-up, the support for XATTR on the dst branch may differ from the ++src branch. In this case, the copy-up operation will get an error and ++the original user operation which triggered the copy-up will fail. It ++can happen that even all copy-up will fail. ++When both of src and dst branches support XATTR and if an error occurs ++during copying XATTR, then the copy-up should fail obviously. That is a ++good reason and aufs should return an error to userspace. But when only ++the src branch support that XATTR, aufs should not return an error. ++For example, the src branch supports ACL but the dst branch doesn't ++because the dst branch may natively un-support it or temporary ++un-support it due to "noacl" mount option. Of course, the dst branch fs ++may NOT return an error even if the XATTR is not supported. It is ++totally up to the branch fs. ++ ++Anyway when the aufs internal copy-up gets an error from the dst branch ++fs, then aufs tries removing the just copied entry and returns the error ++to the userspace. The worst case of this situation will be all copy-up ++will fail. ++ ++For the copy-up operation, there two basic approaches. ++- copy the specified XATTR only (by category above), and return the ++ error unconditionally if it happens. ++- copy all XATTR, and ignore the error on the specified category only. ++ ++In order to support XATTR and to implement the correct behaviour, aufs ++chooses the latter approach and introduces some new branch attributes, ++"icexsec", "icexsys", "icextr", "icexusr", and "icexoth". ++They correspond to the XATTR namespaces (see above). Additionally, to be ++convenient, "icex" is also provided which means all "icex*" attributes ++are set (here the word "icex" stands for "ignore copy-error on XATTR"). ++ ++The meaning of these attributes is to ignore the error from setting ++XATTR on that branch. ++Note that aufs tries copying all XATTR unconditionally, and ignores the ++error from the dst branch according to the specified attributes. ++ ++Some XATTR may have its default value. The default value may come from ++the parent dir or the environment. If the default value is set at the ++file creating-time, it will be overwritten by copy-up. ++Some contradiction may happen I am afraid. ++Do we need another attribute to stop copying XATTR? I am unsure. For ++now, aufs implements the branch attributes to ignore the error. +diff -Naur null/Documentation/filesystems/aufs/design/07export.txt linux-5.15.36/Documentation/filesystems/aufs/design/07export.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/07export.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,58 @@ ++ ++# Copyright (C) 2005-2021 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 ++# 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 . ++ ++Export Aufs via NFS ++---------------------------------------------------------------------- ++Here is an approach. ++- like xino/xib, add a new file 'xigen' which stores aufs inode ++ generation. ++- iget_locked(): initialize aufs inode generation for a new inode, and ++ store it in xigen file. ++- destroy_inode(): increment aufs inode generation and store it in xigen ++ file. it is necessary even if it is not unlinked, because any data of ++ inode may be changed by UDBA. ++- encode_fh(): for a root dir, simply return FILEID_ROOT. otherwise ++ build file handle by ++ + branch id (4 bytes) ++ + superblock generation (4 bytes) ++ + inode number (4 or 8 bytes) ++ + parent dir inode number (4 or 8 bytes) ++ + inode generation (4 bytes)) ++ + return value of exportfs_encode_fh() for the parent on a branch (4 ++ bytes) ++ + file handle for a branch (by exportfs_encode_fh()) ++- fh_to_dentry(): ++ + find the index of a branch from its id in handle, and check it is ++ still exist in aufs. ++ + 1st level: get the inode number from handle and search it in cache. ++ + 2nd level: if not found in cache, get the parent inode number from ++ the handle and search it in cache. and then open the found parent ++ dir, find the matching inode number by vfs_readdir() and get its ++ name, and call lookup_one_len() for the target dentry. ++ + 3rd level: if the parent dir is not cached, call ++ exportfs_decode_fh() for a branch and get the parent on a branch, ++ build a pathname of it, convert it a pathname in aufs, call ++ path_lookup(). now aufs gets a parent dir dentry, then handle it as ++ the 2nd level. ++ + to open the dir, aufs needs struct vfsmount. aufs keeps vfsmount ++ for every branch, but not itself. to get this, (currently) aufs ++ searches in current->nsproxy->mnt_ns list. it may not be a good ++ idea, but I didn't get other approach. ++ + test the generation of the gotten inode. ++- every inode operation: they may get EBUSY due to UDBA. in this case, ++ convert it into ESTALE for NFSD. ++- readdir(): call lockdep_on/off() because filldir in NFSD calls ++ lookup_one_len(), vfs_getattr(), encode_fh() and others. +diff -Naur null/Documentation/filesystems/aufs/design/08shwh.txt linux-5.15.36/Documentation/filesystems/aufs/design/08shwh.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/08shwh.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,52 @@ ++ ++# Copyright (C) 2005-2021 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 ++# 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 . ++ ++Show Whiteout Mode (shwh) ++---------------------------------------------------------------------- ++Generally aufs hides the name of whiteouts. But in some cases, to show ++them is very useful for users. For instance, creating a new middle layer ++(branch) by merging existing layers. ++ ++(borrowing aufs1 HOW-TO from a user, Michael Towers) ++When you have three branches, ++- Bottom: 'system', squashfs (underlying base system), read-only ++- Middle: 'mods', squashfs, read-only ++- Top: 'overlay', ram (tmpfs), read-write ++ ++The top layer is loaded at boot time and saved at shutdown, to preserve ++the changes made to the system during the session. ++When larger changes have been made, or smaller changes have accumulated, ++the size of the saved top layer data grows. At this point, it would be ++nice to be able to merge the two overlay branches ('mods' and 'overlay') ++and rewrite the 'mods' squashfs, clearing the top layer and thus ++restoring save and load speed. ++ ++This merging is simplified by the use of another aufs mount, of just the ++two overlay branches using the 'shwh' option. ++# mount -t aufs -o ro,shwh,br:/livesys/overlay=ro+wh:/livesys/mods=rr+wh \ ++ aufs /livesys/merge_union ++ ++A merged view of these two branches is then available at ++/livesys/merge_union, and the new feature is that the whiteouts are ++visible! ++Note that in 'shwh' mode the aufs mount must be 'ro', which will disable ++writing to all branches. Also the default mode for all branches is 'ro'. ++It is now possible to save the combined contents of the two overlay ++branches to a new squashfs, e.g.: ++# mksquashfs /livesys/merge_union /path/to/newmods.squash ++ ++This new squashfs archive can be stored on the boot device and the ++initramfs will use it to replace the old one at the next boot. +diff -Naur null/Documentation/filesystems/aufs/design/10dynop.txt linux-5.15.36/Documentation/filesystems/aufs/design/10dynop.txt +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/design/10dynop.txt 2022-05-10 16:51:39.864744220 +0300 +@@ -0,0 +1,47 @@ ++ ++# Copyright (C) 2010-2021 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 ++# 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 . ++ ++Dynamically customizable FS operations ++---------------------------------------------------------------------- ++Generally FS operations (struct inode_operations, struct ++address_space_operations, struct file_operations, etc.) are defined as ++"static const", but it never means that FS have only one set of ++operation. Some FS have multiple sets of them. For instance, ext2 has ++three sets, one for XIP, for NOBH, and for normal. ++Since aufs overrides and redirects these operations, sometimes aufs has ++to change its behaviour according to the branch FS type. More importantly ++VFS acts differently if a function (member in the struct) is set or ++not. It means aufs should have several sets of operations and select one ++among them according to the branch FS definition. ++ ++In order to solve this problem and not to affect the behaviour of VFS, ++aufs defines these operations dynamically. For instance, aufs defines ++dummy direct_IO function for struct address_space_operations, but it may ++not be set to the address_space_operations actually. When the branch FS ++doesn't have it, aufs doesn't set it to its address_space_operations ++while the function definition itself is still alive. So the behaviour ++itself will not change, and it will return an error when direct_IO is ++not set. ++ ++The lifetime of these dynamically generated operation object is ++maintained by aufs branch object. When the branch is removed from aufs, ++the reference counter of the object is decremented. When it reaches ++zero, the dynamically generated operation object will be freed. ++ ++This approach is designed to support AIO (io_submit), Direct I/O and ++XIP (DAX) mainly. ++Currently this approach is applied to address_space_operations for ++regular files only. +diff -Naur null/Documentation/filesystems/aufs/README linux-5.15.36/Documentation/filesystems/aufs/README +--- /dev/null ++++ linux-5.15.36/Documentation/filesystems/aufs/README 2022-05-10 16:51:39.863744220 +0300 +@@ -0,0 +1,396 @@ ++ ++Aufs5 -- advanced multi layered unification filesystem version 5.x ++http://aufs.sf.net ++Junjiro R. Okajima ++ ++ ++0. Introduction ++---------------------------------------- ++In the early days, aufs was entirely re-designed and re-implemented ++Unionfs Version 1.x series. Adding many original ideas, approaches, ++improvements and implementations, it became totally different from ++Unionfs while keeping the basic features. ++Later, Unionfs Version 2.x series began taking some of the same ++approaches to aufs1's. ++Unionfs was being developed by Professor Erez Zadok at Stony Brook ++University and his team. ++ ++Aufs5 supports linux-v5.0 and later, If you want older kernel version ++support, ++- for linux-v4.x series, try aufs4-linux.git or aufs4-standalone.git ++- for linux-v3.x series, try aufs3-linux.git or aufs3-standalone.git ++- for linux-v2.6.16 and later, try aufs2-2.6.git, aufs2-standalone.git ++ or aufs1 from CVS on SourceForge. ++ ++Note: it becomes clear that "Aufs was rejected. Let's give it up." ++ According to Christoph Hellwig, linux rejects all union-type ++ filesystems but UnionMount. ++ ++ ++PS. Al Viro seems have a plan to merge aufs as well as overlayfs and ++ UnionMount, and he pointed out an issue around a directory mutex ++ lock and aufs addressed it. But it is still unsure whether aufs will ++ be merged (or any other union solution). ++ ++ ++ ++1. Features ++---------------------------------------- ++- unite several directories into a single virtual filesystem. The member ++ directory is called as a branch. ++- you can specify the permission flags to the branch, which are 'readonly', ++ 'readwrite' and 'whiteout-able.' ++- by upper writable branch, internal copyup and whiteout, files/dirs on ++ readonly branch are modifiable logically. ++- dynamic branch manipulation, add, del. ++- etc... ++ ++Also there are many enhancements in aufs, such as: ++- test only the highest one for the directory permission (dirperm1) ++- copyup on open (coo=) ++- 'move' policy for copy-up between two writable branches, after ++ checking free space. ++- xattr, acl ++- readdir(3) in userspace. ++- keep inode number by external inode number table ++- keep the timestamps of file/dir in internal copyup operation ++- seekable directory, supporting NFS readdir. ++- whiteout is hardlinked in order to reduce the consumption of inodes ++ on branch ++- do not copyup, nor create a whiteout when it is unnecessary ++- revert a single systemcall when an error occurs in aufs ++- remount interface instead of ioctl ++- maintain /etc/mtab by an external command, /sbin/mount.aufs. ++- loopback mounted filesystem as a branch ++- kernel thread for removing the dir who has a plenty of whiteouts ++- support copyup sparse file (a file which has a 'hole' in it) ++- default permission flags for branches ++- selectable permission flags for ro branch, whether whiteout can ++ exist or not ++- export via NFS. ++- support /fs/aufs and /aufs. ++- support multiple writable branches, some policies to select one ++ among multiple writable branches. ++- a new semantics for link(2) and rename(2) to support multiple ++ writable branches. ++- no glibc changes are required. ++- pseudo hardlink (hardlink over branches) ++- allow a direct access manually to a file on branch, e.g. bypassing aufs. ++ including NFS or remote filesystem branch. ++- userspace wrapper for pathconf(3)/fpathconf(3) with _PC_LINK_MAX. ++- and more... ++ ++Currently these features are dropped temporary from aufs5. ++See design/08plan.txt in detail. ++- nested mount, i.e. aufs as readonly no-whiteout branch of another aufs ++ (robr) ++- statistics of aufs thread (/sys/fs/aufs/stat) ++ ++Features or just an idea in the future (see also design/*.txt), ++- reorder the branch index without del/re-add. ++- permanent xino files for NFSD ++- an option for refreshing the opened files after add/del branches ++- light version, without branch manipulation. (unnecessary?) ++- copyup in userspace ++- inotify in userspace ++- readv/writev ++ ++ ++2. Download ++---------------------------------------- ++There are three GIT trees for aufs5, aufs5-linux.git, ++aufs5-standalone.git, and aufs-util.git. Note that there is no "5" in ++"aufs-util.git." ++While the aufs-util is always necessary, you need either of aufs5-linux ++or aufs5-standalone. ++ ++The aufs5-linux tree includes the whole linux mainline GIT tree, ++git://git.kernel.org/.../torvalds/linux.git. ++And you cannot select CONFIG_AUFS_FS=m for this version, eg. you cannot ++build aufs5 as an external kernel module. ++Several extra patches are not included in this tree. Only ++aufs5-standalone tree contains them. They are described in the later ++section "Configuration and Compilation." ++ ++On the other hand, the aufs5-standalone tree has only aufs source files ++and necessary patches, and you can select CONFIG_AUFS_FS=m. ++But you need to apply all aufs patches manually. ++ ++You will find GIT branches whose name is in form of "aufs5.x" where "x" ++represents the linux kernel version, "linux-5.x". For instance, ++"aufs5.0" is for linux-5.0. For latest "linux-5.x-rcN", use ++"aufs5.x-rcN" branch. ++ ++o aufs5-linux tree ++$ git clone --reference /your/linux/git/tree \ ++ git://github.com/sfjro/aufs5-linux.git aufs5-linux.git ++- if you don't have linux GIT tree, then remove "--reference ..." ++$ cd aufs5-linux.git ++$ git checkout origin/aufs5.0 ++ ++Or You may want to directly git-pull aufs into your linux GIT tree, and ++leave the patch-work to GIT. ++$ cd /your/linux/git/tree ++$ git remote add aufs5 git://github.com/sfjro/aufs5-linux.git ++$ git fetch aufs5 ++$ git checkout -b my5.0 v5.0 ++$ (add your local change...) ++$ git pull aufs5 aufs5.0 ++- now you have v5.0 + your_changes + aufs5.0 in you my5.0 branch. ++- you may need to solve some conflicts between your_changes and ++ aufs5.0. in this case, git-rerere is recommended so that you can ++ solve the similar conflicts automatically when you upgrade to 5.1 or ++ later in the future. ++ ++o aufs5-standalone tree ++$ git clone git://github.com/sfjro/aufs5-standalone.git aufs5-standalone.git ++$ cd aufs5-standalone.git ++$ git checkout origin/aufs5.0 ++ ++o aufs-util tree ++$ git clone git://git.code.sf.net/p/aufs/aufs-util aufs-util.git ++- note that the public aufs-util.git is on SourceForge instead of ++ GitHUB. ++$ cd aufs-util.git ++$ git checkout origin/aufs5.0 ++ ++Note: The 5.x-rcN branch is to be used with `rc' kernel versions ONLY. ++The minor version number, 'x' in '5.x', of aufs may not always ++follow the minor version number of the kernel. ++Because changes in the kernel that cause the use of a new ++minor version number do not always require changes to aufs-util. ++ ++Since aufs-util has its own minor version number, you may not be ++able to find a GIT branch in aufs-util for your kernel's ++exact minor version number. ++In this case, you should git-checkout the branch for the ++nearest lower number. ++ ++For (an unreleased) example: ++If you are using "linux-5.10" and the "aufs5.10" branch ++does not exist in aufs-util repository, then "aufs5.9", "aufs5.8" ++or something numerically smaller is the branch for your kernel. ++ ++Also you can view all branches by ++ $ git branch -a ++ ++ ++3. Configuration and Compilation ++---------------------------------------- ++Make sure you have git-checkout'ed the correct branch. ++ ++For aufs5-linux tree, ++- enable CONFIG_AUFS_FS. ++- set other aufs configurations if necessary. ++- for aufs5.13 and later ++ Because aufs is not only an ordinary filesystem (callee of VFS), but ++ also a caller of VFS functions for branch filesystems, subclassing of ++ the internal locks for LOCKDEP is necessary. LOCKDEP is a debugging ++ feature of linux kernel. If you enable CONFIG_LOCKDEP, then you will ++ need to customize some LOCKDEP numbers. Here are what I use on my ++ test environment. ++ CONFIG_LOCKDEP_BITS=21 ++ CONFIG_LOCKDEP_CHAINS_BITS=21 ++ CONFIG_LOCKDEP_STACK_TRACE_BITS=24 ++ ++For aufs5-standalone tree, ++There are several ways to build. ++ ++1. ++- apply ./aufs5-kbuild.patch to your kernel source files. ++- apply ./aufs5-base.patch too. ++- apply ./aufs5-mmap.patch too. ++- apply ./aufs5-standalone.patch too, if you have a plan to set ++ CONFIG_AUFS_FS=m. otherwise you don't need ./aufs5-standalone.patch. ++- copy ./{Documentation,fs,include/uapi/linux/aufs_type.h} files to your ++ kernel source tree. Never copy $PWD/include/uapi/linux/Kbuild. ++- enable CONFIG_AUFS_FS, you can select either ++ =m or =y. ++- and build your kernel as usual. ++- install the built kernel. ++- install the header files too by "make headers_install" to the ++ directory where you specify. By default, it is $PWD/usr. ++ "make help" shows a brief note for headers_install. ++- and reboot your system. ++ ++2. ++- module only (CONFIG_AUFS_FS=m). ++- apply ./aufs5-base.patch to your kernel source files. ++- apply ./aufs5-mmap.patch too. ++- apply ./aufs5-standalone.patch too. ++- build your kernel, don't forget "make headers_install", and reboot. ++- edit ./config.mk and set other aufs configurations if necessary. ++ Note: You should read $PWD/fs/aufs/Kconfig carefully which describes ++ every aufs configurations. ++- build the module by simple "make". ++- you can specify ${KDIR} make variable which points to your kernel ++ source tree. ++- install the files ++ + run "make install" to install the aufs module, or copy the built ++ $PWD/aufs.ko to /lib/modules/... and run depmod -a (or reboot simply). ++ + run "make install_headers" (instead of headers_install) to install ++ the modified aufs header file (you can specify DESTDIR which is ++ available in aufs standalone version's Makefile only), or copy ++ $PWD/usr/include/linux/aufs_type.h to /usr/include/linux or wherever ++ you like manually. By default, the target directory is $PWD/usr. ++- no need to apply aufs5-kbuild.patch, nor copying source files to your ++ kernel source tree. ++ ++Note: The header file aufs_type.h is necessary to build aufs-util ++ as well as "make headers_install" in the kernel source tree. ++ headers_install is subject to be forgotten, but it is essentially ++ necessary, not only for building aufs-util. ++ You may not meet problems without headers_install in some older ++ version though. ++ ++And then, ++- read README in aufs-util, build and install it ++- note that your distribution may contain an obsoleted version of ++ aufs_type.h in /usr/include/linux or something. When you build aufs ++ utilities, make sure that your compiler refers the correct aufs header ++ file which is built by "make headers_install." ++- if you want to use readdir(3) in userspace or pathconf(3) wrapper, ++ then run "make install_ulib" too. And refer to the aufs manual in ++ detail. ++ ++There several other patches in aufs5-standalone.git. They are all ++optional. When you meet some problems, they will help you. ++- aufs5-loopback.patch ++ Supports a nested loopback mount in a branch-fs. This patch is ++ unnecessary until aufs produces a message like "you may want to try ++ another patch for loopback file". ++- vfs-ino.patch ++ Modifies a system global kernel internal function get_next_ino() in ++ order to stop assigning 0 for an inode-number. Not directly related to ++ aufs, but recommended generally. ++- tmpfs-idr.patch ++ Keeps the tmpfs inode number as the lowest value. Effective to reduce ++ the size of aufs XINO files for tmpfs branch. Also it prevents the ++ duplication of inode number, which is important for backup tools and ++ other utilities. When you find aufs XINO files for tmpfs branch ++ growing too much, try this patch. ++ ++ ++4. Usage ++---------------------------------------- ++At first, make sure aufs-util are installed, and please read the aufs ++manual, aufs.5 in aufs-util.git tree. ++$ man -l aufs.5 ++ ++And then, ++$ mkdir /tmp/rw /tmp/aufs ++# mount -t aufs -o br=/tmp/rw:${HOME} none /tmp/aufs ++ ++Here is another example. The result is equivalent. ++# mount -t aufs -o br=/tmp/rw=rw:${HOME}=ro none /tmp/aufs ++ Or ++# mount -t aufs -o br:/tmp/rw none /tmp/aufs ++# mount -o remount,append:${HOME} /tmp/aufs ++ ++Then, you can see whole tree of your home dir through /tmp/aufs. If ++you modify a file under /tmp/aufs, the one on your home directory is ++not affected, instead the same named file will be newly created under ++/tmp/rw. And all of your modification to a file will be applied to ++the one under /tmp/rw. This is called the file based Copy on Write ++(COW) method. ++Aufs mount options are described in aufs.5. ++If you run chroot or something and make your aufs as a root directory, ++then you need to customize the shutdown script. See the aufs manual in ++detail. ++ ++Additionally, there are some sample usages of aufs which are a ++diskless system with network booting, and LiveCD over NFS. ++See sample dir in CVS tree on SourceForge. ++ ++ ++5. Contact ++---------------------------------------- ++When you have any problems or strange behaviour in aufs, please let me ++know with: ++- /proc/mounts (instead of the output of mount(8)) ++- /sys/module/aufs/* ++- /sys/fs/aufs/* (if you have them) ++- /debug/aufs/* (if you have them) ++- linux kernel version ++ if your kernel is not plain, for example modified by distributor, ++ the url where i can download its source is necessary too. ++- aufs version which was printed at loading the module or booting the ++ system, instead of the date you downloaded. ++- configuration (define/undefine CONFIG_AUFS_xxx) ++- kernel configuration or /proc/config.gz (if you have it) ++- LSM (linux security module, if you are using) ++- behaviour which you think to be incorrect ++- actual operation, reproducible one is better ++- mailto: aufs-users at lists.sourceforge.net ++ ++Usually, I don't watch the Public Areas(Bugs, Support Requests, Patches, ++and Feature Requests) on SourceForge. Please join and write to ++aufs-users ML. ++ ++ ++6. Acknowledgements ++---------------------------------------- ++Thanks to everyone who have tried and are using aufs, whoever ++have reported a bug or any feedback. ++ ++Especially donators: ++Tomas Matejicek(slax.org) made a donation (much more than once). ++ Since Apr 2010, Tomas M (the author of Slax and Linux Live ++ scripts) is making "doubling" donations. ++ Unfortunately I cannot list all of the donators, but I really ++ appreciate. ++ It ends Aug 2010, but the ordinary donation URL is still available. ++ ++Dai Itasaka made a donation (2007/8). ++Chuck Smith made a donation (2008/4, 10 and 12). ++Henk Schoneveld made a donation (2008/9). ++Chih-Wei Huang, ASUS, CTC donated Eee PC 4G (2008/10). ++Francois Dupoux made a donation (2008/11). ++Bruno Cesar Ribas and Luis Carlos Erpen de Bona, C3SL serves public ++ aufs2 GIT tree (2009/2). ++William Grant made a donation (2009/3). ++Patrick Lane made a donation (2009/4). ++The Mail Archive (mail-archive.com) made donations (2009/5). ++Nippy Networks (Ed Wildgoose) made a donation (2009/7). ++New Dream Network, LLC (www.dreamhost.com) made a donation (2009/11). ++Pavel Pronskiy made a donation (2011/2). ++Iridium and Inmarsat satellite phone retailer (www.mailasail.com), Nippy ++ Networks (Ed Wildgoose) made a donation for hardware (2011/3). ++Max Lekomcev (DOM-TV project) made a donation (2011/7, 12, 2012/3, 6 and ++11). ++Sam Liddicott made a donation (2011/9). ++Era Scarecrow made a donation (2013/4). ++Bor Ratajc made a donation (2013/4). ++Alessandro Gorreta made a donation (2013/4). ++POIRETTE Marc made a donation (2013/4). ++Alessandro Gorreta made a donation (2013/4). ++lauri kasvandik made a donation (2013/5). ++"pemasu from Finland" made a donation (2013/7). ++The Parted Magic Project made a donation (2013/9 and 11). ++Pavel Barta made a donation (2013/10). ++Nikolay Pertsev made a donation (2014/5). ++James B made a donation (2014/7, 2015/7, and 2021/12). ++Stefano Di Biase made a donation (2014/8). ++Daniel Epellei made a donation (2015/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 ++helpful for me to keep on developing aufs. ++ ++ ++7. ++---------------------------------------- ++If you are an experienced user, no explanation is needed. Aufs is ++just a linux filesystem. ++ ++ ++Enjoy! ++ ++# Local variables: ; ++# mode: text; ++# End: ; +diff -Naur null/fs/aufs/aufs.h linux-5.15.36/fs/aufs/aufs.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/aufs.h 2022-05-10 16:51:39.866744220 +0300 +@@ -0,0 +1,62 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * all header files ++ */ ++ ++#ifndef __AUFS_H__ ++#define __AUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++#define AuStub(type, name, body, ...) \ ++ static inline type name(__VA_ARGS__) { body; } ++ ++#define AuStubVoid(name, ...) \ ++ AuStub(void, name, , __VA_ARGS__) ++#define AuStubInt0(name, ...) \ ++ AuStub(int, name, return 0, __VA_ARGS__) ++ ++#include "debug.h" ++ ++#include "branch.h" ++#include "cpup.h" ++#include "dcsub.h" ++#include "dbgaufs.h" ++#include "dentry.h" ++#include "dir.h" ++#include "dirren.h" ++#include "dynop.h" ++#include "file.h" ++#include "fstype.h" ++#include "hbl.h" ++#include "inode.h" ++#include "lcnt.h" ++#include "loop.h" ++#include "module.h" ++#include "opts.h" ++#include "rwsem.h" ++#include "super.h" ++#include "sysaufs.h" ++#include "vfsub.h" ++#include "whout.h" ++#include "wkq.h" ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_H__ */ +diff -Naur null/fs/aufs/branch.c linux-5.15.36/fs/aufs/branch.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/branch.c 2022-05-10 16:51:39.866744220 +0300 +@@ -0,0 +1,1427 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * branch management ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * free a single branch ++ */ ++static void au_br_do_free(struct au_branch *br) ++{ ++ int i; ++ struct au_wbr *wbr; ++ struct au_dykey **key; ++ ++ au_hnotify_fin_br(br); ++ /* always, regardless the mount option */ ++ au_dr_hino_free(&br->br_dirren); ++ au_xino_put(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) { ++ for (i = 0; i < AuBrWh_Last; i++) ++ dput(wbr->wbr_wh[i]); ++ AuDebugOn(atomic_read(&wbr->wbr_wh_running)); ++ AuRwDestroy(&wbr->wbr_wh_rwsem); ++ } ++ ++ if (br->br_fhsm) { ++ au_br_fhsm_fin(br->br_fhsm); ++ au_kfree_try_rcu(br->br_fhsm); ++ } ++ ++ key = br->br_dykey; ++ for (i = 0; i < AuBrDynOp; i++, key++) ++ if (*key) ++ au_dy_put(*key); ++ else ++ break; ++ ++ /* recursive lock, s_umount of branch's */ ++ /* synchronize_rcu(); */ /* why? */ ++ lockdep_off(); ++ path_put(&br->br_path); ++ lockdep_on(); ++ 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); ++} ++ ++/* ++ * frees all branches ++ */ ++void au_br_free(struct au_sbinfo *sbinfo) ++{ ++ aufs_bindex_t bmax; ++ struct au_branch **br; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ bmax = sbinfo->si_bbot + 1; ++ br = sbinfo->si_branch; ++ while (bmax--) ++ au_br_do_free(*br++); ++} ++ ++/* ++ * find the index of a branch which is specified by @br_id. ++ */ ++int au_br_index(struct super_block *sb, aufs_bindex_t br_id) ++{ ++ aufs_bindex_t bindex, bbot; ++ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) ++ if (au_sbr_id(sb, bindex) == br_id) ++ return bindex; ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * add a branch ++ */ ++ ++static int test_overlap(struct super_block *sb, struct dentry *h_adding, ++ struct dentry *h_root) ++{ ++ if (unlikely(h_adding == h_root ++ || au_test_loopback_overlap(sb, h_adding))) ++ return 1; ++ if (h_adding->d_sb != h_root->d_sb) ++ return 0; ++ return au_test_subdir(h_adding, h_root) ++ || au_test_subdir(h_root, h_adding); ++} ++ ++/* ++ * returns a newly allocated branch. @new_nbranch is a number of branches ++ * after adding a branch. ++ */ ++static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch, ++ int perm) ++{ ++ struct au_branch *add_branch; ++ struct dentry *root; ++ struct inode *inode; ++ int err; ++ ++ err = -ENOMEM; ++ add_branch = kzalloc(sizeof(*add_branch), GFP_NOFS); ++ if (unlikely(!add_branch)) ++ goto out; ++ 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_xino; ++ ++ if (au_br_writable(perm)) { ++ /* may be freed separately at changing the branch permission */ ++ add_branch->br_wbr = kzalloc(sizeof(*add_branch->br_wbr), ++ GFP_NOFS); ++ if (unlikely(!add_branch->br_wbr)) ++ goto out_hnotify; ++ } ++ ++ if (au_br_fhsm(perm)) { ++ err = au_fhsm_br_alloc(add_branch); ++ if (unlikely(err)) ++ goto out_wbr; ++ } ++ ++ root = sb->s_root; ++ err = au_sbr_realloc(au_sbi(sb), new_nbranch, /*may_shrink*/0); ++ if (!err) ++ err = au_di_realloc(au_di(root), new_nbranch, /*may_shrink*/0); ++ if (!err) { ++ inode = d_inode(root); ++ err = au_hinode_realloc(au_ii(inode), new_nbranch, ++ /*may_shrink*/0); ++ } ++ if (!err) ++ return add_branch; /* success */ ++ ++out_wbr: ++ au_kfree_rcu(add_branch->br_wbr); ++out_hnotify: ++ au_hnotify_fin_br(add_branch); ++out_xino: ++ au_xino_put(add_branch); ++out_br: ++ au_kfree_rcu(add_branch); ++out: ++ return ERR_PTR(err); ++} ++ ++/* ++ * test if the branch permission is legal or not. ++ */ ++static int test_br(struct inode *inode, int brperm, char *path) ++{ ++ int err; ++ ++ err = (au_br_writable(brperm) && IS_RDONLY(inode)); ++ if (!err) ++ goto out; ++ ++ err = -EINVAL; ++ pr_err("write permission for readonly mount or inode, %s\n", path); ++ ++out: ++ return err; ++} ++ ++/* ++ * returns: ++ * 0: success, the caller will add it ++ * plus: success, it is already unified, the caller should ignore it ++ * minus: error ++ */ ++static int test_add(struct super_block *sb, struct au_opt_add *add, int remount) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct dentry *root, *h_dentry; ++ struct inode *inode, *h_inode; ++ ++ root = sb->s_root; ++ bbot = au_sbbot(sb); ++ if (unlikely(bbot >= 0 ++ && au_find_dbindex(root, add->path.dentry) >= 0)) { ++ err = 1; ++ if (!remount) { ++ err = -EINVAL; ++ pr_err("%s duplicated\n", add->pathname); ++ } ++ goto out; ++ } ++ ++ err = -ENOSPC; /* -E2BIG; */ ++ if (unlikely(AUFS_BRANCH_MAX <= add->bindex ++ || AUFS_BRANCH_MAX - 1 <= bbot)) { ++ pr_err("number of branches exceeded %s\n", add->pathname); ++ goto out; ++ } ++ ++ err = -EDOM; ++ if (unlikely(add->bindex < 0 || bbot + 1 < add->bindex)) { ++ pr_err("bad index %d\n", add->bindex); ++ goto out; ++ } ++ ++ inode = d_inode(add->path.dentry); ++ err = -ENOENT; ++ if (unlikely(!inode->i_nlink)) { ++ pr_err("no existence %s\n", add->pathname); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ if (unlikely(inode->i_sb == sb)) { ++ pr_err("%s must be outside\n", add->pathname); ++ goto out; ++ } ++ ++ if (unlikely(au_test_fs_unsuppoted(inode->i_sb))) { ++ pr_err("unsupported filesystem, %s (%s)\n", ++ add->pathname, au_sbtype(inode->i_sb)); ++ goto out; ++ } ++ ++ if (unlikely(inode->i_sb->s_stack_depth)) { ++ pr_err("already stacked, %s (%s)\n", ++ add->pathname, au_sbtype(inode->i_sb)); ++ goto out; ++ } ++ ++ err = test_br(d_inode(add->path.dentry), add->perm, add->pathname); ++ if (unlikely(err)) ++ goto out; ++ ++ if (bbot < 0) ++ return 0; /* success */ ++ ++ err = -EINVAL; ++ for (bindex = 0; bindex <= bbot; bindex++) ++ if (unlikely(test_overlap(sb, add->path.dentry, ++ au_h_dptr(root, bindex)))) { ++ pr_err("%s is overlapped\n", add->pathname); ++ goto out; ++ } ++ ++ err = 0; ++ if (au_opt_test(au_mntflags(sb), WARN_PERM)) { ++ h_dentry = au_h_dptr(root, 0); ++ h_inode = d_inode(h_dentry); ++ if ((h_inode->i_mode & S_IALLUGO) != (inode->i_mode & S_IALLUGO) ++ || !uid_eq(h_inode->i_uid, inode->i_uid) ++ || !gid_eq(h_inode->i_gid, inode->i_gid)) ++ pr_warn("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n", ++ add->pathname, ++ i_uid_read(inode), i_gid_read(inode), ++ (inode->i_mode & S_IALLUGO), ++ i_uid_read(h_inode), i_gid_read(h_inode), ++ (h_inode->i_mode & S_IALLUGO)); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * initialize or clean the whiteouts for an adding branch ++ */ ++static int au_br_init_wh(struct super_block *sb, struct au_branch *br, ++ int new_perm) ++{ ++ int err, old_perm; ++ aufs_bindex_t bindex; ++ struct inode *h_inode; ++ struct au_wbr *wbr; ++ struct au_hinode *hdir; ++ struct dentry *h_dentry; ++ ++ err = vfsub_mnt_want_write(au_br_mnt(br)); ++ if (unlikely(err)) ++ goto out; ++ ++ wbr = br->br_wbr; ++ old_perm = br->br_perm; ++ br->br_perm = new_perm; ++ hdir = NULL; ++ h_inode = NULL; ++ bindex = au_br_index(sb, br->br_id); ++ if (0 <= bindex) { ++ hdir = au_hi(d_inode(sb->s_root), bindex); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ } else { ++ h_dentry = au_br_dentry(br); ++ h_inode = d_inode(h_dentry); ++ inode_lock_nested(h_inode, AuLsc_I_PARENT); ++ } ++ if (!wbr) ++ err = au_wh_init(br, sb); ++ else { ++ wbr_wh_write_lock(wbr); ++ err = au_wh_init(br, sb); ++ wbr_wh_write_unlock(wbr); ++ } ++ if (hdir) ++ au_hn_inode_unlock(hdir); ++ else ++ inode_unlock(h_inode); ++ vfsub_mnt_drop_write(au_br_mnt(br)); ++ br->br_perm = old_perm; ++ ++ if (!err && wbr && !au_br_writable(new_perm)) { ++ au_kfree_rcu(wbr); ++ br->br_wbr = NULL; ++ } ++ ++out: ++ return err; ++} ++ ++static int au_wbr_init(struct au_branch *br, struct super_block *sb, ++ int perm) ++{ ++ int err; ++ struct kstatfs kst; ++ struct au_wbr *wbr; ++ ++ wbr = br->br_wbr; ++ au_rw_init(&wbr->wbr_wh_rwsem); ++ atomic_set(&wbr->wbr_wh_running, 0); ++ ++ /* ++ * a limit for rmdir/rename a dir ++ * cf. AUFS_MAX_NAMELEN in include/uapi/linux/aufs_type.h ++ */ ++ err = vfs_statfs(&br->br_path, &kst); ++ if (unlikely(err)) ++ goto out; ++ err = -EINVAL; ++ if (kst.f_namelen >= NAME_MAX) ++ err = au_br_init_wh(sb, br, perm); ++ else ++ pr_err("%pd(%s), unsupported namelen %ld\n", ++ au_br_dentry(br), ++ au_sbtype(au_br_dentry(br)->d_sb), kst.f_namelen); ++ ++out: ++ return err; ++} ++ ++/* initialize a new branch */ ++static int au_br_init(struct au_branch *br, struct super_block *sb, ++ struct au_opt_add *add) ++{ ++ int err; ++ struct au_branch *brbase; ++ struct file *xf; ++ struct inode *h_inode; ++ ++ err = 0; ++ br->br_perm = add->perm; ++ br->br_path = add->path; /* set first, path_get() later */ ++ spin_lock_init(&br->br_dykey_lock); ++ 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); ++ ++ /* always, regardless the given option */ ++ err = au_dr_br_init(sb, br, &add->path); ++ if (unlikely(err)) ++ goto out_err; ++ ++ if (au_br_writable(add->perm)) { ++ err = au_wbr_init(br, sb, add->perm); ++ if (unlikely(err)) ++ goto out_err; ++ } ++ ++ 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_init_br(sb, br, h_inode->i_ino, &xf->f_path); ++ if (unlikely(err)) { ++ AuDebugOn(au_xino_file(br->br_xino, /*idx*/-1)); ++ goto out_err; ++ } ++ } ++ ++ sysaufs_br_init(br); ++ path_get(&br->br_path); ++ goto out; /* success */ ++ ++out_err: ++ memset(&br->br_path, 0, sizeof(br->br_path)); ++out: ++ return err; ++} ++ ++static void au_br_do_add_brp(struct au_sbinfo *sbinfo, aufs_bindex_t bindex, ++ struct au_branch *br, aufs_bindex_t bbot, ++ aufs_bindex_t amount) ++{ ++ struct au_branch **brp; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ brp = sbinfo->si_branch + bindex; ++ memmove(brp + 1, brp, sizeof(*brp) * amount); ++ *brp = br; ++ sbinfo->si_bbot++; ++ if (unlikely(bbot < 0)) ++ sbinfo->si_bbot = 0; ++} ++ ++static void au_br_do_add_hdp(struct au_dinfo *dinfo, aufs_bindex_t bindex, ++ aufs_bindex_t bbot, aufs_bindex_t amount) ++{ ++ struct au_hdentry *hdp; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ hdp = au_hdentry(dinfo, bindex); ++ memmove(hdp + 1, hdp, sizeof(*hdp) * amount); ++ au_h_dentry_init(hdp); ++ dinfo->di_bbot++; ++ if (unlikely(bbot < 0)) ++ dinfo->di_btop = 0; ++} ++ ++static void au_br_do_add_hip(struct au_iinfo *iinfo, aufs_bindex_t bindex, ++ aufs_bindex_t bbot, aufs_bindex_t amount) ++{ ++ struct au_hinode *hip; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ hip = au_hinode(iinfo, bindex); ++ memmove(hip + 1, hip, sizeof(*hip) * amount); ++ au_hinode_init(hip); ++ iinfo->ii_bbot++; ++ if (unlikely(bbot < 0)) ++ iinfo->ii_btop = 0; ++} ++ ++static void au_br_do_add(struct super_block *sb, struct au_branch *br, ++ aufs_bindex_t bindex) ++{ ++ struct dentry *root, *h_dentry; ++ struct inode *root_inode, *h_inode; ++ aufs_bindex_t bbot, amount; ++ ++ root = sb->s_root; ++ root_inode = d_inode(root); ++ bbot = au_sbbot(sb); ++ amount = bbot + 1 - bindex; ++ h_dentry = au_br_dentry(br); ++ au_sbilist_lock(); ++ au_br_do_add_brp(au_sbi(sb), bindex, br, bbot, amount); ++ au_br_do_add_hdp(au_di(root), bindex, bbot, amount); ++ au_br_do_add_hip(au_ii(root_inode), bindex, bbot, amount); ++ au_set_h_dptr(root, bindex, dget(h_dentry)); ++ h_inode = d_inode(h_dentry); ++ au_set_h_iptr(root_inode, bindex, au_igrab(h_inode), /*flags*/0); ++ au_sbilist_unlock(); ++} ++ ++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount) ++{ ++ int err; ++ aufs_bindex_t bbot, add_bindex; ++ struct dentry *root, *h_dentry; ++ struct inode *root_inode; ++ struct au_branch *add_branch; ++ ++ root = sb->s_root; ++ root_inode = d_inode(root); ++ IMustLock(root_inode); ++ IiMustWriteLock(root_inode); ++ err = test_add(sb, add, remount); ++ if (unlikely(err < 0)) ++ goto out; ++ if (err) { ++ err = 0; ++ goto out; /* success */ ++ } ++ ++ bbot = au_sbbot(sb); ++ add_branch = au_br_alloc(sb, bbot + 2, add->perm); ++ err = PTR_ERR(add_branch); ++ if (IS_ERR(add_branch)) ++ goto out; ++ ++ err = au_br_init(add_branch, sb, add); ++ if (unlikely(err)) { ++ au_br_do_free(add_branch); ++ goto out; ++ } ++ ++ add_bindex = 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) { ++ au_cpup_attr_all(root_inode, /*force*/1); ++ sb->s_maxbytes = h_dentry->d_sb->s_maxbytes; ++ } else ++ au_add_nlink(root_inode, d_inode(h_dentry)); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static unsigned long long au_farray_cb(struct super_block *sb, void *a, ++ unsigned long long max __maybe_unused, ++ void *arg) ++{ ++ unsigned long long n; ++ struct file **p, *f; ++ struct hlist_bl_head *files; ++ struct hlist_bl_node *pos; ++ struct au_finfo *finfo; ++ ++ n = 0; ++ p = a; ++ files = &au_sbi(sb)->si_files; ++ hlist_bl_lock(files); ++ hlist_bl_for_each_entry(finfo, pos, files, fi_hlist) { ++ f = finfo->fi_file; ++ if (file_count(f) ++ && !special_file(file_inode(f)->i_mode)) { ++ get_file(f); ++ *p++ = f; ++ n++; ++ AuDebugOn(n > max); ++ } ++ } ++ hlist_bl_unlock(files); ++ ++ return n; ++} ++ ++static struct file **au_farray_alloc(struct super_block *sb, ++ unsigned long long *max) ++{ ++ 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); ++} ++ ++static void au_farray_free(struct file **a, unsigned long long max) ++{ ++ unsigned long long ull; ++ ++ for (ull = 0; ull < max; ull++) ++ if (a[ull]) ++ fput(a[ull]); ++ kvfree(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * delete a branch ++ */ ++ ++/* to show the line number, do not make it inlined function */ ++#define AuVerbose(do_info, fmt, ...) do { \ ++ if (do_info) \ ++ pr_info(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++static int au_test_ibusy(struct inode *inode, aufs_bindex_t btop, ++ aufs_bindex_t bbot) ++{ ++ return (inode && !S_ISDIR(inode->i_mode)) || btop == bbot; ++} ++ ++static int au_test_dbusy(struct dentry *dentry, aufs_bindex_t btop, ++ aufs_bindex_t bbot) ++{ ++ return au_test_ibusy(d_inode(dentry), btop, bbot); ++} ++ ++/* ++ * test if the branch is deletable or not. ++ */ ++static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex, ++ unsigned int sigen, const unsigned int verbose) ++{ ++ int err, i, j, ndentry; ++ aufs_bindex_t btop, bbot; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry *d; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, root, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ for (i = 0; !err && i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = 0; !err && j < ndentry; j++) { ++ d = dpage->dentries[j]; ++ AuDebugOn(au_dcount(d) <= 0); ++ if (!au_digen_test(d, sigen)) { ++ di_read_lock_child(d, AuLock_IR); ++ if (unlikely(au_dbrange_test(d))) { ++ di_read_unlock(d, AuLock_IR); ++ continue; ++ } ++ } else { ++ di_write_lock_child(d); ++ if (unlikely(au_dbrange_test(d))) { ++ di_write_unlock(d); ++ continue; ++ } ++ err = au_reval_dpath(d, sigen); ++ if (!err) ++ di_downgrade_lock(d, AuLock_IR); ++ else { ++ di_write_unlock(d); ++ break; ++ } ++ } ++ ++ /* AuDbgDentry(d); */ ++ btop = au_dbtop(d); ++ bbot = au_dbbot(d); ++ if (btop <= bindex ++ && bindex <= bbot ++ && au_h_dptr(d, bindex) ++ && au_test_dbusy(d, btop, bbot)) { ++ err = -EBUSY; ++ AuVerbose(verbose, "busy %pd\n", d); ++ AuDbgDentry(d); ++ } ++ di_read_unlock(d, AuLock_IR); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex, ++ unsigned int sigen, const unsigned int verbose) ++{ ++ int err; ++ unsigned long long max, ull; ++ struct inode *i, **array; ++ aufs_bindex_t btop, bbot; ++ ++ array = au_iarray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ AuDbg("b%d\n", bindex); ++ for (ull = 0; !err && ull < max; ull++) { ++ i = array[ull]; ++ if (unlikely(!i)) ++ break; ++ if (i->i_ino == AUFS_ROOT_INO) ++ continue; ++ ++ /* AuDbgInode(i); */ ++ if (au_iigen(i, NULL) == sigen) ++ ii_read_lock_child(i); ++ else { ++ ii_write_lock_child(i); ++ err = au_refresh_hinode_self(i); ++ au_iigen_dec(i); ++ if (!err) ++ ii_downgrade_lock(i); ++ else { ++ ii_write_unlock(i); ++ break; ++ } ++ } ++ ++ btop = au_ibtop(i); ++ bbot = au_ibbot(i); ++ if (btop <= bindex ++ && bindex <= bbot ++ && au_h_iptr(i, bindex) ++ && au_test_ibusy(i, btop, bbot)) { ++ err = -EBUSY; ++ AuVerbose(verbose, "busy i%lu\n", i->i_ino); ++ AuDbgInode(i); ++ } ++ ii_read_unlock(i); ++ } ++ au_iarray_free(array, max); ++ ++out: ++ return err; ++} ++ ++static int test_children_busy(struct dentry *root, aufs_bindex_t bindex, ++ const unsigned int verbose) ++{ ++ int err; ++ unsigned int sigen; ++ ++ sigen = au_sigen(root->d_sb); ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(d_inode(root)); ++ di_write_unlock(root); ++ err = test_dentry_busy(root, bindex, sigen, verbose); ++ if (!err) ++ err = test_inode_busy(root->d_sb, bindex, sigen, verbose); ++ di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */ ++ ++ return err; ++} ++ ++static int test_dir_busy(struct file *file, aufs_bindex_t br_id, ++ struct file **to_free, int *idx) ++{ ++ int err; ++ unsigned char matched, root; ++ aufs_bindex_t bindex, bbot; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ ++ err = 0; ++ root = IS_ROOT(file->f_path.dentry); ++ if (root) { ++ get_file(file); ++ to_free[*idx] = file; ++ (*idx)++; ++ goto out; ++ } ++ ++ matched = 0; ++ fidir = au_fi(file)->fi_hdir; ++ AuDebugOn(!fidir); ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); bindex <= bbot; bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ if (!hfile->hf_file) ++ continue; ++ ++ if (hfile->hf_br->br_id == br_id) { ++ matched = 1; ++ break; ++ } ++ } ++ if (matched) ++ err = -EBUSY; ++ ++out: ++ return err; ++} ++ ++static int test_file_busy(struct super_block *sb, aufs_bindex_t br_id, ++ struct file **to_free, int opened) ++{ ++ int err, idx; ++ unsigned long long ull, max; ++ aufs_bindex_t btop; ++ struct file *file, **array; ++ struct dentry *root; ++ struct au_hfile *hfile; ++ ++ array = au_farray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ idx = 0; ++ root = sb->s_root; ++ di_write_unlock(root); ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ fi_read_lock(file); ++ btop = au_fbtop(file); ++ if (!d_is_dir(file->f_path.dentry)) { ++ hfile = &au_fi(file)->fi_htop; ++ if (hfile->hf_br->br_id == br_id) ++ err = -EBUSY; ++ } else ++ err = test_dir_busy(file, br_id, to_free, &idx); ++ fi_read_unlock(file); ++ if (unlikely(err)) ++ break; ++ } ++ di_write_lock_child(root); ++ au_farray_free(array, max); ++ AuDebugOn(idx > opened); ++ ++out: ++ return err; ++} ++ ++static void br_del_file(struct file **to_free, unsigned long long opened, ++ aufs_bindex_t br_id) ++{ ++ unsigned long long ull; ++ aufs_bindex_t bindex, btop, bbot, bfound; ++ struct file *file; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ ++ for (ull = 0; ull < opened; ull++) { ++ file = to_free[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ AuDebugOn(!d_is_dir(file->f_path.dentry)); ++ bfound = -1; ++ fidir = au_fi(file)->fi_hdir; ++ AuDebugOn(!fidir); ++ fi_write_lock(file); ++ btop = au_fbtop(file); ++ bbot = au_fbbot_dir(file); ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ if (!hfile->hf_file) ++ continue; ++ ++ if (hfile->hf_br->br_id == br_id) { ++ bfound = bindex; ++ break; ++ } ++ } ++ AuDebugOn(bfound < 0); ++ au_set_h_fptr(file, bfound, NULL); ++ if (bfound == btop) { ++ for (btop++; btop <= bbot; btop++) ++ if (au_hf_dir(file, btop)) { ++ au_set_fbtop(file, btop); ++ break; ++ } ++ } ++ fi_write_unlock(file); ++ } ++} ++ ++static void au_br_do_del_brp(struct au_sbinfo *sbinfo, ++ const aufs_bindex_t bindex, ++ const aufs_bindex_t bbot) ++{ ++ struct au_branch **brp, **p; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ brp = sbinfo->si_branch + bindex; ++ if (bindex < bbot) ++ memmove(brp, brp + 1, sizeof(*brp) * (bbot - bindex)); ++ sbinfo->si_branch[0 + bbot] = NULL; ++ sbinfo->si_bbot--; ++ ++ p = au_krealloc(sbinfo->si_branch, sizeof(*p) * bbot, AuGFP_SBILIST, ++ /*may_shrink*/1); ++ if (p) ++ sbinfo->si_branch = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex, ++ const aufs_bindex_t bbot) ++{ ++ struct au_hdentry *hdp, *p; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ hdp = au_hdentry(dinfo, bindex); ++ if (bindex < bbot) ++ memmove(hdp, hdp + 1, sizeof(*hdp) * (bbot - bindex)); ++ /* au_h_dentry_init(au_hdentry(dinfo, bbot); */ ++ dinfo->di_bbot--; ++ ++ p = au_krealloc(dinfo->di_hdentry, sizeof(*p) * bbot, AuGFP_SBILIST, ++ /*may_shrink*/1); ++ if (p) ++ dinfo->di_hdentry = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex, ++ const aufs_bindex_t bbot) ++{ ++ struct au_hinode *hip, *p; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ hip = au_hinode(iinfo, bindex); ++ if (bindex < bbot) ++ memmove(hip, hip + 1, sizeof(*hip) * (bbot - bindex)); ++ /* au_hinode_init(au_hinode(iinfo, bbot)); */ ++ iinfo->ii_bbot--; ++ ++ p = au_krealloc(iinfo->ii_hinode, sizeof(*p) * bbot, AuGFP_SBILIST, ++ /*may_shrink*/1); ++ if (p) ++ iinfo->ii_hinode = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_branch *br) ++{ ++ aufs_bindex_t bbot; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root, *h_root; ++ struct inode *inode, *h_inode; ++ struct au_hinode *hinode; ++ ++ SiMustWriteLock(sb); ++ ++ root = sb->s_root; ++ inode = d_inode(root); ++ sbinfo = au_sbi(sb); ++ bbot = sbinfo->si_bbot; ++ ++ h_root = au_h_dptr(root, bindex); ++ hinode = au_hi(inode, bindex); ++ h_inode = au_igrab(hinode->hi_inode); ++ au_hiput(hinode); ++ ++ au_sbilist_lock(); ++ au_br_do_del_brp(sbinfo, bindex, bbot); ++ au_br_do_del_hdp(au_di(root), bindex, bbot); ++ au_br_do_del_hip(au_ii(inode), bindex, bbot); ++ au_sbilist_unlock(); ++ ++ /* ignore an error */ ++ au_dr_br_fin(sb, br); /* always, regardless the mount option */ ++ ++ dput(h_root); ++ iput(h_inode); ++ au_br_do_free(br); ++} ++ ++static unsigned long long empty_cb(struct super_block *sb, void *array, ++ unsigned long long max, void *arg) ++{ ++ return max; ++} ++ ++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) ++{ ++ int err, rerr, i; ++ unsigned long long opened; ++ unsigned int mnt_flags; ++ aufs_bindex_t bindex, bbot, br_id; ++ unsigned char do_wh, verbose; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *root; ++ struct file **to_free; ++ ++ err = 0; ++ opened = 0; ++ to_free = NULL; ++ root = sb->s_root; ++ bindex = au_find_dbindex(root, del->h_path.dentry); ++ if (bindex < 0) { ++ if (remount) ++ goto out; /* success */ ++ err = -ENOENT; ++ pr_err("%s no such branch\n", del->pathname); ++ goto out; ++ } ++ AuDbg("bindex b%d\n", bindex); ++ ++ err = -EBUSY; ++ mnt_flags = au_mntflags(sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ bbot = au_sbbot(sb); ++ if (unlikely(!bbot)) { ++ 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_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); ++ if (IS_ERR(to_free)) ++ goto out; ++ ++ err = test_file_busy(sb, br_id, to_free, opened); ++ if (unlikely(err)) { ++ AuVerbose(verbose, "%llu file(s) opened\n", opened); ++ goto out; ++ } ++ } ++ ++ wbr = br->br_wbr; ++ do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph); ++ if (do_wh) { ++ /* instead of WbrWhMustWriteLock(wbr) */ ++ SiMustWriteLock(sb); ++ for (i = 0; i < AuBrWh_Last; i++) { ++ dput(wbr->wbr_wh[i]); ++ wbr->wbr_wh[i] = NULL; ++ } ++ } ++ ++ err = test_children_busy(root, bindex, verbose); ++ if (unlikely(err)) { ++ if (do_wh) ++ goto out_wh; ++ goto out; ++ } ++ ++ err = 0; ++ if (to_free) { ++ /* ++ * now we confirmed the branch is deletable. ++ * let's free the remaining opened dirs on the branch. ++ */ ++ di_write_unlock(root); ++ br_del_file(to_free, opened, br_id); ++ di_write_lock_child(root); ++ } ++ ++ 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); ++ sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes; ++ } else ++ au_sub_nlink(d_inode(root), d_inode(del->h_path.dentry)); ++ if (au_opt_test(mnt_flags, PLINK)) ++ au_plink_half_refresh(sb, br_id); ++ ++ goto out; /* success */ ++ ++out_wh: ++ /* revert */ ++ rerr = au_br_init_wh(sb, br, br->br_perm); ++ if (rerr) ++ pr_warn("failed re-creating base whiteout, %s. (%d)\n", ++ del->pathname, rerr); ++out: ++ if (to_free) ++ au_farray_free(to_free, opened); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_ibusy(struct super_block *sb, struct aufs_ibusy __user *arg) ++{ ++ int err; ++ aufs_bindex_t btop, bbot; ++ struct aufs_ibusy ibusy; ++ struct inode *inode, *h_inode; ++ ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = copy_from_user(&ibusy, arg, sizeof(ibusy)); ++ if (!err) ++ /* VERIFY_WRITE */ ++ err = !access_ok(&arg->h_ino, sizeof(arg->h_ino)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ si_read_lock(sb, AuLock_FLUSH); ++ if (unlikely(ibusy.bindex < 0 || ibusy.bindex > au_sbbot(sb))) ++ goto out_unlock; ++ ++ err = 0; ++ ibusy.h_ino = 0; /* invalid */ ++ inode = ilookup(sb, ibusy.ino); ++ if (!inode ++ || inode->i_ino == AUFS_ROOT_INO ++ || au_is_bad_inode(inode)) ++ goto out_unlock; ++ ++ ii_read_lock_child(inode); ++ btop = au_ibtop(inode); ++ bbot = au_ibbot(inode); ++ if (btop <= ibusy.bindex && ibusy.bindex <= bbot) { ++ h_inode = au_h_iptr(inode, ibusy.bindex); ++ if (h_inode && au_test_ibusy(inode, btop, bbot)) ++ ibusy.h_ino = h_inode->i_ino; ++ } ++ ii_read_unlock(inode); ++ iput(inode); ++ ++out_unlock: ++ si_read_unlock(sb); ++ if (!err) { ++ err = __put_user(ibusy.h_ino, &arg->h_ino); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ } ++out: ++ return err; ++} ++ ++long au_ibusy_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_ibusy(file->f_path.dentry->d_sb, (void __user *)arg); ++} ++ ++#ifdef CONFIG_COMPAT ++long au_ibusy_compat_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_ibusy(file->f_path.dentry->d_sb, compat_ptr(arg)); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * change a branch permission ++ */ ++ ++static void au_warn_ima(void) ++{ ++#ifdef CONFIG_IMA ++ /* since it doesn't support mark_files_ro() */ ++ AuWarn1("RW -> RO makes IMA to produce wrong message\n"); ++#endif ++} ++ ++static int do_need_sigen_inc(int a, int b) ++{ ++ return au_br_whable(a) && !au_br_whable(b); ++} ++ ++static int need_sigen_inc(int old, int new) ++{ ++ return do_need_sigen_inc(old, new) ++ || do_need_sigen_inc(new, old); ++} ++ ++static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err, do_warn; ++ unsigned int mnt_flags; ++ unsigned long long ull, max; ++ aufs_bindex_t br_id; ++ unsigned char verbose, writer; ++ struct file *file, *hf, **array; ++ struct au_hfile *hfile; ++ struct inode *h_inode; ++ ++ mnt_flags = au_mntflags(sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ ++ array = au_farray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ do_warn = 0; ++ br_id = au_sbr_id(sb, bindex); ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ fi_read_lock(file); ++ if (unlikely(au_test_mmapped(file))) { ++ err = -EBUSY; ++ AuVerbose(verbose, "mmapped %pD\n", file); ++ AuDbgFile(file); ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ goto out_array; ++ } ++ ++ hfile = &au_fi(file)->fi_htop; ++ hf = hfile->hf_file; ++ if (!d_is_reg(file->f_path.dentry) ++ || !(file->f_mode & FMODE_WRITE) ++ || hfile->hf_br->br_id != br_id ++ || !(hf->f_mode & FMODE_WRITE)) ++ array[ull] = NULL; ++ else { ++ do_warn = 1; ++ get_file(file); ++ } ++ ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ fput(file); ++ } ++ ++ err = 0; ++ if (do_warn) ++ au_warn_ima(); ++ ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (!file) ++ continue; ++ ++ /* todo: already flushed? */ ++ /* ++ * fs/super.c:mark_files_ro() is gone, but aufs keeps its ++ * approach which resets f_mode and calls mnt_drop_write() and ++ * file_release_write() for each file, because the branch ++ * attribute in aufs world is totally different from the native ++ * fs rw/ro mode. ++ */ ++ /* fi_read_lock(file); */ ++ hfile = &au_fi(file)->fi_htop; ++ hf = hfile->hf_file; ++ /* fi_read_unlock(file); */ ++ spin_lock(&hf->f_lock); ++ writer = !!(hf->f_mode & FMODE_WRITER); ++ hf->f_mode &= ~(FMODE_WRITE | FMODE_WRITER); ++ spin_unlock(&hf->f_lock); ++ if (writer) { ++ h_inode = file_inode(hf); ++ if (hf->f_mode & FMODE_READ) ++ i_readcount_inc(h_inode); ++ put_write_access(h_inode); ++ __mnt_drop_write(hf->f_path.mnt); ++ } ++ } ++ ++out_array: ++ au_farray_free(array, max); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, ++ int *do_refresh) ++{ ++ int err, rerr; ++ aufs_bindex_t bindex; ++ struct dentry *root; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ root = sb->s_root; ++ bindex = au_find_dbindex(root, mod->h_root); ++ if (bindex < 0) { ++ if (remount) ++ return 0; /* success */ ++ err = -ENOENT; ++ pr_err("%s no such branch\n", mod->path); ++ goto out; ++ } ++ AuDbg("bindex b%d\n", bindex); ++ ++ err = test_br(d_inode(mod->h_root), mod->perm, mod->path); ++ if (unlikely(err)) ++ goto out; ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(mod->h_root != au_br_dentry(br)); ++ if (br->br_perm == mod->perm) ++ return 0; /* success */ ++ ++ /* pre-allocate for non-fhsm --> fhsm */ ++ bf = NULL; ++ if (!au_br_fhsm(br->br_perm) && au_br_fhsm(mod->perm)) { ++ err = au_fhsm_br_alloc(br); ++ if (unlikely(err)) ++ goto out; ++ bf = br->br_fhsm; ++ br->br_fhsm = NULL; ++ } ++ ++ if (au_br_writable(br->br_perm)) { ++ /* remove whiteout base */ ++ err = au_br_init_wh(sb, br, mod->perm); ++ if (unlikely(err)) ++ goto out_bf; ++ ++ if (!au_br_writable(mod->perm)) { ++ /* rw --> ro, file might be mmapped */ ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(d_inode(root)); ++ di_write_unlock(root); ++ err = au_br_mod_files_ro(sb, bindex); ++ /* aufs_write_lock() calls ..._child() */ ++ di_write_lock_child(root); ++ ++ if (unlikely(err)) { ++ rerr = -ENOMEM; ++ br->br_wbr = kzalloc(sizeof(*br->br_wbr), ++ GFP_NOFS); ++ if (br->br_wbr) ++ rerr = au_wbr_init(br, sb, br->br_perm); ++ if (unlikely(rerr)) { ++ AuIOErr("nested error %d (%d)\n", ++ rerr, err); ++ br->br_perm = mod->perm; ++ } ++ } ++ } ++ } else if (au_br_writable(mod->perm)) { ++ /* ro --> rw */ ++ err = -ENOMEM; ++ br->br_wbr = kzalloc(sizeof(*br->br_wbr), GFP_NOFS); ++ if (br->br_wbr) { ++ err = au_wbr_init(br, sb, mod->perm); ++ if (unlikely(err)) { ++ au_kfree_rcu(br->br_wbr); ++ br->br_wbr = NULL; ++ } ++ } ++ } ++ if (unlikely(err)) ++ goto out_bf; ++ ++ if (au_br_fhsm(br->br_perm)) { ++ if (!au_br_fhsm(mod->perm)) { ++ /* fhsm --> non-fhsm */ ++ au_br_fhsm_fin(br->br_fhsm); ++ au_kfree_rcu(br->br_fhsm); ++ br->br_fhsm = NULL; ++ } ++ } else if (au_br_fhsm(mod->perm)) ++ /* non-fhsm --> fhsm */ ++ br->br_fhsm = bf; ++ ++ *do_refresh |= need_sigen_inc(br->br_perm, mod->perm); ++ br->br_perm = mod->perm; ++ goto out; /* success */ ++ ++out_bf: ++ au_kfree_try_rcu(bf); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs) ++{ ++ int err; ++ struct kstatfs kstfs; ++ ++ err = vfs_statfs(&br->br_path, &kstfs); ++ if (!err) { ++ stfs->f_blocks = kstfs.f_blocks; ++ stfs->f_bavail = kstfs.f_bavail; ++ stfs->f_files = kstfs.f_files; ++ stfs->f_ffree = kstfs.f_ffree; ++ } ++ ++ return err; ++} +diff -Naur null/fs/aufs/branch.h linux-5.15.36/fs/aufs/branch.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/branch.h 2022-05-10 16:51:39.866744220 +0300 +@@ -0,0 +1,375 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * branch filesystems and xino for them ++ */ ++ ++#ifndef __AUFS_BRANCH_H__ ++#define __AUFS_BRANCH_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "dirren.h" ++#include "dynop.h" ++#include "lcnt.h" ++#include "rwsem.h" ++#include "super.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* a xino file */ ++struct au_xino { ++ struct file **xi_file; ++ unsigned int xi_nfile; ++ ++ struct { ++ spinlock_t spin; ++ ino_t *array; ++ int total; ++ /* reserved for future use */ ++ /* unsigned long *bitmap; */ ++ wait_queue_head_t wqh; ++ } xi_nondir; ++ ++ struct mutex xi_mtx; /* protects xi_file array */ ++ struct hlist_bl_head xi_writing; ++ ++ atomic_t xi_truncating; ++ ++ struct kref xi_kref; ++}; ++ ++/* File-based Hierarchical Storage Management */ ++struct au_br_fhsm { ++#ifdef CONFIG_AUFS_FHSM ++ struct mutex bf_lock; ++ unsigned long bf_jiffy; ++ struct aufs_stfs bf_stfs; ++ int bf_readable; ++#endif ++}; ++ ++/* members for writable branch only */ ++enum {AuBrWh_BASE, AuBrWh_PLINK, AuBrWh_ORPH, AuBrWh_Last}; ++struct au_wbr { ++ struct au_rwsem wbr_wh_rwsem; ++ struct dentry *wbr_wh[AuBrWh_Last]; ++ atomic_t wbr_wh_running; ++#define wbr_whbase wbr_wh[AuBrWh_BASE] /* whiteout base */ ++#define wbr_plink wbr_wh[AuBrWh_PLINK] /* pseudo-link dir */ ++#define wbr_orph wbr_wh[AuBrWh_ORPH] /* dir for orphans */ ++ ++ /* mfs mode */ ++ unsigned long long wbr_bytes; ++}; ++ ++/* ext2 has 3 types of operations at least, ext3 has 4 */ ++#define AuBrDynOp (AuDyLast * 4) ++ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++/* support for asynchronous destruction */ ++struct au_br_hfsnotify { ++ struct fsnotify_group *hfsn_group; ++}; ++#endif ++ ++/* sysfs entries */ ++struct au_brsysfs { ++ char name[16]; ++ struct attribute attr; ++}; ++ ++enum { ++ AuBrSysfs_BR, ++ AuBrSysfs_BRID, ++ AuBrSysfs_Last ++}; ++ ++/* protected by superblock rwsem */ ++struct au_branch { ++ struct au_xino *br_xino; ++ ++ aufs_bindex_t br_id; ++ ++ int br_perm; ++ struct path br_path; ++ spinlock_t br_dykey_lock; ++ struct au_dykey *br_dykey[AuBrDynOp]; ++ 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; ++ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ struct au_br_hfsnotify *br_hfsn; ++#endif ++ ++#ifdef CONFIG_SYSFS ++ /* entries under sysfs per mount-point */ ++ struct au_brsysfs br_sysfs[AuBrSysfs_Last]; ++#endif ++ ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *br_dbgaufs; /* xino */ ++#endif ++ ++ struct au_dr_br br_dirren; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct vfsmount *au_br_mnt(struct au_branch *br) ++{ ++ return br->br_path.mnt; ++} ++ ++static inline struct dentry *au_br_dentry(struct au_branch *br) ++{ ++ return br->br_path.dentry; ++} ++ ++static inline struct user_namespace *au_br_userns(struct au_branch *br) ++{ ++ return mnt_user_ns(br->br_path.mnt); ++} ++ ++static inline struct super_block *au_br_sb(struct au_branch *br) ++{ ++ return au_br_mnt(br)->mnt_sb; ++} ++ ++static inline int au_br_rdonly(struct au_branch *br) ++{ ++ return (sb_rdonly(au_br_sb(br)) ++ || !au_br_writable(br->br_perm)) ++ ? -EROFS : 0; ++} ++ ++static inline int au_br_hnotifyable(int brperm __maybe_unused) ++{ ++#ifdef CONFIG_AUFS_HNOTIFY ++ return !(brperm & AuBrPerm_RR); ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_br_test_oflag(int oflag, struct au_branch *br) ++{ ++ int err, exec_flag; ++ ++ err = 0; ++ exec_flag = oflag & __FMODE_EXEC; ++ if (unlikely(exec_flag && path_noexec(&br->br_path))) ++ err = -EACCES; ++ ++ 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 */ ++struct au_sbinfo; ++void au_br_free(struct au_sbinfo *sinfo); ++int au_br_index(struct super_block *sb, aufs_bindex_t br_id); ++struct au_opt_add; ++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount); ++struct au_opt_del; ++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount); ++long au_ibusy_ioctl(struct file *file, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_ibusy_compat_ioctl(struct file *file, unsigned long arg); ++#endif ++struct au_opt_mod; ++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, ++ int *do_refresh); ++struct aufs_stfs; ++int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs); ++ ++/* xino.c */ ++static const loff_t au_loff_max = LLONG_MAX; ++ ++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, ++ int wbrtop); ++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(struct file *file, void *buf, size_t size, loff_t *pos); ++ssize_t xino_fwrite(struct file *file, void *buf, size_t size, loff_t *pos); ++ ++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; ++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_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 */ ++static inline ++aufs_bindex_t au_sbr_id(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_sbr(sb, bindex)->br_id; ++} ++ ++static inline ++struct vfsmount *au_sbr_mnt(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_mnt(au_sbr(sb, bindex)); ++} ++ ++static inline ++struct user_namespace *au_sbr_userns(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_userns(au_sbr(sb, bindex)); ++} ++ ++static inline ++struct super_block *au_sbr_sb(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_sb(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; ++} ++ ++static inline int au_sbr_whable(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_whable(au_sbr_perm(sb, bindex)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define wbr_wh_read_lock(wbr) au_rw_read_lock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_lock(wbr) au_rw_write_lock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_read_trylock(wbr) au_rw_read_trylock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_trylock(wbr) au_rw_write_trylock(&(wbr)->wbr_wh_rwsem) ++/* ++#define wbr_wh_read_trylock_nested(wbr) \ ++ au_rw_read_trylock_nested(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_trylock_nested(wbr) \ ++ au_rw_write_trylock_nested(&(wbr)->wbr_wh_rwsem) ++*/ ++ ++#define wbr_wh_read_unlock(wbr) au_rw_read_unlock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_unlock(wbr) au_rw_write_unlock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_downgrade_lock(wbr) au_rw_dgrade_lock(&(wbr)->wbr_wh_rwsem) ++ ++#define WbrWhMustNoWaiters(wbr) AuRwMustNoWaiters(&(wbr)->wbr_wh_rwsem) ++#define WbrWhMustAnyLock(wbr) AuRwMustAnyLock(&(wbr)->wbr_wh_rwsem) ++#define WbrWhMustWriteLock(wbr) AuRwMustWriteLock(&(wbr)->wbr_wh_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_FHSM ++static inline void au_br_fhsm_init(struct au_br_fhsm *brfhsm) ++{ ++ mutex_init(&brfhsm->bf_lock); ++ brfhsm->bf_jiffy = 0; ++ brfhsm->bf_readable = 0; ++} ++ ++static inline void au_br_fhsm_fin(struct au_br_fhsm *brfhsm) ++{ ++ mutex_destroy(&brfhsm->bf_lock); ++} ++#else ++AuStubVoid(au_br_fhsm_init, struct au_br_fhsm *brfhsm) ++AuStubVoid(au_br_fhsm_fin, struct au_br_fhsm *brfhsm) ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_BRANCH_H__ */ +diff -Naur null/fs/aufs/conf.mk linux-5.15.36/fs/aufs/conf.mk +--- /dev/null ++++ linux-5.15.36/fs/aufs/conf.mk 2022-05-10 16:51:39.867744220 +0300 +@@ -0,0 +1,40 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++AuConfStr = CONFIG_AUFS_FS=${CONFIG_AUFS_FS} ++ ++define AuConf ++ifdef ${1} ++AuConfStr += ${1}=${${1}} ++endif ++endef ++ ++AuConfAll = BRANCH_MAX_127 BRANCH_MAX_511 BRANCH_MAX_1023 BRANCH_MAX_32767 \ ++ SBILIST \ ++ HNOTIFY HFSNOTIFY \ ++ EXPORT INO_T_64 \ ++ XATTR \ ++ FHSM \ ++ RDU \ ++ DIRREN \ ++ SHWH \ ++ BR_RAMFS \ ++ BR_FUSE POLL \ ++ BR_HFSPLUS \ ++ BDEV_LOOP \ ++ DEBUG MAGIC_SYSRQ ++$(foreach i, ${AuConfAll}, \ ++ $(eval $(call AuConf,CONFIG_AUFS_${i}))) ++ ++AuConfName = ${obj}/conf.str ++${AuConfName}.tmp: FORCE ++ @echo ${AuConfStr} | tr ' ' '\n' | sed -e 's/^/"/' -e 's/$$/\\n"/' > $@ ++${AuConfName}: ${AuConfName}.tmp ++ @diff -q $< $@ > /dev/null 2>&1 || { \ ++ echo ' GEN ' $@; \ ++ cp -p $< $@; \ ++ } ++FORCE: ++clean-files += ${AuConfName} ${AuConfName}.tmp ++${obj}/sysfs.o: ${AuConfName} ++ ++-include ${srctree}/${src}/conf_priv.mk +diff -Naur null/fs/aufs/cpup.c linux-5.15.36/fs/aufs/cpup.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/cpup.c 2022-05-10 16:51:39.867744220 +0300 +@@ -0,0 +1,1459 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * copy-up functions, see wbr_policy.c for copy-down ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++void au_cpup_attr_flags(struct inode *dst, unsigned int iflags) ++{ ++ const unsigned int mask = S_DEAD | S_SWAPFILE | S_PRIVATE ++ | S_NOATIME | S_NOCMTIME | S_AUTOMOUNT; ++ ++ BUILD_BUG_ON(sizeof(iflags) != sizeof(dst->i_flags)); ++ ++ dst->i_flags |= iflags & ~mask; ++ if (au_test_fs_notime(dst->i_sb)) ++ dst->i_flags |= S_NOATIME | S_NOCMTIME; ++} ++ ++void au_cpup_attr_timesizes(struct inode *inode) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ fsstack_copy_attr_times(inode, h_inode); ++ fsstack_copy_inode_size(inode, h_inode); ++} ++ ++void au_cpup_attr_nlink(struct inode *inode, int force) ++{ ++ struct inode *h_inode; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot; ++ ++ sb = inode->i_sb; ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (!force ++ && !S_ISDIR(h_inode->i_mode) ++ && au_opt_test(au_mntflags(sb), PLINK) ++ && au_plink_test(inode)) ++ return; ++ ++ /* ++ * 0 can happen in revalidating. ++ * h_inode->i_mutex may not be held here, but it is harmless since once ++ * i_nlink reaches 0, it will never become positive except O_TMPFILE ++ * case. ++ * todo: O_TMPFILE+linkat(AT_SYMLINK_FOLLOW) bypassing aufs may cause ++ * the incorrect link count. ++ */ ++ set_nlink(inode, h_inode->i_nlink); ++ ++ /* ++ * fewer nlink makes find(1) noisy, but larger nlink doesn't. ++ * it may includes whplink directory. ++ */ ++ if (S_ISDIR(h_inode->i_mode)) { ++ bbot = au_ibbot(inode); ++ for (bindex++; bindex <= bbot; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (h_inode) ++ au_add_nlink(inode, h_inode); ++ } ++ } ++} ++ ++void au_cpup_attr_changeable(struct inode *inode) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ inode->i_mode = h_inode->i_mode; ++ inode->i_uid = h_inode->i_uid; ++ inode->i_gid = h_inode->i_gid; ++ au_cpup_attr_timesizes(inode); ++ au_cpup_attr_flags(inode, h_inode->i_flags); ++} ++ ++void au_cpup_igen(struct inode *inode, struct inode *h_inode) ++{ ++ struct au_iinfo *iinfo = au_ii(inode); ++ ++ IiMustWriteLock(inode); ++ ++ iinfo->ii_higen = h_inode->i_generation; ++ iinfo->ii_hsb1 = h_inode->i_sb; ++} ++ ++void au_cpup_attr_all(struct inode *inode, int force) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ au_cpup_attr_changeable(inode); ++ if (inode->i_nlink > 0) ++ au_cpup_attr_nlink(inode, force); ++ inode->i_rdev = h_inode->i_rdev; ++ inode->i_blkbits = h_inode->i_blkbits; ++ au_cpup_igen(inode, h_inode); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Note: dt_dentry and dt_h_dentry are not dget/dput-ed */ ++ ++/* keep the timestamps of the parent dir when cpup */ ++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, ++ struct path *h_path) ++{ ++ struct inode *h_inode; ++ ++ dt->dt_dentry = dentry; ++ dt->dt_h_path = *h_path; ++ h_inode = d_inode(h_path->dentry); ++ dt->dt_atime = h_inode->i_atime; ++ dt->dt_mtime = h_inode->i_mtime; ++ /* smp_mb(); */ ++} ++ ++void au_dtime_revert(struct au_dtime *dt) ++{ ++ struct iattr attr; ++ int err; ++ ++ attr.ia_atime = dt->dt_atime; ++ attr.ia_mtime = dt->dt_mtime; ++ attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET ++ | ATTR_ATIME | ATTR_ATIME_SET; ++ ++ /* no delegation since this is a directory */ ++ err = vfsub_notify_change(&dt->dt_h_path, &attr, /*delegated*/NULL); ++ if (unlikely(err)) ++ pr_warn("restoring timestamps failed(%d). ignored\n", err); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* internal use only */ ++struct au_cpup_reg_attr { ++ int valid; ++ struct kstat st; ++ unsigned int iflags; /* inode->i_flags */ ++}; ++ ++static noinline_for_stack ++int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct path *h_src, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err, sbits, icex; ++ unsigned int mnt_flags; ++ unsigned char verbose; ++ struct iattr ia; ++ struct path h_path; ++ struct inode *h_isrc, *h_idst; ++ struct kstat *h_st; ++ struct au_branch *br; ++ ++ br = au_sbr(dst->d_sb, bindex); ++ h_path.mnt = au_br_mnt(br); ++ h_path.dentry = au_h_dptr(dst, bindex); ++ h_idst = d_inode(h_path.dentry); ++ h_isrc = d_inode(h_src->dentry); ++ ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID ++ | ATTR_ATIME | ATTR_MTIME ++ | ATTR_ATIME_SET | ATTR_MTIME_SET; ++ if (h_src_attr && h_src_attr->valid) { ++ h_st = &h_src_attr->st; ++ ia.ia_uid = h_st->uid; ++ ia.ia_gid = h_st->gid; ++ ia.ia_atime = h_st->atime; ++ ia.ia_mtime = h_st->mtime; ++ if (h_idst->i_mode != h_st->mode ++ && !S_ISLNK(h_idst->i_mode)) { ++ ia.ia_valid |= ATTR_MODE; ++ ia.ia_mode = h_st->mode; ++ } ++ sbits = !!(h_st->mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(h_idst, h_src_attr->iflags); ++ } else { ++ ia.ia_uid = h_isrc->i_uid; ++ ia.ia_gid = h_isrc->i_gid; ++ ia.ia_atime = h_isrc->i_atime; ++ ia.ia_mtime = h_isrc->i_mtime; ++ if (h_idst->i_mode != h_isrc->i_mode ++ && !S_ISLNK(h_idst->i_mode)) { ++ ia.ia_valid |= ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ } ++ sbits = !!(h_isrc->i_mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(h_idst, h_isrc->i_flags); ++ } ++ /* no delegation since it is just created */ ++ err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL); ++ ++ /* is this nfs only? */ ++ if (!err && sbits && au_test_nfs(h_path.dentry->d_sb)) { ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL); ++ } ++ ++ icex = br->br_perm & AuBrAttr_ICEX; ++ if (!err) { ++ mnt_flags = au_mntflags(dst->d_sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ err = au_cpup_xattr(&h_path, h_src, icex, verbose); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_copy_file(struct file *dst, struct file *src, loff_t len, ++ char *buf, unsigned long blksize) ++{ ++ int err; ++ size_t sz, rbytes, wbytes; ++ unsigned char all_zero; ++ char *p, *zp; ++ struct inode *h_inode; ++ /* reduce stack usage */ ++ struct iattr *ia; ++ ++ zp = page_address(ZERO_PAGE(0)); ++ if (unlikely(!zp)) ++ return -ENOMEM; /* possible? */ ++ ++ err = 0; ++ all_zero = 0; ++ while (len) { ++ AuDbg("len %lld\n", len); ++ sz = blksize; ++ if (len < blksize) ++ sz = len; ++ ++ rbytes = 0; ++ /* todo: signal_pending? */ ++ while (!rbytes || err == -EAGAIN || err == -EINTR) { ++ rbytes = vfsub_read_k(src, buf, sz, &src->f_pos); ++ err = rbytes; ++ } ++ if (unlikely(err < 0)) ++ break; ++ ++ all_zero = 0; ++ if (len >= rbytes && rbytes == blksize) ++ all_zero = !memcmp(buf, zp, rbytes); ++ if (!all_zero) { ++ wbytes = rbytes; ++ p = buf; ++ while (wbytes) { ++ size_t b; ++ ++ b = vfsub_write_k(dst, p, wbytes, &dst->f_pos); ++ err = b; ++ /* todo: signal_pending? */ ++ if (unlikely(err == -EAGAIN || err == -EINTR)) ++ continue; ++ if (unlikely(err < 0)) ++ break; ++ wbytes -= b; ++ p += b; ++ } ++ if (unlikely(err < 0)) ++ break; ++ } else { ++ loff_t res; ++ ++ AuLabel(hole); ++ res = vfsub_llseek(dst, rbytes, SEEK_CUR); ++ err = res; ++ if (unlikely(res < 0)) ++ break; ++ } ++ len -= rbytes; ++ err = 0; ++ } ++ ++ /* the last block may be a hole */ ++ if (!err && all_zero) { ++ AuLabel(last hole); ++ ++ err = 1; ++ if (au_test_nfs(dst->f_path.dentry->d_sb)) { ++ /* nfs requires this step to make last hole */ ++ /* is this only nfs? */ ++ do { ++ /* todo: signal_pending? */ ++ err = vfsub_write_k(dst, "\0", 1, &dst->f_pos); ++ } while (err == -EAGAIN || err == -EINTR); ++ if (err == 1) ++ dst->f_pos--; ++ } ++ ++ if (err == 1) { ++ ia = (void *)buf; ++ ia->ia_size = dst->f_pos; ++ ia->ia_valid = ATTR_SIZE | ATTR_FILE; ++ ia->ia_file = dst; ++ h_inode = file_inode(dst); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD2); ++ /* no delegation since it is just created */ ++ err = vfsub_notify_change(&dst->f_path, ia, ++ /*delegated*/NULL); ++ inode_unlock(h_inode); ++ } ++ } ++ ++ return err; ++} ++ ++int au_copy_file(struct file *dst, struct file *src, loff_t len) ++{ ++ int err; ++ unsigned long blksize; ++ unsigned char do_kfree; ++ char *buf; ++ struct super_block *h_sb; ++ ++ err = -ENOMEM; ++ 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); ++ do_kfree = (blksize != PAGE_SIZE && blksize >= sizeof(struct iattr *)); ++ if (do_kfree) ++ buf = kmalloc(blksize, GFP_NOFS); ++ else ++ buf = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!buf)) ++ goto out; ++ ++ if (len > (1 << 22)) ++ AuDbg("copying a large file %lld\n", (long long)len); ++ ++ src->f_pos = 0; ++ dst->f_pos = 0; ++ err = au_do_copy_file(dst, src, len, buf, blksize); ++ if (do_kfree) { ++ AuDebugOn(!au_kfree_do_sz_test(blksize)); ++ au_kfree_do_rcu(buf); ++ } else ++ free_page((unsigned long)buf); ++ ++out: ++ return err; ++} ++ ++static int au_do_copy(struct file *dst, struct file *src, loff_t len) ++{ ++ int err; ++ 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; ++ ++ /* XFS acquires inode_lock */ ++ if (!au_test_xfs(h_src_sb)) ++ err = au_copy_file(dst, src, len); ++ else { ++ inode_unlock_shared(h_src_inode); ++ err = au_copy_file(dst, src, len); ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ } ++ ++ return err; ++} ++ ++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->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); ++ lo = vfsub_clone_file_range(src, dst, len); ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ } else ++ 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); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * to support a sparse file which is opened with O_APPEND, ++ * we need to close the file. ++ */ ++static int au_cp_regular(struct au_cp_generic *cpg) ++{ ++ int err, i; ++ enum { SRC, DST }; ++ struct { ++ aufs_bindex_t bindex; ++ unsigned int flags; ++ struct dentry *dentry; ++ int force_wr; ++ struct file *file; ++ } *f, file[] = { ++ { ++ .bindex = cpg->bsrc, ++ .flags = O_RDONLY | O_NOATIME | O_LARGEFILE, ++ }, ++ { ++ .bindex = cpg->bdst, ++ .flags = O_WRONLY | O_NOATIME | O_LARGEFILE, ++ .force_wr = !!au_ftest_cpup(cpg->flags, RWDST), ++ } ++ }; ++ struct au_branch *br; ++ struct super_block *sb, *h_src_sb; ++ struct inode *h_src_inode; ++ struct task_struct *tsk = current; ++ ++ /* bsrc branch can be ro/rw. */ ++ sb = cpg->dentry->d_sb; ++ f = file; ++ for (i = 0; i < 2; i++, f++) { ++ 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); ++ 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 */ ++ h_src_inode = d_inode(file[SRC].dentry); ++ h_src_sb = h_src_inode->i_sb; ++ if (!au_test_nfs(h_src_sb)) ++ IMustLock(h_src_inode); ++ err = au_clone_or_copy(file[DST].file, file[SRC].file, cpg->len); ++ ++ /* i wonder if we had O_NO_DELAY_FPUT flag */ ++ if (tsk->flags & PF_KTHREAD) ++ __fput_sync(file[DST].file); ++ else { ++ /* it happened actually */ ++ fput(file[DST].file); ++ /* ++ * too bad. ++ * we have to call both since we don't know which place the file ++ * was added to. ++ */ ++ task_work_run(); ++ flush_delayed_fput(); ++ } ++ br = au_sbr(sb, file[DST].bindex); ++ au_lcnt_dec(&br->br_nfiles); ++ ++out_src: ++ fput(file[SRC].file); ++ br = au_sbr(sb, file[SRC].bindex); ++ au_lcnt_dec(&br->br_nfiles); ++out: ++ return err; ++} ++ ++static int au_do_cpup_regular(struct au_cp_generic *cpg, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err, rerr; ++ loff_t l; ++ struct path h_path; ++ struct inode *h_src_inode, *h_dst_inode; ++ ++ err = 0; ++ h_src_inode = au_h_iptr(d_inode(cpg->dentry), cpg->bsrc); ++ l = i_size_read(h_src_inode); ++ if (cpg->len == -1 || l < cpg->len) ++ cpg->len = l; ++ if (cpg->len) { ++ /* try stopping to update while we are referencing */ ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ au_pin_hdir_unlock(cpg->pin); ++ ++ h_path.dentry = au_h_dptr(cpg->dentry, cpg->bsrc); ++ h_path.mnt = au_sbr_mnt(cpg->dentry->d_sb, cpg->bsrc); ++ h_src_attr->iflags = h_src_inode->i_flags; ++ if (!au_test_nfs(h_src_inode->i_sb)) ++ err = vfsub_getattr(&h_path, &h_src_attr->st); ++ else { ++ inode_unlock_shared(h_src_inode); ++ err = vfsub_getattr(&h_path, &h_src_attr->st); ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ } ++ if (unlikely(err)) { ++ inode_unlock_shared(h_src_inode); ++ goto out; ++ } ++ h_src_attr->valid = 1; ++ if (!au_test_nfs(h_src_inode->i_sb)) { ++ err = au_cp_regular(cpg); ++ inode_unlock_shared(h_src_inode); ++ } else { ++ inode_unlock_shared(h_src_inode); ++ err = au_cp_regular(cpg); ++ } ++ rerr = au_pin_hdir_relock(cpg->pin); ++ if (!err && rerr) ++ err = rerr; ++ } ++ if (!err && (h_src_inode->i_state & I_LINKABLE)) { ++ h_path.dentry = au_h_dptr(cpg->dentry, cpg->bdst); ++ h_dst_inode = d_inode(h_path.dentry); ++ spin_lock(&h_dst_inode->i_lock); ++ h_dst_inode->i_state |= I_LINKABLE; ++ spin_unlock(&h_dst_inode->i_lock); ++ } ++ ++out: ++ return err; ++} ++ ++static int au_do_cpup_symlink(struct path *h_path, struct dentry *h_src, ++ struct inode *h_dir) ++{ ++ int err; ++ DEFINE_DELAYED_CALL(done); ++ const char *sym; ++ ++ sym = vfs_get_link(h_src, &done); ++ err = PTR_ERR(sym); ++ if (IS_ERR(sym)) ++ goto out; ++ ++ err = vfsub_symlink(h_dir, h_path, sym); ++ ++out: ++ do_delayed_call(&done); ++ return err; ++} ++ ++/* ++ * regardless 'acl' option, reset all ACL. ++ * All ACL will be copied up later from the original entry on the lower branch. ++ */ ++static int au_reset_acl(struct inode *h_dir, struct path *h_path, umode_t mode) ++{ ++ int err; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct user_namespace *h_userns; ++ ++ h_userns = mnt_user_ns(h_path->mnt); ++ h_dentry = h_path->dentry; ++ h_inode = d_inode(h_dentry); ++ /* forget_all_cached_acls(h_inode)); */ ++ err = vfsub_removexattr(h_userns, h_dentry, XATTR_NAME_POSIX_ACL_ACCESS); ++ AuTraceErr(err); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ if (!err) ++ err = vfsub_acl_chmod(h_userns, h_inode, mode); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_do_cpup_dir(struct au_cp_generic *cpg, struct dentry *dst_parent, ++ struct inode *h_dir, struct path *h_path) ++{ ++ int err; ++ struct inode *dir, *inode; ++ struct user_namespace *h_userns; ++ ++ h_userns = mnt_user_ns(h_path->mnt); ++ err = vfsub_removexattr(h_userns, h_path->dentry, ++ XATTR_NAME_POSIX_ACL_DEFAULT); ++ AuTraceErr(err); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * strange behaviour from the users view, ++ * particularly setattr case ++ */ ++ dir = d_inode(dst_parent); ++ if (au_ibtop(dir) == cpg->bdst) ++ au_cpup_attr_nlink(dir, /*force*/1); ++ inode = d_inode(cpg->dentry); ++ au_cpup_attr_nlink(inode, /*force*/1); ++ ++out: ++ return err; ++} ++ ++static noinline_for_stack ++int cpup_entry(struct au_cp_generic *cpg, struct dentry *dst_parent, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err; ++ umode_t mode; ++ unsigned int mnt_flags; ++ unsigned char isdir, isreg, force; ++ const unsigned char do_dt = !!au_ftest_cpup(cpg->flags, DTIME); ++ struct au_dtime dt; ++ struct path h_path; ++ struct dentry *h_src, *h_dst, *h_parent; ++ struct inode *h_inode, *h_dir; ++ struct super_block *sb; ++ ++ /* bsrc branch can be ro/rw. */ ++ h_src = au_h_dptr(cpg->dentry, cpg->bsrc); ++ h_inode = d_inode(h_src); ++ AuDebugOn(h_inode != au_h_iptr(d_inode(cpg->dentry), cpg->bsrc)); ++ ++ /* try stopping to be referenced while we are creating */ ++ h_dst = au_h_dptr(cpg->dentry, cpg->bdst); ++ if (au_ftest_cpup(cpg->flags, RENAME)) ++ AuDebugOn(strncmp(h_dst->d_name.name, AUFS_WH_PFX, ++ AUFS_WH_PFX_LEN)); ++ h_parent = h_dst->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ AuDebugOn(h_parent != h_dst->d_parent); ++ ++ sb = cpg->dentry->d_sb; ++ h_path.mnt = au_sbr_mnt(sb, cpg->bdst); ++ if (do_dt) { ++ h_path.dentry = h_parent; ++ au_dtime_store(&dt, dst_parent, &h_path); ++ } ++ h_path.dentry = h_dst; ++ ++ isreg = 0; ++ isdir = 0; ++ mode = h_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ isreg = 1; ++ err = vfsub_create(h_dir, &h_path, 0600, /*want_excl*/true); ++ if (!err) ++ err = au_do_cpup_regular(cpg, h_src_attr); ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ err = vfsub_mkdir(h_dir, &h_path, mode); ++ if (!err) ++ err = au_do_cpup_dir(cpg, dst_parent, h_dir, &h_path); ++ break; ++ case S_IFLNK: ++ err = au_do_cpup_symlink(&h_path, h_src, h_dir); ++ break; ++ case S_IFCHR: ++ case S_IFBLK: ++ AuDebugOn(!capable(CAP_MKNOD)); ++ fallthrough; ++ case S_IFIFO: ++ case S_IFSOCK: ++ err = vfsub_mknod(h_dir, &h_path, mode, h_inode->i_rdev); ++ break; ++ default: ++ AuIOErr("Unknown inode type 0%o\n", mode); ++ err = -EIO; ++ } ++ if (!err) ++ err = au_reset_acl(h_dir, &h_path, mode); ++ ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, UDBA_NONE) ++ && !isdir ++ && au_opt_test(mnt_flags, XINO) ++ && (h_inode->i_nlink == 1 ++ || (h_inode->i_state & I_LINKABLE)) ++ /* todo: unnecessary? */ ++ /* && d_inode(cpg->dentry)->i_nlink == 1 */ ++ && cpg->bdst < cpg->bsrc ++ && !au_ftest_cpup(cpg->flags, KEEPLINO)) ++ au_xino_write(sb, cpg->bsrc, h_inode->i_ino, /*ino*/0); ++ /* ignore this error */ ++ ++ if (!err) { ++ force = 0; ++ if (isreg) { ++ force = !!cpg->len; ++ if (cpg->len == -1) ++ force = !!i_size_read(h_inode); ++ } ++ au_fhsm_wrote(sb, cpg->bdst, force); ++ } ++ ++ if (do_dt) ++ au_dtime_revert(&dt); ++ return err; ++} ++ ++static int au_do_ren_after_cpup(struct au_cp_generic *cpg, struct path *h_path) ++{ ++ int err; ++ struct dentry *dentry, *h_dentry, *h_parent, *parent; ++ struct path h_ppath; ++ struct inode *h_dir; ++ aufs_bindex_t bdst; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ h_ppath.mnt = au_sbr_mnt(dentry->d_sb, bdst); ++ h_dentry = au_h_dptr(dentry, bdst); ++ if (!au_ftest_cpup(cpg->flags, OVERWRITE)) { ++ dget(h_dentry); ++ au_set_h_dptr(dentry, bdst, NULL); ++ err = au_lkup_neg(dentry, bdst, /*wh*/0); ++ if (!err) ++ h_path->dentry = dget(au_h_dptr(dentry, bdst)); ++ au_set_h_dptr(dentry, bdst, h_dentry); ++ } else { ++ err = 0; ++ parent = dget_parent(dentry); ++ h_ppath.dentry = au_h_dptr(parent, bdst); ++ dput(parent); ++ h_path->dentry = vfsub_lkup_one(&dentry->d_name, &h_ppath); ++ if (IS_ERR(h_path->dentry)) ++ err = PTR_ERR(h_path->dentry); ++ } ++ if (unlikely(err)) ++ goto out; ++ ++ h_parent = h_dentry->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ AuDbg("%pd %pd\n", h_dentry, h_path->dentry); ++ /* no delegation since it is just created */ ++ err = vfsub_rename(h_dir, h_dentry, h_dir, h_path, /*delegated*/NULL, ++ /*flags*/0); ++ dput(h_path->dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * copyup the @dentry from @bsrc to @bdst. ++ * the caller must set the both of lower dentries. ++ * @len is for truncating when it is -1 copyup the entire file. ++ * 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 unnecessary. ++ */ ++static int au_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) ++{ ++ int err, rerr; ++ aufs_bindex_t old_ibtop; ++ unsigned char isdir, plink; ++ struct dentry *h_src, *h_dst, *h_parent; ++ struct inode *dst_inode, *h_dir, *inode, *delegated, *src_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct path h_src_path; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct path h_path; ++ struct au_cpup_reg_attr h_src_attr; ++ } *a; ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ a->h_src_attr.valid = 0; ++ ++ sb = cpg->dentry->d_sb; ++ br = au_sbr(sb, cpg->bdst); ++ a->h_path.mnt = au_br_mnt(br); ++ h_dst = au_h_dptr(cpg->dentry, cpg->bdst); ++ h_parent = h_dst->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ h_src = au_h_dptr(cpg->dentry, cpg->bsrc); ++ inode = d_inode(cpg->dentry); ++ ++ if (!dst_parent) ++ dst_parent = dget_parent(cpg->dentry); ++ else ++ dget(dst_parent); ++ ++ plink = !!au_opt_test(au_mntflags(sb), PLINK); ++ dst_inode = au_h_iptr(inode, cpg->bdst); ++ if (dst_inode) { ++ if (unlikely(!plink)) { ++ err = -EIO; ++ AuIOErr("hi%lu(i%lu) exists on b%d " ++ "but plink is disabled\n", ++ dst_inode->i_ino, inode->i_ino, cpg->bdst); ++ goto out_parent; ++ } ++ ++ if (dst_inode->i_nlink) { ++ const int do_dt = au_ftest_cpup(cpg->flags, DTIME); ++ ++ h_src = au_plink_lkup(inode, cpg->bdst); ++ err = PTR_ERR(h_src); ++ if (IS_ERR(h_src)) ++ goto out_parent; ++ if (unlikely(d_is_negative(h_src))) { ++ err = -EIO; ++ AuIOErr("i%lu exists on b%d " ++ "but not pseudo-linked\n", ++ inode->i_ino, cpg->bdst); ++ dput(h_src); ++ goto out_parent; ++ } ++ ++ if (do_dt) { ++ a->h_path.dentry = h_parent; ++ au_dtime_store(&a->dt, dst_parent, &a->h_path); ++ } ++ ++ a->h_path.dentry = h_dst; ++ delegated = NULL; ++ err = vfsub_link(h_src, h_dir, &a->h_path, &delegated); ++ if (!err && au_ftest_cpup(cpg->flags, RENAME)) ++ err = au_do_ren_after_cpup(cpg, &a->h_path); ++ if (do_dt) ++ au_dtime_revert(&a->dt); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ dput(h_src); ++ goto out_parent; ++ } else ++ /* todo: cpup_wh_file? */ ++ /* udba work */ ++ au_update_ibrange(inode, /*do_put_zero*/1); ++ } ++ ++ isdir = S_ISDIR(inode->i_mode); ++ old_ibtop = au_ibtop(inode); ++ err = cpup_entry(cpg, dst_parent, &a->h_src_attr); ++ if (unlikely(err)) ++ goto out_rev; ++ dst_inode = d_inode(h_dst); ++ inode_lock_nested(dst_inode, AuLsc_I_CHILD2); ++ /* todo: necessary? */ ++ /* au_pin_hdir_unlock(cpg->pin); */ ++ ++ h_src_path.dentry = h_src; ++ h_src_path.mnt = au_sbr_mnt(sb, cpg->bsrc); ++ err = cpup_iattr(cpg->dentry, cpg->bdst, &h_src_path, &a->h_src_attr); ++ if (unlikely(err)) { ++ /* todo: necessary? */ ++ /* au_pin_hdir_relock(cpg->pin); */ /* ignore an error */ ++ inode_unlock(dst_inode); ++ goto out_rev; ++ } ++ ++ if (cpg->bdst < old_ibtop) { ++ if (S_ISREG(inode->i_mode)) { ++ err = au_dy_iaop(inode, cpg->bdst, dst_inode); ++ if (unlikely(err)) { ++ /* ignore an error */ ++ /* au_pin_hdir_relock(cpg->pin); */ ++ inode_unlock(dst_inode); ++ goto out_rev; ++ } ++ } ++ au_set_ibtop(inode, cpg->bdst); ++ } else ++ au_set_ibbot(inode, cpg->bdst); ++ au_set_h_iptr(inode, cpg->bdst, au_igrab(dst_inode), ++ au_hi_flags(inode, isdir)); ++ ++ /* todo: necessary? */ ++ /* err = au_pin_hdir_relock(cpg->pin); */ ++ inode_unlock(dst_inode); ++ if (unlikely(err)) ++ goto out_rev; ++ ++ src_inode = d_inode(h_src); ++ if (!isdir ++ && (src_inode->i_nlink > 1 ++ || src_inode->i_state & I_LINKABLE) ++ && plink) ++ au_plink_append(inode, cpg->bdst, h_dst); ++ ++ if (au_ftest_cpup(cpg->flags, RENAME)) { ++ a->h_path.dentry = h_dst; ++ err = au_do_ren_after_cpup(cpg, &a->h_path); ++ } ++ if (!err) ++ goto out_parent; /* success */ ++ ++ /* revert */ ++out_rev: ++ a->h_path.dentry = h_parent; ++ au_dtime_store(&a->dt, dst_parent, &a->h_path); ++ a->h_path.dentry = h_dst; ++ rerr = 0; ++ if (d_is_positive(h_dst)) { ++ if (!isdir) { ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(h_dir, &a->h_path, ++ /*delegated*/NULL, /*force*/0); ++ } else ++ rerr = vfsub_rmdir(h_dir, &a->h_path); ++ } ++ au_dtime_revert(&a->dt); ++ if (rerr) { ++ AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr); ++ err = -EIO; ++ } ++out_parent: ++ dput(dst_parent); ++ au_kfree_rcu(a); ++out: ++ return err; ++} ++ ++#if 0 /* reserved */ ++struct au_cpup_single_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++ struct dentry *dst_parent; ++}; ++ ++static void au_call_cpup_single(void *args) ++{ ++ struct au_cpup_single_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_single(a->cpg, a->dst_parent); ++ au_pin_hdir_release(a->cpg->pin); ++} ++#endif ++ ++/* ++ * prevent SIGXFSZ in copy-up. ++ * testing CAP_MKNOD is for generic fs, ++ * but CAP_FSETID is for xfs only, currently. ++ */ ++static int au_cpup_sio_test(struct au_pin *pin, umode_t mode) ++{ ++ int do_sio; ++ struct super_block *sb; ++ struct inode *h_dir; ++ ++ do_sio = 0; ++ sb = au_pinned_parent(pin)->d_sb; ++ if (!au_wkq_test() ++ && (!au_sbi(sb)->si_plink_maint_pid ++ || au_plink_maint(sb, AuLock_NOPLM))) { ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ /* no condition about RLIMIT_FSIZE and the file size */ ++ do_sio = 1; ++ break; ++ case S_IFCHR: ++ case S_IFBLK: ++ do_sio = !capable(CAP_MKNOD); ++ break; ++ } ++ if (!do_sio) ++ do_sio = ((mode & (S_ISUID | S_ISGID)) ++ && !capable(CAP_FSETID)); ++ /* this workaround may be removed in the future */ ++ if (!do_sio) { ++ h_dir = au_pinned_h_dir(pin); ++ do_sio = h_dir->i_mode & S_ISVTX; ++ } ++ } ++ ++ return do_sio; ++} ++ ++#if 0 /* reserved */ ++int au_sio_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) ++{ ++ int err, wkq_err; ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(cpg->dentry, cpg->bsrc); ++ if (!au_cpup_sio_test(pin, d_inode(h_dentry)->i_mode)) ++ err = au_cpup_single(cpg, dst_parent); ++ else { ++ struct au_cpup_single_args args = { ++ .errp = &err, ++ .cpg = cpg, ++ .dst_parent = dst_parent ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_single, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++#endif ++ ++/* ++ * copyup the @dentry from the first active lower branch to @bdst, ++ * using au_cpup_single(). ++ */ ++static int au_cpup_simple(struct au_cp_generic *cpg) ++{ ++ int err; ++ unsigned int flags_orig; ++ struct dentry *dentry; ++ ++ AuDebugOn(cpg->bsrc < 0); ++ ++ dentry = cpg->dentry; ++ DiMustWriteLock(dentry); ++ ++ err = au_lkup_neg(dentry, cpg->bdst, /*wh*/1); ++ if (!err) { ++ flags_orig = cpg->flags; ++ au_fset_cpup(cpg->flags, RENAME); ++ err = au_cpup_single(cpg, NULL); ++ cpg->flags = flags_orig; ++ if (!err) ++ return 0; /* success */ ++ ++ /* revert */ ++ au_set_h_dptr(dentry, cpg->bdst, NULL); ++ au_set_dbtop(dentry, cpg->bsrc); ++ } ++ ++ return err; ++} ++ ++struct au_cpup_simple_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++}; ++ ++static void au_call_cpup_simple(void *args) ++{ ++ struct au_cpup_simple_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_simple(a->cpg); ++ au_pin_hdir_release(a->cpg->pin); ++} ++ ++static int au_do_sio_cpup_simple(struct au_cp_generic *cpg) ++{ ++ int err, wkq_err; ++ struct dentry *dentry, *parent; ++ struct file *h_file; ++ struct inode *h_dir; ++ struct user_namespace *h_userns; ++ ++ dentry = cpg->dentry; ++ h_file = NULL; ++ if (au_ftest_cpup(cpg->flags, HOPEN)) { ++ AuDebugOn(cpg->bsrc < 0); ++ h_file = au_h_open_pre(dentry, cpg->bsrc, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ } ++ ++ parent = dget_parent(dentry); ++ h_dir = au_h_iptr(d_inode(parent), cpg->bdst); ++ h_userns = au_sbr_userns(dentry->d_sb, cpg->bdst); ++ if (!au_test_h_perm_sio(h_userns, h_dir, MAY_EXEC | MAY_WRITE) ++ && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode)) ++ err = au_cpup_simple(cpg); ++ else { ++ struct au_cpup_simple_args args = { ++ .errp = &err, ++ .cpg = cpg ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_simple, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ dput(parent); ++ if (h_file) ++ au_h_open_post(dentry, cpg->bsrc, h_file); ++ ++out: ++ return err; ++} ++ ++int au_sio_cpup_simple(struct au_cp_generic *cpg) ++{ ++ aufs_bindex_t bsrc, bbot; ++ struct dentry *dentry, *h_dentry; ++ ++ if (cpg->bsrc < 0) { ++ dentry = cpg->dentry; ++ bbot = au_dbbot(dentry); ++ for (bsrc = cpg->bdst + 1; bsrc <= bbot; bsrc++) { ++ h_dentry = au_h_dptr(dentry, bsrc); ++ if (h_dentry) { ++ AuDebugOn(d_is_negative(h_dentry)); ++ break; ++ } ++ } ++ AuDebugOn(bsrc > bbot); ++ cpg->bsrc = bsrc; ++ } ++ AuDebugOn(cpg->bsrc <= cpg->bdst); ++ return au_do_sio_cpup_simple(cpg); ++} ++ ++int au_sio_cpdown_simple(struct au_cp_generic *cpg) ++{ ++ AuDebugOn(cpg->bdst <= cpg->bsrc); ++ return au_do_sio_cpup_simple(cpg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * copyup the deleted file for writing. ++ */ ++static int au_do_cpup_wh(struct au_cp_generic *cpg, struct dentry *wh_dentry, ++ struct file *file) ++{ ++ int err; ++ unsigned int flags_orig; ++ aufs_bindex_t bsrc_orig; ++ struct au_dinfo *dinfo; ++ struct { ++ struct au_hdentry *hd; ++ struct dentry *h_dentry; ++ } hdst, hsrc; ++ ++ dinfo = au_di(cpg->dentry); ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ bsrc_orig = cpg->bsrc; ++ cpg->bsrc = dinfo->di_btop; ++ hdst.hd = au_hdentry(dinfo, cpg->bdst); ++ hdst.h_dentry = hdst.hd->hd_dentry; ++ hdst.hd->hd_dentry = wh_dentry; ++ dinfo->di_btop = cpg->bdst; ++ ++ hsrc.h_dentry = NULL; ++ if (file) { ++ hsrc.hd = au_hdentry(dinfo, cpg->bsrc); ++ hsrc.h_dentry = hsrc.hd->hd_dentry; ++ hsrc.hd->hd_dentry = au_hf_top(file)->f_path.dentry; ++ } ++ flags_orig = cpg->flags; ++ cpg->flags = !AuCpup_DTIME; ++ err = au_cpup_single(cpg, /*h_parent*/NULL); ++ cpg->flags = flags_orig; ++ if (file) { ++ if (!err) ++ err = au_reopen_nondir(file); ++ hsrc.hd->hd_dentry = hsrc.h_dentry; ++ } ++ hdst.hd->hd_dentry = hdst.h_dentry; ++ dinfo->di_btop = cpg->bsrc; ++ cpg->bsrc = bsrc_orig; ++ ++ return err; ++} ++ ++static int au_cpup_wh(struct au_cp_generic *cpg, struct file *file) ++{ ++ int err; ++ aufs_bindex_t bdst; ++ struct au_dtime dt; ++ struct dentry *dentry, *parent, *h_parent, *wh_dentry; ++ struct au_branch *br; ++ struct path h_path; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ br = au_sbr(dentry->d_sb, bdst); ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ wh_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ h_path.dentry = h_parent; ++ h_path.mnt = au_br_mnt(br); ++ au_dtime_store(&dt, parent, &h_path); ++ err = au_do_cpup_wh(cpg, wh_dentry, file); ++ if (unlikely(err)) ++ goto out_wh; ++ ++ dget(wh_dentry); ++ h_path.dentry = wh_dentry; ++ if (!d_is_dir(wh_dentry)) { ++ /* no delegation since it is just created */ ++ err = vfsub_unlink(d_inode(h_parent), &h_path, ++ /*delegated*/NULL, /*force*/0); ++ } else ++ err = vfsub_rmdir(d_inode(h_parent), &h_path); ++ if (unlikely(err)) { ++ AuIOErr("failed remove copied-up tmp file %pd(%d)\n", ++ wh_dentry, err); ++ err = -EIO; ++ } ++ au_dtime_revert(&dt); ++ au_set_hi_wh(d_inode(dentry), bdst, wh_dentry); ++ ++out_wh: ++ dput(wh_dentry); ++out: ++ dput(parent); ++ return err; ++} ++ ++struct au_cpup_wh_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++ struct file *file; ++}; ++ ++static void au_call_cpup_wh(void *args) ++{ ++ struct au_cpup_wh_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_wh(a->cpg, a->file); ++ au_pin_hdir_release(a->cpg->pin); ++} ++ ++int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file) ++{ ++ int err, wkq_err; ++ aufs_bindex_t bdst; ++ struct dentry *dentry, *parent, *h_orph, *h_parent; ++ struct inode *dir, *h_dir, *h_tmpdir; ++ struct au_wbr *wbr; ++ struct au_pin wh_pin, *pin_orig; ++ struct user_namespace *h_userns; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ h_orph = NULL; ++ h_parent = NULL; ++ h_dir = au_igrab(au_h_iptr(dir, bdst)); ++ h_tmpdir = h_dir; ++ pin_orig = NULL; ++ if (!h_dir->i_nlink) { ++ wbr = au_sbr(dentry->d_sb, bdst)->br_wbr; ++ h_orph = wbr->wbr_orph; ++ ++ h_parent = dget(au_h_dptr(parent, bdst)); ++ au_set_h_dptr(parent, bdst, dget(h_orph)); ++ h_tmpdir = d_inode(h_orph); ++ au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0); ++ ++ inode_lock_nested(h_tmpdir, AuLsc_I_PARENT3); ++ /* todo: au_h_open_pre()? */ ++ ++ pin_orig = cpg->pin; ++ au_pin_init(&wh_pin, dentry, bdst, AuLsc_DI_PARENT, ++ AuLsc_I_PARENT3, cpg->pin->udba, AuPin_DI_LOCKED); ++ cpg->pin = &wh_pin; ++ } ++ ++ h_userns = au_sbr_userns(dentry->d_sb, bdst); ++ if (!au_test_h_perm_sio(h_userns, h_tmpdir, MAY_EXEC | MAY_WRITE) ++ && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode)) ++ err = au_cpup_wh(cpg, file); ++ else { ++ struct au_cpup_wh_args args = { ++ .errp = &err, ++ .cpg = cpg, ++ .file = file ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_wh, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ if (h_orph) { ++ inode_unlock(h_tmpdir); ++ /* todo: au_h_open_post()? */ ++ au_set_h_iptr(dir, bdst, au_igrab(h_dir), /*flags*/0); ++ au_set_h_dptr(parent, bdst, h_parent); ++ AuDebugOn(!pin_orig); ++ cpg->pin = pin_orig; ++ } ++ iput(h_dir); ++ dput(parent); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * generic routine for both of copy-up and copy-down. ++ */ ++/* cf. revalidate function in file.c */ ++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg), ++ void *arg) ++{ ++ int err; ++ struct au_pin pin; ++ struct dentry *d, *parent, *h_parent, *real_parent, *h_dentry; ++ ++ err = 0; ++ parent = dget_parent(dentry); ++ if (IS_ROOT(parent)) ++ goto out; ++ ++ au_pin_init(&pin, dentry, bdst, AuLsc_DI_PARENT2, AuLsc_I_PARENT2, ++ au_opt_udba(dentry->d_sb), AuPin_MNT_WRITE); ++ ++ /* do not use au_dpage */ ++ real_parent = parent; ++ while (1) { ++ dput(parent); ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ if (h_parent) ++ goto out; /* success */ ++ ++ /* find top dir which is necessary to cpup */ ++ do { ++ d = parent; ++ dput(parent); ++ parent = dget_parent(d); ++ di_read_lock_parent3(parent, !AuLock_IR); ++ h_parent = au_h_dptr(parent, bdst); ++ di_read_unlock(parent, !AuLock_IR); ++ } while (!h_parent); ++ ++ if (d != real_parent) ++ di_write_lock_child3(d); ++ ++ /* somebody else might create while we were sleeping */ ++ h_dentry = au_h_dptr(d, bdst); ++ if (!h_dentry || d_is_negative(h_dentry)) { ++ if (h_dentry) ++ au_update_dbtop(d); ++ ++ au_pin_set_dentry(&pin, d); ++ err = au_do_pin(&pin); ++ if (!err) { ++ err = cp(d, bdst, &pin, h_parent, arg); ++ au_unpin(&pin); ++ } ++ } ++ ++ if (d != real_parent) ++ di_write_unlock(d); ++ if (unlikely(err)) ++ break; ++ } ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++static int au_cpup_dir(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent __maybe_unused, ++ void *arg __maybe_unused) ++{ ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = bdst, ++ .bsrc = -1, ++ .len = 0, ++ .pin = pin, ++ .flags = AuCpup_DTIME ++ }; ++ return au_sio_cpup_simple(&cpg); ++} ++ ++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ return au_cp_dirs(dentry, bdst, au_cpup_dir, NULL); ++} ++ ++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ int err; ++ struct dentry *parent; ++ struct inode *dir; ++ ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ err = 0; ++ if (au_h_iptr(dir, bdst)) ++ goto out; ++ ++ di_read_unlock(parent, AuLock_IR); ++ di_write_lock_parent(parent); ++ /* someone else might change our inode while we were sleeping */ ++ if (!au_h_iptr(dir, bdst)) ++ err = au_cpup_dirs(dentry, bdst); ++ di_downgrade_lock(parent, AuLock_IR); ++ ++out: ++ dput(parent); ++ return err; ++} +diff -Naur null/fs/aufs/cpup.h linux-5.15.36/fs/aufs/cpup.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/cpup.h 2022-05-10 16:51:39.867744220 +0300 +@@ -0,0 +1,100 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * copy-up/down functions ++ */ ++ ++#ifndef __AUFS_CPUP_H__ ++#define __AUFS_CPUP_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct inode; ++struct file; ++struct au_pin; ++ ++void au_cpup_attr_flags(struct inode *dst, unsigned int iflags); ++void au_cpup_attr_timesizes(struct inode *inode); ++void au_cpup_attr_nlink(struct inode *inode, int force); ++void au_cpup_attr_changeable(struct inode *inode); ++void au_cpup_igen(struct inode *inode, struct inode *h_inode); ++void au_cpup_attr_all(struct inode *inode, int force); ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_cp_generic { ++ struct dentry *dentry; ++ aufs_bindex_t bdst, bsrc; ++ loff_t len; ++ struct au_pin *pin; ++ unsigned int flags; ++}; ++ ++/* cpup flags */ ++#define AuCpup_DTIME 1 /* do dtime_store/revert */ ++#define AuCpup_KEEPLINO (1 << 1) /* do not clear the lower xino, ++ for link(2) */ ++#define AuCpup_RENAME (1 << 2) /* rename after cpup */ ++#define AuCpup_HOPEN (1 << 3) /* call h_open_pre/post() in ++ cpup */ ++#define AuCpup_OVERWRITE (1 << 4) /* allow overwriting the ++ existing entry */ ++#define AuCpup_RWDST (1 << 5) /* force write target even if ++ the branch is marked as RO */ ++ ++#ifndef CONFIG_AUFS_BR_HFSPLUS ++#undef AuCpup_HOPEN ++#define AuCpup_HOPEN 0 ++#endif ++ ++#define au_ftest_cpup(flags, name) ((flags) & AuCpup_##name) ++#define au_fset_cpup(flags, name) \ ++ do { (flags) |= AuCpup_##name; } while (0) ++#define au_fclr_cpup(flags, name) \ ++ do { (flags) &= ~AuCpup_##name; } while (0) ++ ++int au_copy_file(struct file *dst, struct file *src, loff_t len); ++int au_sio_cpup_simple(struct au_cp_generic *cpg); ++int au_sio_cpdown_simple(struct au_cp_generic *cpg); ++int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file); ++ ++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg), ++ void *arg); ++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* keep timestamps when copyup */ ++struct au_dtime { ++ struct dentry *dt_dentry; ++ struct path dt_h_path; ++ struct timespec64 dt_atime, dt_mtime; ++}; ++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, ++ struct path *h_path); ++void au_dtime_revert(struct au_dtime *dt); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_CPUP_H__ */ +diff -Naur null/fs/aufs/dbgaufs.c linux-5.15.36/fs/aufs/dbgaufs.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/dbgaufs.c 2022-05-10 16:51:39.867744220 +0300 +@@ -0,0 +1,526 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * debugfs interface ++ */ ++ ++#include ++#include "aufs.h" ++ ++#ifndef CONFIG_SYSFS ++#error DEBUG_FS depends upon SYSFS ++#endif ++ ++static struct dentry *dbgaufs; ++static const mode_t dbgaufs_mode = 0444; ++ ++/* 20 is max digits length of ulong 64 */ ++struct dbgaufs_arg { ++ int n; ++ char a[20 * 4]; ++}; ++ ++/* ++ * common function for all XINO files ++ */ ++static int dbgaufs_xi_release(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ 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, ++ int cnt) ++{ ++ int err; ++ struct kstat st; ++ struct dbgaufs_arg *p; ++ ++ err = -ENOMEM; ++ p = kmalloc(sizeof(*p), GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = 0; ++ p->n = 0; ++ file->private_data = p; ++ if (!xf) ++ goto out; ++ ++ err = vfsub_getattr(&xf->f_path, &st); ++ if (!err) { ++ if (do_fcnt) ++ p->n = snprintf ++ (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", ++ st.blocks, st.blksize, ++ (long long)st.size); ++ AuDebugOn(p->n >= sizeof(p->a)); ++ } else { ++ p->n = snprintf(p->a, sizeof(p->a), "err %d\n", err); ++ err = 0; ++ } ++ ++out: ++ return err; ++} ++ ++static ssize_t dbgaufs_xi_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct dbgaufs_arg *p; ++ ++ p = file->private_data; ++ return simple_read_from_buffer(buf, count, ppos, p->a, p->n); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dbgaufs_plink_arg { ++ int n; ++ char a[]; ++}; ++ ++static int dbgaufs_plink_release(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ free_page((unsigned long)file->private_data); ++ return 0; ++} ++ ++static int dbgaufs_plink_open(struct inode *inode, struct file *file) ++{ ++ int err, i, limit; ++ unsigned long n, sum; ++ struct dbgaufs_plink_arg *p; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct hlist_bl_head *hbl; ++ ++ err = -ENOMEM; ++ p = (void *)get_zeroed_page(GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = -EFBIG; ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ limit = PAGE_SIZE - sizeof(p->n); ++ ++ /* the number of buckets */ ++ n = snprintf(p->a + p->n, limit, "%d\n", AuPlink_NHASH); ++ p->n += n; ++ limit -= n; ++ ++ sum = 0; ++ for (i = 0, hbl = sbinfo->si_plink; i < AuPlink_NHASH; ++ i++, hbl++) { ++ n = au_hbl_count(hbl); ++ sum += n; ++ ++ n = snprintf(p->a + p->n, limit, "%lu ", n); ++ p->n += n; ++ limit -= n; ++ if (unlikely(limit <= 0)) ++ goto out_free; ++ } ++ p->a[p->n - 1] = '\n'; ++ ++ /* the sum of plinks */ ++ n = snprintf(p->a + p->n, limit, "%lu\n", sum); ++ p->n += n; ++ limit -= n; ++ if (unlikely(limit <= 0)) ++ goto out_free; ++ } else { ++#define str "1\n0\n0\n" ++ p->n = sizeof(str) - 1; ++ strcpy(p->a, str); ++#undef str ++ } ++ si_read_unlock(sb); ++ ++ err = 0; ++ file->private_data = p; ++ goto out; /* success */ ++ ++out_free: ++ free_page((unsigned long)p); ++out: ++ return err; ++} ++ ++static ssize_t dbgaufs_plink_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct dbgaufs_plink_arg *p; ++ ++ p = file->private_data; ++ return simple_read_from_buffer(buf, count, ppos, p->a, p->n); ++} ++ ++static const struct file_operations dbgaufs_plink_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_plink_open, ++ .release = dbgaufs_plink_release, ++ .read = dbgaufs_plink_read ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int dbgaufs_xib_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ err = dbgaufs_xi_open(sbinfo->si_xib, file, /*do_fcnt*/0, /*cnt*/0); ++ si_read_unlock(sb); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xib_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xib_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define DbgaufsXi_PREFIX "xi" ++ ++static int dbgaufs_xino_open(struct inode *inode, struct file *file) ++{ ++ 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; ++ 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; ++ ++ 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 (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; ++} ++ ++static const struct file_operations dbgaufs_xino_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xino_open, ++ .release = dbgaufs_xi_release, ++ .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; ++ ++ if (!au_sbi(sb)->si_dbgaufs) ++ return; ++ ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ 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(); ++ br->br_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent, ++ sbinfo, &dbgaufs_xino_fop); ++ lockdep_on(); ++ if (unlikely(!br->br_dbgaufs)) ++ pr_warn("failed creating %pd/%s, ignored.\n", ++ parent, name); ++ } ++} ++ ++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; ++ aufs_bindex_t bbot; ++ ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return; ++ ++ sbinfo = au_sbi(sb); ++ parent = sbinfo->si_dbgaufs; ++ if (!parent) ++ return; ++ ++ bbot = au_sbbot(sb); ++ 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); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++static int dbgaufs_xigen_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ err = dbgaufs_xi_open(sbinfo->si_xigen, file, /*do_fcnt*/0, /*cnt*/0); ++ si_read_unlock(sb); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xigen_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xigen_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ err = -EIO; ++ sbinfo->si_dbgaufs_xigen = debugfs_create_file ++ ("xigen", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_xigen_fop); ++ if (sbinfo->si_dbgaufs_xigen) ++ err = 0; ++ ++ return err; ++} ++#else ++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) ++{ ++ return 0; ++} ++#endif /* CONFIG_AUFS_EXPORT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++void dbgaufs_si_fin(struct au_sbinfo *sbinfo) ++{ ++ /* ++ * This function is a dynamic '__fin' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ debugfs_remove_recursive(sbinfo->si_dbgaufs); ++ sbinfo->si_dbgaufs = NULL; ++} ++ ++int dbgaufs_si_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ char name[SysaufsSiNameLen]; ++ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ err = -ENOENT; ++ if (!dbgaufs) { ++ AuErr1("/debug/aufs is uninitialized\n"); ++ goto out; ++ } ++ ++ err = -EIO; ++ sysaufs_name(sbinfo, name); ++ sbinfo->si_dbgaufs = debugfs_create_dir(name, dbgaufs); ++ if (unlikely(!sbinfo->si_dbgaufs)) ++ goto out; ++ ++ /* 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 */ ++ ++out_dir: ++ dbgaufs_si_fin(sbinfo); ++out: ++ if (unlikely(err)) ++ pr_err("debugfs/aufs failed\n"); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void dbgaufs_fin(void) ++{ ++ debugfs_remove(dbgaufs); ++} ++ ++int __init dbgaufs_init(void) ++{ ++ int err; ++ ++ err = -EIO; ++ dbgaufs = debugfs_create_dir(AUFS_NAME, NULL); ++ if (dbgaufs) ++ err = 0; ++ return err; ++} +diff -Naur null/fs/aufs/dbgaufs.h linux-5.15.36/fs/aufs/dbgaufs.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/dbgaufs.h 2022-05-10 16:51:39.867744220 +0300 +@@ -0,0 +1,53 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * debugfs interface ++ */ ++ ++#ifndef __DBGAUFS_H__ ++#define __DBGAUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++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, 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, ++ int topdown) ++AuStubVoid(dbgaufs_si_fin, struct au_sbinfo *sbinfo) ++AuStubInt0(dbgaufs_si_init, struct au_sbinfo *sbinfo) ++AuStubVoid(dbgaufs_fin, void) ++AuStubInt0(__init dbgaufs_init, void) ++#endif /* CONFIG_DEBUG_FS */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __DBGAUFS_H__ */ +diff -Naur null/fs/aufs/dcsub.c linux-5.15.36/fs/aufs/dcsub.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/dcsub.c 2022-05-10 16:51:39.867744220 +0300 +@@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * sub-routines for dentry cache ++ */ ++ ++#include "aufs.h" ++ ++static void au_dpage_free(struct au_dpage *dpage) ++{ ++ int i; ++ struct dentry **p; ++ ++ p = dpage->dentries; ++ for (i = 0; i < dpage->ndentry; i++) ++ dput(*p++); ++ free_page((unsigned long)dpage->dentries); ++} ++ ++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp) ++{ ++ int err; ++ void *p; ++ ++ err = -ENOMEM; ++ dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp); ++ if (unlikely(!dpages->dpages)) ++ goto out; ++ ++ p = (void *)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out_dpages; ++ ++ dpages->dpages[0].ndentry = 0; ++ dpages->dpages[0].dentries = p; ++ dpages->ndpage = 1; ++ return 0; /* success */ ++ ++out_dpages: ++ au_kfree_try_rcu(dpages->dpages); ++out: ++ return err; ++} ++ ++void au_dpages_free(struct au_dcsub_pages *dpages) ++{ ++ int i; ++ struct au_dpage *p; ++ ++ p = dpages->dpages; ++ for (i = 0; i < dpages->ndpage; i++) ++ au_dpage_free(p++); ++ au_kfree_try_rcu(dpages->dpages); ++} ++ ++static int au_dpages_append(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, gfp_t gfp) ++{ ++ int err, sz; ++ struct au_dpage *dpage; ++ void *p; ++ ++ dpage = dpages->dpages + dpages->ndpage - 1; ++ sz = PAGE_SIZE / sizeof(dentry); ++ if (unlikely(dpage->ndentry >= sz)) { ++ AuLabel(new dpage); ++ err = -ENOMEM; ++ sz = dpages->ndpage * sizeof(*dpages->dpages); ++ p = au_kzrealloc(dpages->dpages, sz, ++ sz + sizeof(*dpages->dpages), gfp, ++ /*may_shrink*/0); ++ if (unlikely(!p)) ++ goto out; ++ ++ dpages->dpages = p; ++ dpage = dpages->dpages + dpages->ndpage; ++ p = (void *)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out; ++ ++ dpage->ndentry = 0; ++ dpage->dentries = p; ++ dpages->ndpage++; ++ } ++ ++ AuDebugOn(au_dcount(dentry) <= 0); ++ dpage->dentries[dpage->ndentry++] = dget_dlock(dentry); ++ return 0; /* success */ ++ ++out: ++ return err; ++} ++ ++/* todo: BAD approach */ ++/* copied from linux/fs/dcache.c */ ++enum d_walk_ret { ++ D_WALK_CONTINUE, ++ D_WALK_QUIT, ++ D_WALK_NORETRY, ++ D_WALK_SKIP, ++}; ++ ++extern void d_walk(struct dentry *parent, void *data, ++ enum d_walk_ret (*enter)(void *, struct dentry *)); ++ ++struct ac_dpages_arg { ++ int err; ++ struct au_dcsub_pages *dpages; ++ struct super_block *sb; ++ au_dpages_test test; ++ void *arg; ++}; ++ ++static enum d_walk_ret au_call_dpages_append(void *_arg, struct dentry *dentry) ++{ ++ enum d_walk_ret ret; ++ struct ac_dpages_arg *arg = _arg; ++ ++ ret = D_WALK_CONTINUE; ++ if (dentry->d_sb == arg->sb ++ && !IS_ROOT(dentry) ++ && au_dcount(dentry) > 0 ++ && au_di(dentry) ++ && (!arg->test || arg->test(dentry, arg->arg))) { ++ arg->err = au_dpages_append(arg->dpages, dentry, GFP_ATOMIC); ++ if (unlikely(arg->err)) ++ ret = D_WALK_QUIT; ++ } ++ ++ return ret; ++} ++ ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg) ++{ ++ struct ac_dpages_arg args = { ++ .err = 0, ++ .dpages = dpages, ++ .sb = root->d_sb, ++ .test = test, ++ .arg = arg ++ }; ++ ++ d_walk(root, &args, au_call_dpages_append); ++ ++ return args.err; ++} ++ ++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, ++ int do_include, au_dpages_test test, void *arg) ++{ ++ int err; ++ ++ err = 0; ++ write_seqlock(&rename_lock); ++ spin_lock(&dentry->d_lock); ++ if (do_include ++ && au_dcount(dentry) > 0 ++ && (!test || test(dentry, arg))) ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ spin_unlock(&dentry->d_lock); ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * RCU for vfsmount is unnecessary since this is a traverse in a single ++ * mount ++ */ ++ while (!IS_ROOT(dentry)) { ++ dentry = dentry->d_parent; /* rename_lock is locked */ ++ spin_lock(&dentry->d_lock); ++ if (au_dcount(dentry) > 0 ++ && (!test || test(dentry, arg))) ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ spin_unlock(&dentry->d_lock); ++ if (unlikely(err)) ++ break; ++ } ++ ++out: ++ write_sequnlock(&rename_lock); ++ return err; ++} ++ ++static inline int au_dcsub_dpages_aufs(struct dentry *dentry, void *arg) ++{ ++ return au_di(dentry) && dentry->d_sb == arg; ++} ++ ++int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, int do_include) ++{ ++ return au_dcsub_pages_rev(dpages, dentry, do_include, ++ au_dcsub_dpages_aufs, dentry->d_sb); ++} ++ ++int au_test_subdir(struct dentry *d1, struct dentry *d2) ++{ ++ struct path path[2] = { ++ { ++ .dentry = d1 ++ }, ++ { ++ .dentry = d2 ++ } ++ }; ++ ++ return path_is_under(path + 0, path + 1); ++} +diff -Naur null/fs/aufs/dcsub.h linux-5.15.36/fs/aufs/dcsub.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/dcsub.h 2022-05-10 16:51:39.867744220 +0300 +@@ -0,0 +1,137 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * sub-routines for dentry cache ++ */ ++ ++#ifndef __AUFS_DCSUB_H__ ++#define __AUFS_DCSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++struct au_dpage { ++ int ndentry; ++ struct dentry **dentries; ++}; ++ ++struct au_dcsub_pages { ++ int ndpage; ++ struct au_dpage *dpages; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dcsub.c */ ++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp); ++void au_dpages_free(struct au_dcsub_pages *dpages); ++typedef int (*au_dpages_test)(struct dentry *dentry, void *arg); ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg); ++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, ++ int do_include, au_dpages_test test, void *arg); ++int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, int do_include); ++int au_test_subdir(struct dentry *d1, struct dentry *d2); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * todo: in linux-3.13, several similar (but faster) helpers are added to ++ * include/linux/dcache.h. Try them (in the future). ++ */ ++ ++static inline int au_d_hashed_positive(struct dentry *d) ++{ ++ int err; ++ struct inode *inode = d_inode(d); ++ ++ err = 0; ++ if (unlikely(d_unhashed(d) ++ || d_is_negative(d) ++ || !inode->i_nlink)) ++ err = -ENOENT; ++ return err; ++} ++ ++static inline int au_d_linkable(struct dentry *d) ++{ ++ int err; ++ struct inode *inode = d_inode(d); ++ ++ err = au_d_hashed_positive(d); ++ if (err ++ && d_is_positive(d) ++ && (inode->i_state & I_LINKABLE)) ++ err = 0; ++ return err; ++} ++ ++static inline int au_d_alive(struct dentry *d) ++{ ++ int err; ++ struct inode *inode; ++ ++ err = 0; ++ if (!IS_ROOT(d)) ++ err = au_d_hashed_positive(d); ++ else { ++ inode = d_inode(d); ++ if (unlikely(d_unlinked(d) ++ || d_is_negative(d) ++ || !inode->i_nlink)) ++ err = -ENOENT; ++ } ++ return err; ++} ++ ++static inline int au_alive_dir(struct dentry *d) ++{ ++ int err; ++ ++ err = au_d_alive(d); ++ if (unlikely(err || IS_DEADDIR(d_inode(d)))) ++ err = -ENOENT; ++ return err; ++} ++ ++static inline int au_qstreq(struct qstr *a, struct qstr *b) ++{ ++ return a->len == b->len ++ && !memcmp(a->name, b->name, a->len); ++} ++ ++/* ++ * by the commit ++ * 360f547 2015-01-25 dcache: let the dentry count go down to zero without ++ * taking d_lock ++ * the type of d_lockref.count became int, but the inlined function d_count() ++ * still returns unsigned int. ++ * I don't know why. Maybe it is for every d_count() users? ++ * Anyway au_dcount() lives on. ++ */ ++static inline int au_dcount(struct dentry *d) ++{ ++ return (int)d_count(d); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DCSUB_H__ */ +diff -Naur null/fs/aufs/debug.c linux-5.15.36/fs/aufs/debug.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/debug.c 2022-05-10 16:51:39.868744219 +0300 +@@ -0,0 +1,444 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * debug print functions ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* Returns 0, or -errno. arg is in kp->arg. */ ++static int param_atomic_t_set(const char *val, const struct kernel_param *kp) ++{ ++ int err, n; ++ ++ err = kstrtoint(val, 0, &n); ++ if (!err) { ++ if (n > 0) ++ au_debug_on(); ++ else ++ au_debug_off(); ++ } ++ return err; ++} ++ ++/* Returns length written or -errno. Buffer is 4k (ie. be short!) */ ++static int param_atomic_t_get(char *buffer, const struct kernel_param *kp) ++{ ++ atomic_t *a; ++ ++ a = kp->arg; ++ return sprintf(buffer, "%d", atomic_read(a)); ++} ++ ++static struct kernel_param_ops param_ops_atomic_t = { ++ .set = param_atomic_t_set, ++ .get = param_atomic_t_get ++ /* void (*free)(void *arg) */ ++}; ++ ++atomic_t aufs_debug = ATOMIC_INIT(0); ++MODULE_PARM_DESC(debug, "debug print"); ++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; ++#define dpri(fmt, ...) do { \ ++ if ((au_plevel \ ++ && strcmp(au_plevel, KERN_DEBUG)) \ ++ || au_debug_test()) \ ++ printk("%s" fmt, au_plevel, ##__VA_ARGS__); \ ++} while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_dpri_whlist(struct au_nhash *whlist) ++{ ++ unsigned long ul, n; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (ul = 0; ul < n; ul++) { ++ hlist_for_each_entry(pos, head, wh_hash) ++ dpri("b%d, %.*s, %d\n", ++ pos->wh_bindex, ++ pos->wh_str.len, pos->wh_str.name, ++ pos->wh_str.len); ++ head++; ++ } ++} ++ ++void au_dpri_vdir(struct au_vdir *vdir) ++{ ++ unsigned long ul; ++ union au_vdir_deblk_p p; ++ unsigned char *o; ++ ++ if (!vdir || IS_ERR(vdir)) { ++ dpri("err %ld\n", PTR_ERR(vdir)); ++ return; ++ } ++ ++ dpri("deblk %u, nblk %lu, deblk %p, last{%lu, %p}, ver %llu\n", ++ vdir->vd_deblk_sz, vdir->vd_nblk, vdir->vd_deblk, ++ vdir->vd_last.ul, vdir->vd_last.p.deblk, vdir->vd_version); ++ for (ul = 0; ul < vdir->vd_nblk; ul++) { ++ p.deblk = vdir->vd_deblk[ul]; ++ o = p.deblk; ++ dpri("[%lu]: %p\n", ul, o); ++ } ++} ++ ++static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode, int hn, ++ struct dentry *wh) ++{ ++ char *n = NULL; ++ int l = 0; ++ ++ if (!inode || IS_ERR(inode)) { ++ dpri("i%d: err %ld\n", bindex, PTR_ERR(inode)); ++ return -1; ++ } ++ ++ /* the type of i_blocks depends upon CONFIG_LBDAF */ ++ BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long) ++ && sizeof(inode->i_blocks) != sizeof(u64)); ++ if (wh) { ++ n = (void *)wh->d_name.name; ++ l = wh->d_name.len; ++ } ++ ++ dpri("i%d: %p, i%lu, %s, cnt %d, nl %u, 0%o, sz %llu, blk %llu," ++ " hn %d, ct %lld, np %lu, st 0x%lx, f 0x%x, v %llu, g %x%s%.*s\n", ++ bindex, inode, ++ 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)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, ++ l ? ", wh " : "", l, n); ++ return 0; ++} ++ ++void au_dpri_inode(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ aufs_bindex_t bindex; ++ int err, hn; ++ ++ err = do_pri_inode(-1, inode, -1, NULL); ++ if (err || !au_test_aufs(inode->i_sb) || au_is_bad_inode(inode)) ++ return; ++ ++ iinfo = au_ii(inode); ++ dpri("i-1: btop %d, bbot %d, gen %d\n", ++ iinfo->ii_btop, iinfo->ii_bbot, au_iigen(inode, NULL)); ++ if (iinfo->ii_btop < 0) ++ return; ++ hn = 0; ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; bindex++) { ++ hi = au_hinode(iinfo, bindex); ++ hn = !!au_hn(hi); ++ do_pri_inode(bindex, hi->hi_inode, hn, hi->hi_whdentry); ++ } ++} ++ ++void au_dpri_dalias(struct inode *inode) ++{ ++ struct dentry *d; ++ ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) ++ au_dpri_dentry(d); ++ spin_unlock(&inode->i_lock); ++} ++ ++static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry) ++{ ++ struct dentry *wh = NULL; ++ int hn; ++ struct inode *inode; ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ ++ if (!dentry || IS_ERR(dentry)) { ++ dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry)); ++ return -1; ++ } ++ /* do not call dget_parent() here */ ++ /* note: access d_xxx without d_lock */ ++ dpri("d%d: %p, %pd2?, %s, cnt %d, flags 0x%x, %shashed\n", ++ bindex, dentry, dentry, ++ dentry->d_sb ? au_sbtype(dentry->d_sb) : "??", ++ au_dcount(dentry), dentry->d_flags, ++ d_unhashed(dentry) ? "un" : ""); ++ hn = -1; ++ inode = NULL; ++ if (d_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (inode ++ && au_test_aufs(dentry->d_sb) ++ && bindex >= 0 ++ && !au_is_bad_inode(inode)) { ++ iinfo = au_ii(inode); ++ hi = au_hinode(iinfo, bindex); ++ hn = !!au_hn(hi); ++ wh = hi->hi_whdentry; ++ } ++ do_pri_inode(bindex, inode, hn, wh); ++ return 0; ++} ++ ++void au_dpri_dentry(struct dentry *dentry) ++{ ++ struct au_dinfo *dinfo; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_dentry(-1, dentry); ++ if (err || !au_test_aufs(dentry->d_sb)) ++ return; ++ ++ dinfo = au_di(dentry); ++ if (!dinfo) ++ return; ++ dpri("d-1: btop %d, bbot %d, bwh %d, bdiropq %d, gen %d, tmp %d\n", ++ dinfo->di_btop, dinfo->di_bbot, ++ dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry), ++ dinfo->di_tmpfile); ++ if (dinfo->di_btop < 0) ++ return; ++ for (bindex = dinfo->di_btop; bindex <= dinfo->di_bbot; bindex++) ++ do_pri_dentry(bindex, au_hdentry(dinfo, bindex)->hd_dentry); ++} ++ ++static int do_pri_file(aufs_bindex_t bindex, struct file *file) ++{ ++ char a[32]; ++ ++ if (!file || IS_ERR(file)) { ++ dpri("f%d: err %ld\n", bindex, PTR_ERR(file)); ++ return -1; ++ } ++ a[0] = 0; ++ if (bindex < 0 ++ && !IS_ERR_OR_NULL(file->f_path.dentry) ++ && au_test_aufs(file->f_path.dentry->d_sb) ++ && au_fi(file)) ++ snprintf(a, sizeof(a), ", gen %d, mmapped %d", ++ au_figen(file), atomic_read(&au_fi(file)->fi_mmapped)); ++ dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, v %llu, pos %llu%s\n", ++ bindex, file->f_mode, file->f_flags, (long)file_count(file), ++ file->f_version, file->f_pos, a); ++ if (!IS_ERR_OR_NULL(file->f_path.dentry)) ++ do_pri_dentry(bindex, file->f_path.dentry); ++ return 0; ++} ++ ++void au_dpri_file(struct file *file) ++{ ++ struct au_finfo *finfo; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_file(-1, file); ++ if (err ++ || IS_ERR_OR_NULL(file->f_path.dentry) ++ || !au_test_aufs(file->f_path.dentry->d_sb)) ++ return; ++ ++ finfo = au_fi(file); ++ if (!finfo) ++ return; ++ if (finfo->fi_btop < 0) ++ return; ++ fidir = finfo->fi_hdir; ++ if (!fidir) ++ do_pri_file(finfo->fi_btop, finfo->fi_htop.hf_file); ++ else ++ for (bindex = finfo->fi_btop; ++ bindex >= 0 && bindex <= fidir->fd_bbot; ++ bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ do_pri_file(bindex, hfile ? hfile->hf_file : NULL); ++ } ++} ++ ++static int do_pri_br(aufs_bindex_t bindex, struct au_branch *br) ++{ ++ struct vfsmount *mnt; ++ struct super_block *sb; ++ ++ if (!br || IS_ERR(br)) ++ goto out; ++ mnt = au_br_mnt(br); ++ if (!mnt || IS_ERR(mnt)) ++ goto out; ++ sb = mnt->mnt_sb; ++ if (!sb || IS_ERR(sb)) ++ goto out; ++ ++ 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, 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), ++ !!au_xino_file(br->br_xino, /*idx*/-1)); ++ return 0; ++ ++out: ++ dpri("s%d: err %ld\n", bindex, PTR_ERR(br)); ++ return -1; ++} ++ ++void au_dpri_sb(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ aufs_bindex_t bindex; ++ int err; ++ /* to reduce stack size */ ++ struct { ++ struct vfsmount mnt; ++ struct au_branch fake; ++ } *a; ++ ++ /* this function can be called from magic sysrq */ ++ a = kzalloc(sizeof(*a), GFP_ATOMIC); ++ if (unlikely(!a)) { ++ dpri("no memory\n"); ++ return; ++ } ++ ++ a->mnt.mnt_sb = sb; ++ a->fake.br_path.mnt = &a->mnt; ++ err = do_pri_br(-1, &a->fake); ++ au_kfree_rcu(a); ++ dpri("dev 0x%x\n", sb->s_dev); ++ if (err || !au_test_aufs(sb)) ++ return; ++ ++ sbinfo = au_sbi(sb); ++ if (!sbinfo) ++ return; ++ dpri("nw %d, gen %u, kobj %d\n", ++ atomic_read(&sbinfo->si_nowait.nw_len), sbinfo->si_generation, ++ kref_read(&sbinfo->si_kobj.kref)); ++ for (bindex = 0; bindex <= sbinfo->si_bbot; bindex++) ++ do_pri_br(bindex, sbinfo->si_branch[0 + bindex]); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line) ++{ ++ struct inode *h_inode, *inode = d_inode(dentry); ++ struct dentry *h_dentry; ++ aufs_bindex_t bindex, bbot, bi; ++ ++ if (!inode /* || au_di(dentry)->di_lsc == AuLsc_DI_TMP */) ++ return; ++ ++ bbot = au_dbbot(dentry); ++ bi = au_ibbot(inode); ++ if (bi < bbot) ++ bbot = bi; ++ bindex = au_dbtop(dentry); ++ bi = au_ibtop(inode); ++ if (bi > bindex) ++ bindex = bi; ++ ++ for (; bindex <= bbot; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(h_inode != d_inode(h_dentry))) { ++ au_debug_on(); ++ AuDbg("b%d, %s:%d\n", bindex, func, line); ++ AuDbgDentry(dentry); ++ AuDbgInode(inode); ++ au_debug_off(); ++ if (au_test_fuse(h_inode->i_sb)) ++ WARN_ON_ONCE(1); ++ else ++ BUG(); ++ } ++ } ++} ++ ++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen) ++{ ++ int err, i, j; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ AuDebugOn(err); ++ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/1); ++ AuDebugOn(err); ++ for (i = dpages.ndpage - 1; !err && i >= 0; i--) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ for (j = dpage->ndentry - 1; !err && j >= 0; j--) ++ AuDebugOn(au_digen_test(dentries[j], sigen)); ++ } ++ au_dpages_free(&dpages); ++} ++ ++void au_dbg_verify_kthread(void) ++{ ++ if (au_wkq_test()) { ++ au_dbg_blocked(); ++ /* ++ * It may be recursive, but udba=notify between two aufs mounts, ++ * where a single ro branch is shared, is not a problem. ++ */ ++ /* WARN_ON(1); */ ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int __init au_debug_init(void) ++{ ++ aufs_bindex_t bindex; ++ struct au_vdir_destr destr; ++ ++ bindex = -1; ++ AuDebugOn(bindex >= 0); ++ ++ destr.len = -1; ++ AuDebugOn(destr.len < NAME_MAX); ++ ++#ifdef CONFIG_4KSTACKS ++ pr_warn("CONFIG_4KSTACKS is defined.\n"); ++#endif ++ ++ return 0; ++} +diff -Naur null/fs/aufs/debug.h linux-5.15.36/fs/aufs/debug.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/debug.h 2022-05-10 16:51:39.868744219 +0300 +@@ -0,0 +1,226 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * debug print functions ++ */ ++ ++#ifndef __AUFS_DEBUG_H__ ++#define __AUFS_DEBUG_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define AuDebugOn(a) BUG_ON(a) ++ ++/* module parameter */ ++extern atomic_t aufs_debug; ++static inline void au_debug_on(void) ++{ ++ atomic_inc(&aufs_debug); ++} ++static inline void au_debug_off(void) ++{ ++ atomic_dec_if_positive(&aufs_debug); ++} ++ ++static inline int au_debug_test(void) ++{ ++ return atomic_read(&aufs_debug) > 0; ++} ++#else ++#define AuDebugOn(a) do {} while (0) ++AuStubVoid(au_debug_on, void) ++AuStubVoid(au_debug_off, void) ++AuStubInt0(au_debug_test, void) ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++#define param_check_atomic_t(name, p) __param_check(name, p, atomic_t) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* debug print */ ++ ++#define AuDbg(fmt, ...) do { \ ++ if (au_debug_test()) \ ++ pr_debug("DEBUG: " fmt, ##__VA_ARGS__); \ ++} while (0) ++#define AuLabel(l) AuDbg(#l "\n") ++#define AuIOErr(fmt, ...) pr_err("I/O Error, " fmt, ##__VA_ARGS__) ++#define AuWarn1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ pr_warn(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuErr1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ pr_err(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuIOErr1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ AuIOErr(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuUnsupportMsg "This operation is not supported." \ ++ " Please report this application to aufs-users ML." ++#define AuUnsupport(fmt, ...) do { \ ++ pr_err(AuUnsupportMsg "\n" fmt, ##__VA_ARGS__); \ ++ dump_stack(); \ ++} while (0) ++ ++#define AuTraceErr(e) do { \ ++ if (unlikely((e) < 0)) \ ++ AuDbg("err %d\n", (int)(e)); \ ++} while (0) ++ ++#define AuTraceErrPtr(p) do { \ ++ if (IS_ERR(p)) \ ++ AuDbg("err %ld\n", PTR_ERR(p)); \ ++} while (0) ++ ++/* dirty macros for debug print, use with "%.*s" and caution */ ++#define AuLNPair(qstr) (qstr)->len, (qstr)->name ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry; ++#ifdef CONFIG_AUFS_DEBUG ++extern struct mutex au_dbg_mtx; ++extern char *au_plevel; ++struct au_nhash; ++void au_dpri_whlist(struct au_nhash *whlist); ++struct au_vdir; ++void au_dpri_vdir(struct au_vdir *vdir); ++struct inode; ++void au_dpri_inode(struct inode *inode); ++void au_dpri_dalias(struct inode *inode); ++void au_dpri_dentry(struct dentry *dentry); ++struct file; ++void au_dpri_file(struct file *filp); ++struct super_block; ++void au_dpri_sb(struct super_block *sb); ++ ++#define au_dbg_verify_dinode(d) __au_dbg_verify_dinode(d, __func__, __LINE__) ++void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line); ++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen); ++void au_dbg_verify_kthread(void); ++ ++int __init au_debug_init(void); ++ ++#define AuDbgWhlist(w) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#w "\n"); \ ++ au_dpri_whlist(w); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgVdir(v) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#v "\n"); \ ++ au_dpri_vdir(v); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgInode(i) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#i "\n"); \ ++ au_dpri_inode(i); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgDAlias(i) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#i "\n"); \ ++ au_dpri_dalias(i); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgDentry(d) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#d "\n"); \ ++ au_dpri_dentry(d); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgFile(f) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#f "\n"); \ ++ au_dpri_file(f); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgSb(sb) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#sb "\n"); \ ++ au_dpri_sb(sb); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgSym(addr) do { \ ++ char sym[KSYM_SYMBOL_LEN]; \ ++ sprint_symbol(sym, (unsigned long)addr); \ ++ AuDbg("%s\n", sym); \ ++} while (0) ++#else ++AuStubVoid(au_dbg_verify_dinode, struct dentry *dentry) ++AuStubVoid(au_dbg_verify_gen, struct dentry *parent, unsigned int sigen) ++AuStubVoid(au_dbg_verify_kthread, void) ++AuStubInt0(__init au_debug_init, void) ++ ++#define AuDbgWhlist(w) do {} while (0) ++#define AuDbgVdir(v) do {} while (0) ++#define AuDbgInode(i) do {} while (0) ++#define AuDbgDAlias(i) do {} while (0) ++#define AuDbgDentry(d) do {} while (0) ++#define AuDbgFile(f) do {} while (0) ++#define AuDbgSb(sb) do {} while (0) ++#define AuDbgSym(addr) do {} while (0) ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_MAGIC_SYSRQ ++int __init au_sysrq_init(void); ++void au_sysrq_fin(void); ++ ++#ifdef CONFIG_HW_CONSOLE ++#define au_dbg_blocked() do { \ ++ WARN_ON(1); \ ++ handle_sysrq('w'); \ ++} while (0) ++#else ++AuStubVoid(au_dbg_blocked, void) ++#endif ++ ++#else ++AuStubInt0(__init au_sysrq_init, void) ++AuStubVoid(au_sysrq_fin, void) ++AuStubVoid(au_dbg_blocked, void) ++#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DEBUG_H__ */ +diff -Naur null/fs/aufs/dentry.c linux-5.15.36/fs/aufs/dentry.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/dentry.c 2022-05-10 16:51:39.868744219 +0300 +@@ -0,0 +1,1168 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * lookup and dentry operations ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * returns positive/negative dentry, NULL or an error. ++ * NULL means whiteout-ed or not-found. ++ */ ++static struct dentry* ++au_do_lookup(struct dentry *h_parent, struct dentry *dentry, ++ aufs_bindex_t bindex, struct au_do_lookup_args *args) ++{ ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_branch *br; ++ struct user_namespace *h_userns; ++ struct path h_path; ++ int wh_found, opq; ++ unsigned char wh_able; ++ const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG); ++ const unsigned char ignore_perm = !!au_ftest_lkup(args->flags, ++ IGNORE_PERM); ++ ++ wh_found = 0; ++ br = au_sbr(dentry->d_sb, bindex); ++ h_path.dentry = h_parent; ++ h_path.mnt = au_br_mnt(br); ++ h_userns = au_br_userns(br); ++ wh_able = !!au_br_whable(br->br_perm); ++ if (wh_able) ++ wh_found = au_wh_test(h_userns, &h_path, &args->whname, ++ ignore_perm); ++ h_dentry = ERR_PTR(wh_found); ++ if (!wh_found) ++ goto real_lookup; ++ if (unlikely(wh_found < 0)) ++ goto out; ++ ++ /* We found a whiteout */ ++ /* au_set_dbbot(dentry, bindex); */ ++ au_set_dbwh(dentry, bindex); ++ if (!allow_neg) ++ return NULL; /* success */ ++ ++real_lookup: ++ if (!ignore_perm) ++ h_dentry = vfsub_lkup_one(args->name, &h_path); ++ else ++ h_dentry = au_sio_lkup_one(h_userns, args->name, &h_path); ++ if (IS_ERR(h_dentry)) { ++ if (PTR_ERR(h_dentry) == -ENAMETOOLONG ++ && !allow_neg) ++ h_dentry = NULL; ++ goto out; ++ } ++ ++ h_inode = d_inode(h_dentry); ++ if (d_is_negative(h_dentry)) { ++ if (!allow_neg) ++ goto out_neg; ++ } else if (wh_found ++ || (args->type && args->type != (h_inode->i_mode & S_IFMT))) ++ goto out_neg; ++ else if (au_ftest_lkup(args->flags, DIRREN) ++ /* && h_inode */ ++ && !au_dr_lkup_h_ino(args, bindex, h_inode->i_ino)) { ++ AuDbg("b%d %pd ignored hi%llu\n", bindex, h_dentry, ++ (unsigned long long)h_inode->i_ino); ++ goto out_neg; ++ } ++ ++ if (au_dbbot(dentry) <= bindex) ++ au_set_dbbot(dentry, bindex); ++ if (au_dbtop(dentry) < 0 || bindex < au_dbtop(dentry)) ++ au_set_dbtop(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, h_dentry); ++ ++ if (!d_is_dir(h_dentry) ++ || !wh_able ++ || (d_really_is_positive(dentry) && !d_is_dir(dentry))) ++ goto out; /* success */ ++ ++ h_path.dentry = h_dentry; ++ inode_lock_shared_nested(h_inode, AuLsc_I_CHILD); ++ opq = au_diropq_test(h_userns, &h_path); ++ inode_unlock_shared(h_inode); ++ if (opq > 0) ++ au_set_dbdiropq(dentry, bindex); ++ else if (unlikely(opq < 0)) { ++ au_set_h_dptr(dentry, bindex, NULL); ++ h_dentry = ERR_PTR(opq); ++ } ++ goto out; ++ ++out_neg: ++ dput(h_dentry); ++ h_dentry = NULL; ++out: ++ return h_dentry; ++} ++ ++static int au_test_shwh(struct super_block *sb, const struct qstr *name) ++{ ++ if (unlikely(!au_opt_test(au_mntflags(sb), SHWH) ++ && !strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))) ++ return -EPERM; ++ return 0; ++} ++ ++/* ++ * returns the number of lower positive dentries, ++ * otherwise an error. ++ * can be called at unlinking with @type is zero. ++ */ ++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t btop, ++ unsigned int flags) ++{ ++ int npositive, err; ++ aufs_bindex_t bindex, btail, bdiropq; ++ unsigned char isdir, dirperm1, dirren; ++ struct au_do_lookup_args args = { ++ .flags = flags, ++ .name = &dentry->d_name ++ }; ++ struct dentry *parent; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ err = au_test_shwh(sb, args.name); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_wh_name_alloc(&args.whname, args.name); ++ if (unlikely(err)) ++ goto out; ++ ++ isdir = !!d_is_dir(dentry); ++ dirperm1 = !!au_opt_test(au_mntflags(sb), DIRPERM1); ++ dirren = !!au_opt_test(au_mntflags(sb), DIRREN); ++ if (dirren) ++ au_fset_lkup(args.flags, DIRREN); ++ ++ npositive = 0; ++ parent = dget_parent(dentry); ++ btail = au_dbtaildir(parent); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ struct dentry *h_parent, *h_dentry; ++ struct inode *h_inode, *h_dir; ++ struct au_branch *br; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) { ++ if (d_is_positive(h_dentry)) ++ npositive++; ++ break; ++ } ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || !d_is_dir(h_parent)) ++ continue; ++ ++ if (dirren) { ++ /* if the inum matches, then use the prepared name */ ++ err = au_dr_lkup_name(&args, bindex); ++ if (unlikely(err)) ++ goto out_parent; ++ } ++ ++ h_dir = d_inode(h_parent); ++ inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); ++ h_dentry = au_do_lookup(h_parent, dentry, bindex, &args); ++ inode_unlock_shared(h_dir); ++ err = PTR_ERR(h_dentry); ++ if (IS_ERR(h_dentry)) ++ goto out_parent; ++ if (h_dentry) ++ au_fclr_lkup(args.flags, ALLOW_NEG); ++ if (dirperm1) ++ au_fset_lkup(args.flags, IGNORE_PERM); ++ ++ if (au_dbwh(dentry) == bindex) ++ break; ++ if (!h_dentry) ++ continue; ++ if (d_is_negative(h_dentry)) ++ continue; ++ h_inode = d_inode(h_dentry); ++ npositive++; ++ if (!args.type) ++ args.type = h_inode->i_mode & S_IFMT; ++ if (args.type != S_IFDIR) ++ break; ++ else if (isdir) { ++ /* the type of lower may be different */ ++ bdiropq = au_dbdiropq(dentry); ++ if (bdiropq >= 0 && bdiropq <= bindex) ++ break; ++ } ++ br = au_sbr(sb, bindex); ++ if (dirren ++ && au_dr_hino_test_add(&br->br_dirren, h_inode->i_ino, ++ /*add_ent*/NULL)) { ++ /* prepare next name to lookup */ ++ err = au_dr_lkup(&args, dentry, bindex); ++ if (unlikely(err)) ++ goto out_parent; ++ } ++ } ++ ++ if (npositive) { ++ AuLabel(positive); ++ au_update_dbtop(dentry); ++ } ++ err = npositive; ++ if (unlikely(!au_opt_test(au_mntflags(sb), UDBA_NONE) ++ && au_dbtop(dentry) < 0)) { ++ err = -EIO; ++ AuIOErr("both of real entry and whiteout found, %pd, err %d\n", ++ dentry, err); ++ } ++ ++out_parent: ++ dput(parent); ++ au_kfree_try_rcu(args.whname.name); ++ if (dirren) ++ au_dr_lkup_fin(&args); ++out: ++ return err; ++} ++ ++struct dentry *au_sio_lkup_one(struct user_namespace *userns, struct qstr *name, ++ struct path *ppath) ++{ ++ struct dentry *dentry; ++ int wkq_err; ++ ++ if (!au_test_h_perm_sio(userns, d_inode(ppath->dentry), MAY_EXEC)) ++ dentry = vfsub_lkup_one(name, ppath); ++ else { ++ struct vfsub_lkup_one_args args = { ++ .errp = &dentry, ++ .name = name, ++ .ppath = ppath ++ }; ++ ++ wkq_err = au_wkq_wait(vfsub_call_lkup_one, &args); ++ if (unlikely(wkq_err)) ++ dentry = ERR_PTR(wkq_err); ++ } ++ ++ return dentry; ++} ++ ++/* ++ * lookup @dentry on @bindex which should be negative. ++ */ ++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh) ++{ ++ int err; ++ struct dentry *parent, *h_dentry; ++ struct au_branch *br; ++ struct user_namespace *h_userns; ++ struct path h_ppath; ++ ++ parent = dget_parent(dentry); ++ br = au_sbr(dentry->d_sb, bindex); ++ h_ppath.dentry = au_h_dptr(parent, bindex); ++ h_ppath.mnt = au_br_mnt(br); ++ h_userns = au_br_userns(br); ++ if (wh) ++ h_dentry = au_whtmp_lkup(h_ppath.dentry, br, &dentry->d_name); ++ else ++ h_dentry = au_sio_lkup_one(h_userns, &dentry->d_name, &h_ppath); ++ err = PTR_ERR(h_dentry); ++ if (IS_ERR(h_dentry)) ++ goto out; ++ if (unlikely(d_is_positive(h_dentry))) { ++ err = -EIO; ++ AuIOErr("%pd should be negative on b%d.\n", h_dentry, bindex); ++ dput(h_dentry); ++ goto out; ++ } ++ ++ err = 0; ++ if (bindex < au_dbtop(dentry)) ++ au_set_dbtop(dentry, bindex); ++ if (au_dbbot(dentry) < bindex) ++ au_set_dbbot(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, h_dentry); ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* subset of struct inode */ ++struct au_iattr { ++ unsigned long i_ino; ++ /* unsigned int i_nlink; */ ++ kuid_t i_uid; ++ kgid_t i_gid; ++ u64 i_version; ++/* ++ loff_t i_size; ++ blkcnt_t i_blocks; ++*/ ++ umode_t i_mode; ++}; ++ ++static void au_iattr_save(struct au_iattr *ia, struct inode *h_inode) ++{ ++ ia->i_ino = h_inode->i_ino; ++ /* ia->i_nlink = h_inode->i_nlink; */ ++ ia->i_uid = h_inode->i_uid; ++ ia->i_gid = h_inode->i_gid; ++ ia->i_version = inode_query_iversion(h_inode); ++/* ++ ia->i_size = h_inode->i_size; ++ ia->i_blocks = h_inode->i_blocks; ++*/ ++ ia->i_mode = (h_inode->i_mode & S_IFMT); ++} ++ ++static int au_iattr_test(struct au_iattr *ia, struct inode *h_inode) ++{ ++ return ia->i_ino != h_inode->i_ino ++ /* || ia->i_nlink != h_inode->i_nlink */ ++ || !uid_eq(ia->i_uid, h_inode->i_uid) ++ || !gid_eq(ia->i_gid, h_inode->i_gid) ++ || !inode_eq_iversion(h_inode, ia->i_version) ++/* ++ || ia->i_size != h_inode->i_size ++ || ia->i_blocks != h_inode->i_blocks ++*/ ++ || ia->i_mode != (h_inode->i_mode & S_IFMT); ++} ++ ++static int au_h_verify_dentry(struct dentry *h_dentry, struct dentry *h_parent, ++ struct au_branch *br) ++{ ++ int err; ++ struct au_iattr ia; ++ struct inode *h_inode; ++ struct dentry *h_d; ++ struct super_block *h_sb; ++ struct path h_ppath; ++ ++ err = 0; ++ memset(&ia, -1, sizeof(ia)); ++ h_sb = h_dentry->d_sb; ++ h_inode = NULL; ++ if (d_is_positive(h_dentry)) { ++ h_inode = d_inode(h_dentry); ++ au_iattr_save(&ia, h_inode); ++ } else if (au_test_nfs(h_sb) || au_test_fuse(h_sb)) ++ /* nfs d_revalidate may return 0 for negative dentry */ ++ /* fuse d_revalidate always return 0 for negative dentry */ ++ goto out; ++ ++ /* main purpose is namei.c:cached_lookup() and d_revalidate */ ++ h_ppath.dentry = h_parent; ++ h_ppath.mnt = au_br_mnt(br); ++ h_d = vfsub_lkup_one(&h_dentry->d_name, &h_ppath); ++ err = PTR_ERR(h_d); ++ if (IS_ERR(h_d)) ++ goto out; ++ ++ err = 0; ++ if (unlikely(h_d != h_dentry ++ || d_inode(h_d) != h_inode ++ || (h_inode && au_iattr_test(&ia, h_inode)))) ++ err = au_busy_or_stale(); ++ dput(h_d); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, ++ struct dentry *h_parent, struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ if (udba == AuOpt_UDBA_REVAL ++ && !au_test_fs_remote(h_dentry->d_sb)) { ++ IMustLock(h_dir); ++ err = (d_inode(h_dentry->d_parent) != h_dir); ++ } else if (udba != AuOpt_UDBA_NONE) ++ err = au_h_verify_dentry(h_dentry, h_parent, br); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_refresh_hdentry(struct dentry *dentry, struct dentry *parent) ++{ ++ int err; ++ aufs_bindex_t new_bindex, bindex, bbot, bwh, bdiropq; ++ struct au_hdentry tmp, *p, *q; ++ struct au_dinfo *dinfo; ++ struct super_block *sb; ++ ++ DiMustWriteLock(dentry); ++ ++ sb = dentry->d_sb; ++ dinfo = au_di(dentry); ++ bbot = dinfo->di_bbot; ++ bwh = dinfo->di_bwh; ++ bdiropq = dinfo->di_bdiropq; ++ bindex = dinfo->di_btop; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, p++) { ++ if (!p->hd_dentry) ++ continue; ++ ++ new_bindex = au_br_index(sb, p->hd_id); ++ if (new_bindex == bindex) ++ continue; ++ ++ if (dinfo->di_bwh == bindex) ++ bwh = new_bindex; ++ if (dinfo->di_bdiropq == bindex) ++ bdiropq = new_bindex; ++ if (new_bindex < 0) { ++ au_hdput(p); ++ p->hd_dentry = NULL; ++ continue; ++ } ++ ++ /* swap two lower dentries, and loop again */ ++ q = au_hdentry(dinfo, new_bindex); ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hd_dentry) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ dinfo->di_bwh = -1; ++ if (bwh >= 0 && bwh <= au_sbbot(sb) && au_sbr_whable(sb, bwh)) ++ dinfo->di_bwh = bwh; ++ ++ dinfo->di_bdiropq = -1; ++ if (bdiropq >= 0 ++ && bdiropq <= au_sbbot(sb) ++ && au_sbr_whable(sb, bdiropq)) ++ dinfo->di_bdiropq = bdiropq; ++ ++ err = -EIO; ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ bbot = au_dbbot(parent); ++ bindex = 0; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, p++) ++ if (p->hd_dentry) { ++ dinfo->di_btop = bindex; ++ break; ++ } ++ ++ if (dinfo->di_btop >= 0) { ++ bindex = bbot; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex >= 0; bindex--, p--) ++ if (p->hd_dentry) { ++ dinfo->di_bbot = bindex; ++ err = 0; ++ break; ++ } ++ } ++ ++ return err; ++} ++ ++static void au_do_hide(struct dentry *dentry) ++{ ++ struct inode *inode; ++ ++ if (d_really_is_positive(dentry)) { ++ inode = d_inode(dentry); ++ if (!d_is_dir(dentry)) { ++ if (inode->i_nlink && !d_unhashed(dentry)) ++ drop_nlink(inode); ++ } else { ++ clear_nlink(inode); ++ /* stop next lookup */ ++ inode->i_flags |= S_DEAD; ++ } ++ smp_mb(); /* necessary? */ ++ } ++ d_drop(dentry); ++} ++ ++static int au_hide_children(struct dentry *parent) ++{ ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry *dentry; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, parent, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ /* in reverse order */ ++ for (i = dpages.ndpage - 1; i >= 0; i--) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = ndentry - 1; j >= 0; j--) { ++ dentry = dpage->dentries[j]; ++ if (dentry != parent) ++ au_do_hide(dentry); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static void au_hide(struct dentry *dentry) ++{ ++ int err; ++ ++ AuDbgDentry(dentry); ++ if (d_is_dir(dentry)) { ++ /* shrink_dcache_parent(dentry); */ ++ err = au_hide_children(dentry); ++ if (unlikely(err)) ++ AuIOErr("%pd, failed hiding children, ignored %d\n", ++ dentry, err); ++ } ++ au_do_hide(dentry); ++} ++ ++/* ++ * By adding a dirty branch, a cached dentry may be affected in various ways. ++ * ++ * a dirty branch is added ++ * - on the top of layers ++ * - in the middle of layers ++ * - to the bottom of layers ++ * ++ * on the added branch there exists ++ * - a whiteout ++ * - a diropq ++ * - a same named entry ++ * + exist ++ * * negative --> positive ++ * * positive --> positive ++ * - type is unchanged ++ * - type is changed ++ * + doesn't exist ++ * * negative --> negative ++ * * positive --> negative (rejected by au_br_del() for non-dir case) ++ * - none ++ */ ++static int au_refresh_by_dinfo(struct dentry *dentry, struct au_dinfo *dinfo, ++ struct au_dinfo *tmp) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct { ++ struct dentry *dentry; ++ struct inode *inode; ++ mode_t mode; ++ } orig_h, tmp_h = { ++ .dentry = NULL ++ }; ++ struct au_hdentry *hd; ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry; ++ ++ err = 0; ++ AuDebugOn(dinfo->di_btop < 0); ++ orig_h.mode = 0; ++ orig_h.dentry = au_hdentry(dinfo, dinfo->di_btop)->hd_dentry; ++ orig_h.inode = NULL; ++ if (d_is_positive(orig_h.dentry)) { ++ orig_h.inode = d_inode(orig_h.dentry); ++ orig_h.mode = orig_h.inode->i_mode & S_IFMT; ++ } ++ if (tmp->di_btop >= 0) { ++ tmp_h.dentry = au_hdentry(tmp, tmp->di_btop)->hd_dentry; ++ if (d_is_positive(tmp_h.dentry)) { ++ tmp_h.inode = d_inode(tmp_h.dentry); ++ tmp_h.mode = tmp_h.inode->i_mode & S_IFMT; ++ } ++ } ++ ++ inode = NULL; ++ if (d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (!orig_h.inode) { ++ AuDbg("negative originally\n"); ++ if (inode) { ++ au_hide(dentry); ++ goto out; ++ } ++ AuDebugOn(inode); ++ AuDebugOn(dinfo->di_btop != dinfo->di_bbot); ++ AuDebugOn(dinfo->di_bdiropq != -1); ++ ++ if (!tmp_h.inode) { ++ AuDbg("negative --> negative\n"); ++ /* should have only one negative lower */ ++ if (tmp->di_btop >= 0 ++ && tmp->di_btop < dinfo->di_btop) { ++ AuDebugOn(tmp->di_btop != tmp->di_bbot); ++ AuDebugOn(dinfo->di_btop != dinfo->di_bbot); ++ au_set_h_dptr(dentry, dinfo->di_btop, NULL); ++ au_di_cp(dinfo, tmp); ++ hd = au_hdentry(tmp, tmp->di_btop); ++ au_set_h_dptr(dentry, tmp->di_btop, ++ dget(hd->hd_dentry)); ++ } ++ au_dbg_verify_dinode(dentry); ++ } else { ++ AuDbg("negative --> positive\n"); ++ /* ++ * similar to the behaviour of creating with bypassing ++ * aufs. ++ * unhash it in order to force an error in the ++ * succeeding create operation. ++ * we should not set S_DEAD here. ++ */ ++ d_drop(dentry); ++ /* au_di_swap(tmp, dinfo); */ ++ au_dbg_verify_dinode(dentry); ++ } ++ } else { ++ AuDbg("positive originally\n"); ++ /* inode may be NULL */ ++ AuDebugOn(inode && (inode->i_mode & S_IFMT) != orig_h.mode); ++ if (!tmp_h.inode) { ++ AuDbg("positive --> negative\n"); ++ /* or bypassing aufs */ ++ au_hide(dentry); ++ if (tmp->di_bwh >= 0 && tmp->di_bwh <= dinfo->di_btop) ++ dinfo->di_bwh = tmp->di_bwh; ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } else if (orig_h.mode == tmp_h.mode) { ++ AuDbg("positive --> positive, same type\n"); ++ if (!S_ISDIR(orig_h.mode) ++ && dinfo->di_btop > tmp->di_btop) { ++ /* ++ * similar to the behaviour of removing and ++ * creating. ++ */ ++ au_hide(dentry); ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } else { ++ /* fill empty slots */ ++ if (dinfo->di_btop > tmp->di_btop) ++ dinfo->di_btop = tmp->di_btop; ++ if (dinfo->di_bbot < tmp->di_bbot) ++ dinfo->di_bbot = tmp->di_bbot; ++ dinfo->di_bwh = tmp->di_bwh; ++ dinfo->di_bdiropq = tmp->di_bdiropq; ++ bbot = dinfo->di_bbot; ++ bindex = tmp->di_btop; ++ hd = au_hdentry(tmp, bindex); ++ for (; bindex <= bbot; bindex++, hd++) { ++ if (au_h_dptr(dentry, bindex)) ++ continue; ++ h_dentry = hd->hd_dentry; ++ if (!h_dentry) ++ continue; ++ AuDebugOn(d_is_negative(h_dentry)); ++ h_inode = d_inode(h_dentry); ++ AuDebugOn(orig_h.mode ++ != (h_inode->i_mode ++ & S_IFMT)); ++ au_set_h_dptr(dentry, bindex, ++ dget(h_dentry)); ++ } ++ if (inode) ++ err = au_refresh_hinode(inode, dentry); ++ au_dbg_verify_dinode(dentry); ++ } ++ } else { ++ AuDbg("positive --> positive, different type\n"); ++ /* similar to the behaviour of removing and creating */ ++ au_hide(dentry); ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } ++ } ++ ++out: ++ return err; ++} ++ ++void au_refresh_dop(struct dentry *dentry, int force_reval) ++{ ++ const struct dentry_operations *dop ++ = force_reval ? &aufs_dop : dentry->d_sb->s_d_op; ++ static const unsigned int mask ++ = DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE; ++ ++ BUILD_BUG_ON(sizeof(mask) != sizeof(dentry->d_flags)); ++ ++ if (dentry->d_op == dop) ++ return; ++ ++ AuDbg("%pd\n", dentry); ++ spin_lock(&dentry->d_lock); ++ if (dop == &aufs_dop) ++ dentry->d_flags |= mask; ++ else ++ dentry->d_flags &= ~mask; ++ dentry->d_op = dop; ++ spin_unlock(&dentry->d_lock); ++} ++ ++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent) ++{ ++ int err, ebrange, nbr; ++ unsigned int sigen; ++ struct au_dinfo *dinfo, *tmp; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ DiMustWriteLock(dentry); ++ AuDebugOn(IS_ROOT(dentry)); ++ AuDebugOn(d_really_is_negative(parent)); ++ ++ sb = dentry->d_sb; ++ sigen = au_sigen(sb); ++ err = au_digen_test(parent, sigen); ++ if (unlikely(err)) ++ goto out; ++ ++ nbr = au_sbbot(sb) + 1; ++ dinfo = au_di(dentry); ++ err = au_di_realloc(dinfo, nbr, /*may_shrink*/0); ++ if (unlikely(err)) ++ goto out; ++ ebrange = au_dbrange_test(dentry); ++ if (!ebrange) ++ ebrange = au_do_refresh_hdentry(dentry, parent); ++ ++ if (d_unhashed(dentry) || ebrange /* || dinfo->di_tmpfile */) { ++ AuDebugOn(au_dbtop(dentry) < 0 && au_dbbot(dentry) >= 0); ++ if (d_really_is_positive(dentry)) { ++ inode = d_inode(dentry); ++ err = au_refresh_hinode_self(inode); ++ } ++ au_dbg_verify_dinode(dentry); ++ if (!err) ++ goto out_dgen; /* success */ ++ goto out; ++ } ++ ++ /* temporary dinfo */ ++ AuDbgDentry(dentry); ++ err = -ENOMEM; ++ tmp = au_di_alloc(sb, AuLsc_DI_TMP); ++ if (unlikely(!tmp)) ++ goto out; ++ au_di_swap(tmp, dinfo); ++ /* returns the number of positive dentries */ ++ /* ++ * if current working dir is removed, it returns an error. ++ * but the dentry is legal. ++ */ ++ err = au_lkup_dentry(dentry, /*btop*/0, AuLkup_ALLOW_NEG); ++ AuDbgDentry(dentry); ++ au_di_swap(tmp, dinfo); ++ if (err == -ENOENT) ++ err = 0; ++ if (err >= 0) { ++ /* compare/refresh by dinfo */ ++ AuDbgDentry(dentry); ++ err = au_refresh_by_dinfo(dentry, dinfo, tmp); ++ au_dbg_verify_dinode(dentry); ++ AuTraceErr(err); ++ } ++ au_di_realloc(dinfo, nbr, /*may_shrink*/1); /* harmless if err */ ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ if (unlikely(err)) ++ goto out; ++ ++out_dgen: ++ au_update_digen(dentry); ++out: ++ if (unlikely(err && !(dentry->d_flags & DCACHE_NFSFS_RENAMED))) { ++ AuIOErr("failed refreshing %pd, %d\n", dentry, err); ++ AuDbgDentry(dentry); ++ } ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_do_h_d_reval(struct dentry *h_dentry, unsigned int flags, ++ struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err, valid; ++ ++ err = 0; ++ if (!(h_dentry->d_flags & DCACHE_OP_REVALIDATE)) ++ goto out; ++ ++ AuDbg("b%d\n", bindex); ++ /* ++ * gave up supporting LOOKUP_CREATE/OPEN for lower fs, ++ * due to whiteout and branch permission. ++ */ ++ flags &= ~(/*LOOKUP_PARENT |*/ LOOKUP_OPEN | LOOKUP_CREATE ++ | LOOKUP_FOLLOW | LOOKUP_EXCL); ++ /* it may return tri-state */ ++ valid = h_dentry->d_op->d_revalidate(h_dentry, flags); ++ ++ if (unlikely(valid < 0)) ++ err = valid; ++ else if (!valid) ++ err = -EINVAL; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* todo: remove this */ ++static int h_d_revalidate(struct dentry *dentry, struct inode *inode, ++ unsigned int flags, int do_udba, int dirren) ++{ ++ int err; ++ umode_t mode, h_mode; ++ aufs_bindex_t bindex, btail, btop, ibs, ibe; ++ unsigned char plus, unhashed, is_root, h_plus, h_nfs, tmpfile; ++ struct inode *h_inode, *h_cached_inode; ++ struct dentry *h_dentry; ++ struct qstr *name, *h_name; ++ ++ err = 0; ++ plus = 0; ++ mode = 0; ++ ibs = -1; ++ ibe = -1; ++ unhashed = !!d_unhashed(dentry); ++ is_root = !!IS_ROOT(dentry); ++ name = &dentry->d_name; ++ tmpfile = au_di(dentry)->di_tmpfile; ++ ++ /* ++ * Theoretically, REVAL test should be unnecessary in case of ++ * {FS,I}NOTIFY. ++ * But {fs,i}notify doesn't fire some necessary events, ++ * IN_ATTRIB for atime/nlink/pageio ++ * Let's do REVAL test too. ++ */ ++ if (do_udba && inode) { ++ mode = (inode->i_mode & S_IFMT); ++ plus = (inode->i_nlink > 0); ++ ibs = au_ibtop(inode); ++ ibe = au_ibbot(inode); ++ } ++ ++ btop = au_dbtop(dentry); ++ btail = btop; ++ if (inode && S_ISDIR(inode->i_mode)) ++ btail = au_dbtaildir(dentry); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ ++ AuDbg("b%d, %pd\n", bindex, h_dentry); ++ h_nfs = !!au_test_nfs(h_dentry->d_sb); ++ spin_lock(&h_dentry->d_lock); ++ h_name = &h_dentry->d_name; ++ if (unlikely(do_udba ++ && !is_root ++ && ((!h_nfs ++ && (unhashed != !!d_unhashed(h_dentry) ++ || (!tmpfile && !dirren ++ && !au_qstreq(name, h_name)) ++ )) ++ || (h_nfs ++ && !(flags & LOOKUP_OPEN) ++ && (h_dentry->d_flags ++ & DCACHE_NFSFS_RENAMED))) ++ )) { ++ int h_unhashed; ++ ++ h_unhashed = d_unhashed(h_dentry); ++ spin_unlock(&h_dentry->d_lock); ++ AuDbg("unhash 0x%x 0x%x, %pd %pd\n", ++ unhashed, h_unhashed, dentry, h_dentry); ++ goto err; ++ } ++ spin_unlock(&h_dentry->d_lock); ++ ++ err = au_do_h_d_reval(h_dentry, flags, dentry, bindex); ++ if (unlikely(err)) ++ /* do not goto err, to keep the errno */ ++ break; ++ ++ /* todo: plink too? */ ++ if (!do_udba) ++ continue; ++ ++ /* UDBA tests */ ++ if (unlikely(!!inode != d_is_positive(h_dentry))) ++ goto err; ++ ++ h_inode = NULL; ++ if (d_is_positive(h_dentry)) ++ h_inode = d_inode(h_dentry); ++ h_plus = plus; ++ h_mode = mode; ++ h_cached_inode = h_inode; ++ if (h_inode) { ++ h_mode = (h_inode->i_mode & S_IFMT); ++ h_plus = (h_inode->i_nlink > 0); ++ } ++ if (inode && ibs <= bindex && bindex <= ibe) ++ h_cached_inode = au_h_iptr(inode, bindex); ++ ++ if (!h_nfs) { ++ if (unlikely(plus != h_plus && !tmpfile)) ++ goto err; ++ } else { ++ if (unlikely(!(h_dentry->d_flags & DCACHE_NFSFS_RENAMED) ++ && !is_root ++ && !IS_ROOT(h_dentry) ++ && unhashed != d_unhashed(h_dentry))) ++ goto err; ++ } ++ if (unlikely(mode != h_mode ++ || h_cached_inode != h_inode)) ++ goto err; ++ continue; ++ ++err: ++ err = -EINVAL; ++ break; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* todo: consolidate with do_refresh() and au_reval_for_attr() */ ++static int simple_reval_dpath(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *parent; ++ ++ if (!au_digen_test(dentry, sigen)) ++ return 0; ++ ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ AuDebugOn(au_digen_test(parent, sigen)); ++ au_dbg_verify_gen(parent, sigen); ++ err = au_refresh_dentry(dentry, parent); ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_reval_dpath(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *d, *parent; ++ ++ if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR)) ++ return simple_reval_dpath(dentry, sigen); ++ ++ /* slow loop, keep it simple and stupid */ ++ /* cf: au_cpup_dirs() */ ++ err = 0; ++ parent = NULL; ++ while (au_digen_test(dentry, sigen)) { ++ d = dentry; ++ while (1) { ++ dput(parent); ++ parent = dget_parent(d); ++ if (!au_digen_test(parent, sigen)) ++ break; ++ d = parent; ++ } ++ ++ if (d != dentry) ++ di_write_lock_child2(d); ++ ++ /* someone might update our dentry while we were sleeping */ ++ if (au_digen_test(d, sigen)) { ++ /* ++ * todo: consolidate with simple_reval_dpath(), ++ * do_refresh() and au_reval_for_attr(). ++ */ ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(d, parent); ++ di_read_unlock(parent, AuLock_IR); ++ } ++ ++ if (d != dentry) ++ di_write_unlock(d); ++ dput(parent); ++ if (unlikely(err)) ++ break; ++ } ++ ++ return err; ++} ++ ++/* ++ * if valid returns 1, otherwise 0. ++ */ ++static int aufs_d_revalidate(struct dentry *dentry, unsigned int flags) ++{ ++ int valid, err; ++ unsigned int sigen; ++ unsigned char do_udba, dirren; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ /* todo: support rcu-walk? */ ++ if (flags & LOOKUP_RCU) ++ return -ECHILD; ++ ++ valid = 0; ++ if (unlikely(!au_di(dentry))) ++ goto out; ++ ++ valid = 1; ++ sb = dentry->d_sb; ++ /* ++ * todo: very ugly ++ * i_mutex of parent dir may be held, ++ * but we should not return 'invalid' due to busy. ++ */ ++ err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW | AuLock_NOPLM); ++ if (unlikely(err)) { ++ valid = err; ++ AuTraceErr(err); ++ goto out; ++ } ++ inode = NULL; ++ if (d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (unlikely(inode && au_is_bad_inode(inode))) { ++ err = -EINVAL; ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ if (unlikely(au_dbrange_test(dentry))) { ++ err = -EINVAL; ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ ++ sigen = au_sigen(sb); ++ if (au_digen_test(dentry, sigen)) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_dpath(dentry, sigen); ++ if (unlikely(err)) { ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ } ++ di_downgrade_lock(dentry, AuLock_IR); ++ ++ err = -EINVAL; ++ if (!(flags & (LOOKUP_OPEN | LOOKUP_EMPTY)) ++ && inode ++ && !(inode->i_state && I_LINKABLE) ++ && (IS_DEADDIR(inode) || !inode->i_nlink)) { ++ AuTraceErr(err); ++ goto out_inval; ++ } ++ ++ do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE); ++ if (do_udba && inode) { ++ aufs_bindex_t btop = au_ibtop(inode); ++ struct inode *h_inode; ++ ++ if (btop >= 0) { ++ h_inode = au_h_iptr(inode, btop); ++ if (h_inode && au_test_higen(inode, h_inode)) { ++ AuTraceErr(err); ++ goto out_inval; ++ } ++ } ++ } ++ ++ dirren = !!au_opt_test(au_mntflags(sb), DIRREN); ++ err = h_d_revalidate(dentry, inode, flags, do_udba, dirren); ++ if (unlikely(!err && do_udba && au_dbtop(dentry) < 0)) { ++ err = -EIO; ++ AuDbg("both of real entry and whiteout found, %p, err %d\n", ++ dentry, err); ++ } ++ goto out_inval; ++ ++out_dgrade: ++ di_downgrade_lock(dentry, AuLock_IR); ++out_inval: ++ aufs_read_unlock(dentry, AuLock_IR); ++ AuTraceErr(err); ++ valid = !err; ++out: ++ if (!valid) { ++ AuDbg("%pd invalid, %d\n", dentry, valid); ++ d_drop(dentry); ++ } ++ return valid; ++} ++ ++static void aufs_d_release(struct dentry *dentry) ++{ ++ if (au_di(dentry)) { ++ au_di_fin(dentry); ++ au_hn_di_reinit(dentry); ++ } ++} ++ ++const struct dentry_operations aufs_dop = { ++ .d_revalidate = aufs_d_revalidate, ++ .d_weak_revalidate = aufs_d_revalidate, ++ .d_release = aufs_d_release ++}; ++ ++/* aufs_dop without d_revalidate */ ++const struct dentry_operations aufs_dop_noreval = { ++ .d_release = aufs_d_release ++}; +diff -Naur null/fs/aufs/dentry.h linux-5.15.36/fs/aufs/dentry.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/dentry.h 2022-05-10 16:51:39.868744219 +0300 +@@ -0,0 +1,269 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * lookup and dentry operations ++ */ ++ ++#ifndef __AUFS_DENTRY_H__ ++#define __AUFS_DENTRY_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "dirren.h" ++#include "rwsem.h" ++ ++struct au_hdentry { ++ struct dentry *hd_dentry; ++ aufs_bindex_t hd_id; ++}; ++ ++struct au_dinfo { ++ atomic_t di_generation; ++ ++ struct au_rwsem di_rwsem; ++ 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; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* flags for au_lkup_dentry() */ ++#define AuLkup_ALLOW_NEG 1 ++#define AuLkup_IGNORE_PERM (1 << 1) ++#define AuLkup_DIRREN (1 << 2) ++#define au_ftest_lkup(flags, name) ((flags) & AuLkup_##name) ++#define au_fset_lkup(flags, name) \ ++ do { (flags) |= AuLkup_##name; } while (0) ++#define au_fclr_lkup(flags, name) \ ++ do { (flags) &= ~AuLkup_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuLkup_DIRREN ++#define AuLkup_DIRREN 0 ++#endif ++ ++struct au_do_lookup_args { ++ unsigned int flags; ++ mode_t type; ++ struct qstr whname, *name; ++ struct au_dr_lookup dirren; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dentry.c */ ++extern const struct dentry_operations aufs_dop, aufs_dop_noreval; ++struct au_branch; ++struct dentry *au_sio_lkup_one(struct user_namespace *userns, struct qstr *name, ++ struct path *ppath); ++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, ++ struct dentry *h_parent, struct au_branch *br); ++ ++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t btop, ++ unsigned int flags); ++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh); ++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent); ++int au_reval_dpath(struct dentry *dentry, unsigned int sigen); ++void au_refresh_dop(struct dentry *dentry, int force_reval); ++ ++/* dinfo.c */ ++void au_di_init_once(void *_di); ++struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc); ++void au_di_free(struct au_dinfo *dinfo); ++void au_di_swap(struct au_dinfo *a, struct au_dinfo *b); ++void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src); ++int au_di_init(struct dentry *dentry); ++void au_di_fin(struct dentry *dentry); ++int au_di_realloc(struct au_dinfo *dinfo, int nbr, int may_shrink); ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc); ++void di_read_unlock(struct dentry *d, int flags); ++void di_downgrade_lock(struct dentry *d, int flags); ++void di_write_lock(struct dentry *d, unsigned int lsc); ++void di_write_unlock(struct dentry *d); ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex); ++struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex); ++aufs_bindex_t au_dbtail(struct dentry *dentry); ++aufs_bindex_t au_dbtaildir(struct dentry *dentry); ++ ++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++int au_digen_test(struct dentry *dentry, unsigned int sigen); ++int au_dbrange_test(struct dentry *dentry); ++void au_update_digen(struct dentry *dentry); ++void au_update_dbrange(struct dentry *dentry, int do_put_zero); ++void au_update_dbtop(struct dentry *dentry); ++void au_update_dbbot(struct dentry *dentry); ++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_dinfo *au_di(struct dentry *dentry) ++{ ++ return dentry->d_fsdata; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for dinfo */ ++enum { ++ AuLsc_DI_CHILD, /* child first */ ++ AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hnotify */ ++ AuLsc_DI_CHILD3, /* copyup dirs */ ++ AuLsc_DI_PARENT, ++ AuLsc_DI_PARENT2, ++ AuLsc_DI_PARENT3, ++ AuLsc_DI_TMP /* temp for replacing dinfo */ ++}; ++ ++/* ++ * di_read_lock_child, di_write_lock_child, ++ * di_read_lock_child2, di_write_lock_child2, ++ * di_read_lock_child3, di_write_lock_child3, ++ * di_read_lock_parent, di_write_lock_parent, ++ * di_read_lock_parent2, di_write_lock_parent2, ++ * di_read_lock_parent3, di_write_lock_parent3, ++ */ ++#define AuReadLockFunc(name, lsc) \ ++static inline void di_read_lock_##name(struct dentry *d, int flags) \ ++{ di_read_lock(d, flags, AuLsc_DI_##lsc); } ++ ++#define AuWriteLockFunc(name, lsc) \ ++static inline void di_write_lock_##name(struct dentry *d) \ ++{ di_write_lock(d, AuLsc_DI_##lsc); } ++ ++#define AuRWLockFuncs(name, lsc) \ ++ AuReadLockFunc(name, lsc) \ ++ AuWriteLockFunc(name, lsc) ++ ++AuRWLockFuncs(child, CHILD); ++AuRWLockFuncs(child2, CHILD2); ++AuRWLockFuncs(child3, CHILD3); ++AuRWLockFuncs(parent, PARENT); ++AuRWLockFuncs(parent2, PARENT2); ++AuRWLockFuncs(parent3, PARENT3); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++#define DiMustNoWaiters(d) AuRwMustNoWaiters(&au_di(d)->di_rwsem) ++#define DiMustAnyLock(d) AuRwMustAnyLock(&au_di(d)->di_rwsem) ++#define DiMustWriteLock(d) AuRwMustWriteLock(&au_di(d)->di_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: memory barrier? */ ++static inline unsigned int au_digen(struct dentry *d) ++{ ++ return atomic_read(&au_di(d)->di_generation); ++} ++ ++static inline void au_h_dentry_init(struct au_hdentry *hdentry) ++{ ++ hdentry->hd_dentry = NULL; ++} ++ ++static inline struct au_hdentry *au_hdentry(struct au_dinfo *di, ++ aufs_bindex_t bindex) ++{ ++ return di->di_hdentry + bindex; ++} ++ ++static inline void au_hdput(struct au_hdentry *hd) ++{ ++ if (hd) ++ dput(hd->hd_dentry); ++} ++ ++static inline aufs_bindex_t au_dbtop(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_btop; ++} ++ ++static inline aufs_bindex_t au_dbbot(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bbot; ++} ++ ++static inline aufs_bindex_t au_dbwh(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bwh; ++} ++ ++static inline aufs_bindex_t au_dbdiropq(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bdiropq; ++} ++ ++/* todo: hard/soft set? */ ++static inline void au_set_dbtop(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_btop = bindex; ++} ++ ++static inline void au_set_dbbot(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_bbot = bindex; ++} ++ ++static inline void au_set_dbwh(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ /* dbwh can be outside of btop - bbot range */ ++ au_di(dentry)->di_bwh = bindex; ++} ++ ++static inline void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_bdiropq = bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_HNOTIFY ++static inline void au_digen_dec(struct dentry *d) ++{ ++ atomic_dec(&au_di(d)->di_generation); ++} ++ ++static inline void au_hn_di_reinit(struct dentry *dentry) ++{ ++ dentry->d_fsdata = NULL; ++} ++#else ++AuStubVoid(au_hn_di_reinit, struct dentry *dentry __maybe_unused) ++#endif /* CONFIG_AUFS_HNOTIFY */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DENTRY_H__ */ +diff -Naur null/fs/aufs/dinfo.c linux-5.15.36/fs/aufs/dinfo.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/dinfo.c 2022-05-10 16:51:39.869744219 +0300 +@@ -0,0 +1,554 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * dentry private data ++ */ ++ ++#include "aufs.h" ++ ++void au_di_init_once(void *_dinfo) ++{ ++ struct au_dinfo *dinfo = _dinfo; ++ ++ au_rw_init(&dinfo->di_rwsem); ++} ++ ++struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc) ++{ ++ struct au_dinfo *dinfo; ++ int nbr, i; ++ ++ dinfo = au_cache_alloc_dinfo(); ++ if (unlikely(!dinfo)) ++ goto out; ++ ++ nbr = au_sbbot(sb) + 1; ++ if (nbr <= 0) ++ nbr = 1; ++ dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), GFP_NOFS); ++ if (dinfo->di_hdentry) { ++ au_rw_write_lock_nested(&dinfo->di_rwsem, lsc); ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ dinfo->di_bwh = -1; ++ dinfo->di_bdiropq = -1; ++ dinfo->di_tmpfile = 0; ++ for (i = 0; i < nbr; i++) ++ dinfo->di_hdentry[i].hd_id = -1; ++ goto out; ++ } ++ ++ au_cache_free_dinfo(dinfo); ++ dinfo = NULL; ++ ++out: ++ return dinfo; ++} ++ ++void au_di_free(struct au_dinfo *dinfo) ++{ ++ struct au_hdentry *p; ++ aufs_bindex_t bbot, bindex; ++ ++ /* dentry may not be revalidated */ ++ bindex = dinfo->di_btop; ++ if (bindex >= 0) { ++ bbot = dinfo->di_bbot; ++ p = au_hdentry(dinfo, bindex); ++ while (bindex++ <= bbot) ++ au_hdput(p++); ++ } ++ au_kfree_try_rcu(dinfo->di_hdentry); ++ au_cache_free_dinfo(dinfo); ++} ++ ++void au_di_swap(struct au_dinfo *a, struct au_dinfo *b) ++{ ++ struct au_hdentry *p; ++ aufs_bindex_t bi; ++ ++ AuRwMustWriteLock(&a->di_rwsem); ++ AuRwMustWriteLock(&b->di_rwsem); ++ ++#define DiSwap(v, name) \ ++ do { \ ++ v = a->di_##name; \ ++ a->di_##name = b->di_##name; \ ++ b->di_##name = v; \ ++ } while (0) ++ ++ DiSwap(p, hdentry); ++ DiSwap(bi, btop); ++ DiSwap(bi, bbot); ++ DiSwap(bi, bwh); ++ DiSwap(bi, bdiropq); ++ /* smp_mb(); */ ++ ++#undef DiSwap ++} ++ ++void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src) ++{ ++ AuRwMustWriteLock(&dst->di_rwsem); ++ AuRwMustWriteLock(&src->di_rwsem); ++ ++ dst->di_btop = src->di_btop; ++ dst->di_bbot = src->di_bbot; ++ dst->di_bwh = src->di_bwh; ++ dst->di_bdiropq = src->di_bdiropq; ++ /* smp_mb(); */ ++} ++ ++int au_di_init(struct dentry *dentry) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_dinfo *dinfo; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ dinfo = au_di_alloc(sb, AuLsc_DI_CHILD); ++ if (dinfo) { ++ atomic_set(&dinfo->di_generation, au_sigen(sb)); ++ /* smp_mb(); */ /* atomic_set */ ++ dentry->d_fsdata = dinfo; ++ } else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++void au_di_fin(struct dentry *dentry) ++{ ++ struct au_dinfo *dinfo; ++ ++ dinfo = au_di(dentry); ++ AuRwDestroy(&dinfo->di_rwsem); ++ au_di_free(dinfo); ++} ++ ++int au_di_realloc(struct au_dinfo *dinfo, int nbr, int may_shrink) ++{ ++ int err, sz; ++ struct au_hdentry *hdp; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*hdp) * (dinfo->di_bbot + 1); ++ if (!sz) ++ sz = sizeof(*hdp); ++ hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS, ++ may_shrink); ++ if (hdp) { ++ dinfo->di_hdentry = hdp; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void do_ii_write_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_write_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_write_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_write_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_write_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_write_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_write_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static void do_ii_read_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_read_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_read_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_read_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_read_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_read_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_read_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc) ++{ ++ struct inode *inode; ++ ++ au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc); ++ if (d_really_is_positive(d)) { ++ inode = d_inode(d); ++ if (au_ftest_lock(flags, IW)) ++ do_ii_write_lock(inode, lsc); ++ else if (au_ftest_lock(flags, IR)) ++ do_ii_read_lock(inode, lsc); ++ } ++} ++ ++void di_read_unlock(struct dentry *d, int flags) ++{ ++ struct inode *inode; ++ ++ if (d_really_is_positive(d)) { ++ inode = d_inode(d); ++ if (au_ftest_lock(flags, IW)) { ++ au_dbg_verify_dinode(d); ++ ii_write_unlock(inode); ++ } else if (au_ftest_lock(flags, IR)) { ++ au_dbg_verify_dinode(d); ++ ii_read_unlock(inode); ++ } ++ } ++ au_rw_read_unlock(&au_di(d)->di_rwsem); ++} ++ ++void di_downgrade_lock(struct dentry *d, int flags) ++{ ++ if (d_really_is_positive(d) && au_ftest_lock(flags, IR)) ++ ii_downgrade_lock(d_inode(d)); ++ au_rw_dgrade_lock(&au_di(d)->di_rwsem); ++} ++ ++void di_write_lock(struct dentry *d, unsigned int lsc) ++{ ++ au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc); ++ if (d_really_is_positive(d)) ++ do_ii_write_lock(d_inode(d), lsc); ++} ++ ++void di_write_unlock(struct dentry *d) ++{ ++ au_dbg_verify_dinode(d); ++ if (d_really_is_positive(d)) ++ ii_write_unlock(d_inode(d)); ++ au_rw_write_unlock(&au_di(d)->di_rwsem); ++} ++ ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ AuDebugOn(d1 == d2 ++ || d_inode(d1) == d_inode(d2) ++ || d1->d_sb != d2->d_sb); ++ ++ if ((isdir && au_test_subdir(d1, d2)) ++ || d1 < d2) { ++ di_write_lock_child(d1); ++ di_write_lock_child2(d2); ++ } else { ++ di_write_lock_child(d2); ++ di_write_lock_child2(d1); ++ } ++} ++ ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ AuDebugOn(d1 == d2 ++ || d_inode(d1) == d_inode(d2) ++ || d1->d_sb != d2->d_sb); ++ ++ if ((isdir && au_test_subdir(d1, d2)) ++ || d1 < d2) { ++ di_write_lock_parent(d1); ++ di_write_lock_parent2(d2); ++ } else { ++ di_write_lock_parent(d2); ++ di_write_lock_parent2(d1); ++ } ++} ++ ++void di_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ di_write_unlock(d1); ++ if (d_inode(d1) == d_inode(d2)) ++ au_rw_write_unlock(&au_di(d2)->di_rwsem); ++ else ++ di_write_unlock(d2); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ struct dentry *d; ++ ++ DiMustAnyLock(dentry); ++ ++ if (au_dbtop(dentry) < 0 || bindex < au_dbtop(dentry)) ++ return NULL; ++ AuDebugOn(bindex < 0); ++ d = au_hdentry(au_di(dentry), bindex)->hd_dentry; ++ AuDebugOn(d && au_dcount(d) <= 0); ++ return d; ++} ++ ++/* ++ * extended version of au_h_dptr(). ++ * returns a hashed and positive (or linkable) h_dentry in bindex, NULL, or ++ * error. ++ */ ++struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ struct dentry *h_dentry; ++ struct inode *inode, *h_inode; ++ ++ AuDebugOn(d_really_is_negative(dentry)); ++ ++ h_dentry = NULL; ++ if (au_dbtop(dentry) <= bindex ++ && bindex <= au_dbbot(dentry)) ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && !au_d_linkable(h_dentry)) { ++ dget(h_dentry); ++ goto out; /* success */ ++ } ++ ++ inode = d_inode(dentry); ++ AuDebugOn(bindex < au_ibtop(inode)); ++ AuDebugOn(au_ibbot(inode) < bindex); ++ h_inode = au_h_iptr(inode, bindex); ++ h_dentry = d_find_alias(h_inode); ++ if (h_dentry) { ++ if (!IS_ERR(h_dentry)) { ++ if (!au_d_linkable(h_dentry)) ++ goto out; /* success */ ++ dput(h_dentry); ++ } else ++ goto out; ++ } ++ ++ if (au_opt_test(au_mntflags(dentry->d_sb), PLINK)) { ++ h_dentry = au_plink_lkup(inode, bindex); ++ AuDebugOn(!h_dentry); ++ if (!IS_ERR(h_dentry)) { ++ if (!au_d_hashed_positive(h_dentry)) ++ goto out; /* success */ ++ dput(h_dentry); ++ h_dentry = NULL; ++ } ++ } ++ ++out: ++ AuDbgDentry(h_dentry); ++ return h_dentry; ++} ++ ++aufs_bindex_t au_dbtail(struct dentry *dentry) ++{ ++ aufs_bindex_t bbot, bwh; ++ ++ bbot = au_dbbot(dentry); ++ if (0 <= bbot) { ++ bwh = au_dbwh(dentry); ++ if (!bwh) ++ return bwh; ++ if (0 < bwh && bwh < bbot) ++ return bwh - 1; ++ } ++ return bbot; ++} ++ ++aufs_bindex_t au_dbtaildir(struct dentry *dentry) ++{ ++ aufs_bindex_t bbot, bopq; ++ ++ bbot = au_dbtail(dentry); ++ if (0 <= bbot) { ++ bopq = au_dbdiropq(dentry); ++ if (0 <= bopq && bopq < bbot) ++ bbot = bopq; ++ } ++ return bbot; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry) ++{ ++ struct au_dinfo *dinfo; ++ struct au_hdentry *hd; ++ struct au_branch *br; ++ ++ DiMustWriteLock(dentry); ++ ++ dinfo = au_di(dentry); ++ hd = au_hdentry(dinfo, bindex); ++ au_hdput(hd); ++ hd->hd_dentry = h_dentry; ++ if (h_dentry) { ++ br = au_sbr(dentry->d_sb, bindex); ++ hd->hd_id = br->br_id; ++ } ++} ++ ++int au_dbrange_test(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t btop, bbot; ++ ++ err = 0; ++ btop = au_dbtop(dentry); ++ bbot = au_dbbot(dentry); ++ if (btop >= 0) ++ AuDebugOn(bbot < 0 && btop > bbot); ++ else { ++ err = -EIO; ++ AuDebugOn(bbot >= 0); ++ } ++ ++ return err; ++} ++ ++int au_digen_test(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(au_digen(dentry) != sigen ++ || au_iigen_test(d_inode(dentry), sigen))) ++ err = -EIO; ++ ++ return err; ++} ++ ++void au_update_digen(struct dentry *dentry) ++{ ++ atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb)); ++ /* smp_mb(); */ /* atomic_set */ ++} ++ ++void au_update_dbrange(struct dentry *dentry, int do_put_zero) ++{ ++ struct au_dinfo *dinfo; ++ struct dentry *h_d; ++ struct au_hdentry *hdp; ++ aufs_bindex_t bindex, bbot; ++ ++ DiMustWriteLock(dentry); ++ ++ dinfo = au_di(dentry); ++ if (!dinfo || dinfo->di_btop < 0) ++ return; ++ ++ if (do_put_zero) { ++ bbot = dinfo->di_bbot; ++ bindex = dinfo->di_btop; ++ hdp = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, hdp++) { ++ h_d = hdp->hd_dentry; ++ if (h_d && d_is_negative(h_d)) ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++ } ++ ++ dinfo->di_btop = 0; ++ hdp = au_hdentry(dinfo, dinfo->di_btop); ++ for (; dinfo->di_btop <= dinfo->di_bbot; dinfo->di_btop++, hdp++) ++ if (hdp->hd_dentry) ++ break; ++ if (dinfo->di_btop > dinfo->di_bbot) { ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ return; ++ } ++ ++ hdp = au_hdentry(dinfo, dinfo->di_bbot); ++ for (; dinfo->di_bbot >= 0; dinfo->di_bbot--, hdp--) ++ if (hdp->hd_dentry) ++ break; ++ AuDebugOn(dinfo->di_btop > dinfo->di_bbot || dinfo->di_bbot < 0); ++} ++ ++void au_update_dbtop(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct dentry *h_dentry; ++ ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ if (d_is_positive(h_dentry)) { ++ au_set_dbtop(dentry, bindex); ++ return; ++ } ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++} ++ ++void au_update_dbbot(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, btop; ++ struct dentry *h_dentry; ++ ++ btop = au_dbtop(dentry); ++ for (bindex = au_dbbot(dentry); bindex >= btop; bindex--) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ if (d_is_positive(h_dentry)) { ++ au_set_dbbot(dentry, bindex); ++ return; ++ } ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++} ++ ++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry) ++{ ++ aufs_bindex_t bindex, bbot; ++ ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) ++ if (au_h_dptr(dentry, bindex) == h_dentry) ++ return bindex; ++ return -1; ++} +diff -Naur null/fs/aufs/dir.c linux-5.15.36/fs/aufs/dir.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/dir.c 2022-05-10 16:51:39.869744219 +0300 +@@ -0,0 +1,765 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * directory operations ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++void au_add_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ unsigned int nlink; ++ ++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ ++ nlink = dir->i_nlink; ++ nlink += h_dir->i_nlink - 2; ++ if (h_dir->i_nlink < 2) ++ nlink += 2; ++ smp_mb(); /* for i_nlink */ ++ /* 0 can happen in revaliding */ ++ set_nlink(dir, nlink); ++} ++ ++void au_sub_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ unsigned int nlink; ++ ++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ ++ nlink = dir->i_nlink; ++ nlink -= h_dir->i_nlink - 2; ++ if (h_dir->i_nlink < 2) ++ nlink -= 2; ++ smp_mb(); /* for i_nlink */ ++ /* nlink == 0 means the branch-fs is broken */ ++ set_nlink(dir, nlink); ++} ++ ++loff_t au_dir_size(struct file *file, struct dentry *dentry) ++{ ++ loff_t sz; ++ aufs_bindex_t bindex, bbot; ++ struct file *h_file; ++ struct dentry *h_dentry; ++ ++ sz = 0; ++ if (file) { ++ AuDebugOn(!d_is_dir(file->f_path.dentry)); ++ ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); ++ bindex <= bbot && sz < KMALLOC_MAX_SIZE; ++ bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (h_file && file_inode(h_file)) ++ sz += vfsub_f_size_read(h_file); ++ } ++ } else { ++ AuDebugOn(!dentry); ++ AuDebugOn(!d_is_dir(dentry)); ++ ++ bbot = au_dbtaildir(dentry); ++ for (bindex = au_dbtop(dentry); ++ bindex <= bbot && sz < KMALLOC_MAX_SIZE; ++ bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) ++ sz += i_size_read(d_inode(h_dentry)); ++ } ++ } ++ if (sz < KMALLOC_MAX_SIZE) ++ sz = roundup_pow_of_two(sz); ++ if (sz > KMALLOC_MAX_SIZE) ++ sz = KMALLOC_MAX_SIZE; ++ else if (sz < NAME_MAX) { ++ BUILD_BUG_ON(AUFS_RDBLK_DEF < NAME_MAX); ++ sz = AUFS_RDBLK_DEF; ++ } ++ return sz; ++} ++ ++struct au_dir_ts_arg { ++ struct dentry *dentry; ++ aufs_bindex_t brid; ++}; ++ ++static void au_do_dir_ts(void *arg) ++{ ++ struct au_dir_ts_arg *a = arg; ++ struct au_dtime dt; ++ struct path h_path; ++ struct inode *dir, *h_dir; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_hinode *hdir; ++ int err; ++ aufs_bindex_t btop, bindex; ++ ++ sb = a->dentry->d_sb; ++ if (d_really_is_negative(a->dentry)) ++ goto out; ++ /* no dir->i_mutex lock */ ++ aufs_read_lock(a->dentry, AuLock_DW); /* noflush */ ++ ++ dir = d_inode(a->dentry); ++ btop = au_ibtop(dir); ++ bindex = au_br_index(sb, a->brid); ++ if (bindex < btop) ++ goto out_unlock; ++ ++ br = au_sbr(sb, bindex); ++ h_path.dentry = au_h_dptr(a->dentry, bindex); ++ if (!h_path.dentry) ++ goto out_unlock; ++ h_path.mnt = au_br_mnt(br); ++ au_dtime_store(&dt, a->dentry, &h_path); ++ ++ br = au_sbr(sb, btop); ++ if (!au_br_writable(br->br_perm)) ++ goto out_unlock; ++ h_path.dentry = au_h_dptr(a->dentry, btop); ++ h_path.mnt = au_br_mnt(br); ++ err = vfsub_mnt_want_write(h_path.mnt); ++ if (err) ++ goto out_unlock; ++ hdir = au_hi(dir, btop); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ h_dir = au_h_iptr(dir, btop); ++ if (h_dir->i_nlink ++ && timespec64_compare(&h_dir->i_mtime, &dt.dt_mtime) < 0) { ++ dt.dt_h_path = h_path; ++ au_dtime_revert(&dt); ++ } ++ au_hn_inode_unlock(hdir); ++ vfsub_mnt_drop_write(h_path.mnt); ++ au_cpup_attr_timesizes(dir); ++ ++out_unlock: ++ aufs_read_unlock(a->dentry, AuLock_DW); ++out: ++ dput(a->dentry); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ au_kfree_try_rcu(arg); ++} ++ ++void au_dir_ts(struct inode *dir, aufs_bindex_t bindex) ++{ ++ int perm, wkq_err; ++ aufs_bindex_t btop; ++ struct au_dir_ts_arg *arg; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ IMustLock(dir); ++ ++ dentry = d_find_any_alias(dir); ++ AuDebugOn(!dentry); ++ sb = dentry->d_sb; ++ btop = au_ibtop(dir); ++ if (btop == bindex) { ++ au_cpup_attr_timesizes(dir); ++ goto out; ++ } ++ ++ perm = au_sbr_perm(sb, btop); ++ if (!au_br_writable(perm)) ++ goto out; ++ ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (!arg) ++ goto out; ++ ++ arg->dentry = dget(dentry); /* will be dput-ted by au_do_dir_ts() */ ++ arg->brid = au_sbr_id(sb, bindex); ++ wkq_err = au_wkq_nowait(au_do_dir_ts, arg, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ pr_err("wkq %d\n", wkq_err); ++ dput(dentry); ++ au_kfree_try_rcu(arg); ++ } ++ ++out: ++ dput(dentry); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int reopen_dir(struct file *file) ++{ ++ int err; ++ unsigned int flags; ++ aufs_bindex_t bindex, btail, btop; ++ struct dentry *dentry, *h_dentry; ++ struct file *h_file; ++ ++ /* open all lower dirs */ ++ dentry = file->f_path.dentry; ++ btop = au_dbtop(dentry); ++ for (bindex = au_fbtop(file); bindex < btop; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbtop(file, btop); ++ ++ btail = au_dbtaildir(dentry); ++ for (bindex = au_fbbot_dir(file); btail < bindex; bindex--) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbbot_dir(file, btail); ++ ++ flags = vfsub_file_flags(file); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ h_file = au_hf_dir(file, bindex); ++ if (h_file) ++ continue; ++ ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; /* close all? */ ++ au_set_h_fptr(file, bindex, h_file); ++ } ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static int do_open_dir(struct file *file, int flags, struct file *h_file) ++{ ++ int err; ++ aufs_bindex_t bindex, btail; ++ struct dentry *dentry, *h_dentry; ++ struct vfsmount *mnt; ++ ++ FiMustWriteLock(file); ++ AuDebugOn(h_file); ++ ++ err = 0; ++ mnt = file->f_path.mnt; ++ dentry = file->f_path.dentry; ++ file->f_version = inode_query_iversion(d_inode(dentry)); ++ bindex = au_dbtop(dentry); ++ au_set_fbtop(file, bindex); ++ btail = au_dbtaildir(dentry); ++ au_set_fbbot_dir(file, btail); ++ for (; !err && bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ ++ err = vfsub_test_mntns(mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ break; ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ break; ++ } ++ au_set_h_fptr(file, bindex, h_file); ++ } ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ if (!err) ++ return 0; /* success */ ++ ++ /* close all */ ++ for (bindex = au_fbtop(file); bindex <= btail; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbtop(file, -1); ++ au_set_fbbot_dir(file, -1); ++ ++ return err; ++} ++ ++static int aufs_open_dir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_fidir *fidir; ++ ++ err = -ENOMEM; ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ fidir = au_fidir_alloc(sb); ++ if (fidir) { ++ struct au_do_open_args args = { ++ .open = do_open_dir, ++ .fidir = fidir ++ }; ++ err = au_do_open(file, &args); ++ if (unlikely(err)) ++ au_kfree_rcu(fidir); ++ } ++ si_read_unlock(sb); ++ return err; ++} ++ ++static int aufs_release_dir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ struct au_vdir *vdir_cache; ++ struct au_finfo *finfo; ++ struct au_fidir *fidir; ++ struct au_hfile *hf; ++ aufs_bindex_t bindex, bbot; ++ ++ finfo = au_fi(file); ++ fidir = finfo->fi_hdir; ++ if (fidir) { ++ au_hbl_del(&finfo->fi_hlist, ++ &au_sbi(file->f_path.dentry->d_sb)->si_files); ++ vdir_cache = fidir->fd_vdir_cache; /* lock-free */ ++ if (vdir_cache) ++ au_vdir_free(vdir_cache); ++ ++ bindex = finfo->fi_btop; ++ if (bindex >= 0) { ++ hf = fidir->fd_hfile + bindex; ++ /* ++ * calls fput() instead of filp_close(), ++ * since no dnotify or lock for the lower file. ++ */ ++ bbot = fidir->fd_bbot; ++ for (; bindex <= bbot; bindex++, hf++) ++ if (hf->hf_file) ++ au_hfput(hf, /*execed*/0); ++ } ++ au_kfree_rcu(fidir); ++ finfo->fi_hdir = NULL; ++ } ++ au_finfo_fin(file); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_flush_dir(struct file *file, fl_owner_t id) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct file *h_file; ++ ++ err = 0; ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); !err && bindex <= bbot; bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (h_file) ++ err = vfsub_flush(h_file, id); ++ } ++ return err; ++} ++ ++static int aufs_flush_dir(struct file *file, fl_owner_t id) ++{ ++ return au_do_flush(file, id, au_do_flush_dir); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_fsync_dir_no_file(struct dentry *dentry, int datasync) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); !err && bindex <= bbot; bindex++) { ++ struct path h_path; ++ ++ if (au_test_ro(sb, bindex, inode)) ++ continue; ++ h_path.dentry = au_h_dptr(dentry, bindex); ++ if (!h_path.dentry) ++ continue; ++ ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_fsync(NULL, &h_path, datasync); ++ } ++ ++ return err; ++} ++ ++static int au_do_fsync_dir(struct file *file, int datasync) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct file *h_file; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1, /*fi_lsc*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); !err && bindex <= bbot; bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (!h_file || au_test_ro(sb, bindex, inode)) ++ continue; ++ ++ err = vfsub_fsync(h_file, &h_file->f_path, datasync); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * @file may be NULL ++ */ ++static int aufs_fsync_dir(struct file *file, loff_t start, loff_t end, ++ int datasync) ++{ ++ int err; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ err = 0; ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ inode_lock(inode); ++ sb = dentry->d_sb; ++ si_noflush_read_lock(sb); ++ if (file) ++ err = au_do_fsync_dir(file, datasync); ++ else { ++ di_write_lock_child(dentry); ++ err = au_do_fsync_dir_no_file(dentry, datasync); ++ } ++ au_cpup_attr_timesizes(inode); ++ di_write_unlock(dentry); ++ if (file) ++ fi_write_unlock(file); ++ ++ si_read_unlock(sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_iterate_shared(struct file *file, struct dir_context *ctx) ++{ ++ int err; ++ struct dentry *dentry; ++ struct inode *inode, *h_inode; ++ struct super_block *sb; ++ ++ AuDbg("%pD, ctx{%ps, %llu}\n", file, ctx->actor, ctx->pos); ++ ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1, /*fi_lsc*/0); ++ if (unlikely(err)) ++ goto out; ++ err = au_alive_dir(dentry); ++ if (!err) ++ err = au_vdir_init(file); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ if (!au_test_nfsd()) { ++ err = au_vdir_fill_de(file, ctx); ++ fsstack_copy_attr_atime(inode, h_inode); ++ } else { ++ /* ++ * nfsd filldir may call lookup_one_len(), vfs_getattr(), ++ * encode_fh() and others. ++ */ ++ atomic_inc(&h_inode->i_count); ++ di_read_unlock(dentry, AuLock_IR); ++ si_read_unlock(sb); ++ err = au_vdir_fill_de(file, ctx); ++ fsstack_copy_attr_atime(inode, h_inode); ++ fi_write_unlock(file); ++ iput(h_inode); ++ ++ AuTraceErr(err); ++ return err; ++ } ++ ++out_unlock: ++ di_read_unlock(dentry, AuLock_IR); ++ fi_write_unlock(file); ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuTestEmpty_WHONLY 1 ++#define AuTestEmpty_CALLED (1 << 1) ++#define AuTestEmpty_SHWH (1 << 2) ++#define au_ftest_testempty(flags, name) ((flags) & AuTestEmpty_##name) ++#define au_fset_testempty(flags, name) \ ++ do { (flags) |= AuTestEmpty_##name; } while (0) ++#define au_fclr_testempty(flags, name) \ ++ do { (flags) &= ~AuTestEmpty_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_SHWH ++#undef AuTestEmpty_SHWH ++#define AuTestEmpty_SHWH 0 ++#endif ++ ++struct test_empty_arg { ++ struct dir_context ctx; ++ struct au_nhash *whlist; ++ unsigned int flags; ++ int err; ++ aufs_bindex_t bindex; ++}; ++ ++static int test_empty_cb(struct dir_context *ctx, const char *__name, ++ int namelen, loff_t offset __maybe_unused, u64 ino, ++ unsigned int d_type) ++{ ++ struct test_empty_arg *arg = container_of(ctx, struct test_empty_arg, ++ ctx); ++ char *name = (void *)__name; ++ ++ arg->err = 0; ++ au_fset_testempty(arg->flags, CALLED); ++ /* smp_mb(); */ ++ if (name[0] == '.' ++ && (namelen == 1 || (name[1] == '.' && namelen == 2))) ++ goto out; /* success */ ++ ++ if (namelen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ if (au_ftest_testempty(arg->flags, WHONLY) ++ && !au_nhash_test_known_wh(arg->whlist, name, namelen)) ++ arg->err = -ENOTEMPTY; ++ goto out; ++ } ++ ++ name += AUFS_WH_PFX_LEN; ++ namelen -= AUFS_WH_PFX_LEN; ++ if (!au_nhash_test_known_wh(arg->whlist, name, namelen)) ++ arg->err = au_nhash_append_wh ++ (arg->whlist, name, namelen, ino, d_type, arg->bindex, ++ au_ftest_testempty(arg->flags, SHWH)); ++ ++out: ++ /* smp_mb(); */ ++ AuTraceErr(arg->err); ++ return arg->err; ++} ++ ++static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ 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, ++ /*file*/NULL, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = 0; ++ if (!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE) ++ && !file_inode(h_file)->i_nlink) ++ goto out_put; ++ ++ do { ++ arg->err = 0; ++ au_fclr_testempty(arg->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(h_file, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && au_ftest_testempty(arg->flags, CALLED)); ++ ++out_put: ++ fput(h_file); ++ br = au_sbr(dentry->d_sb, arg->bindex); ++ au_lcnt_dec(&br->br_nfiles); ++out: ++ return err; ++} ++ ++struct do_test_empty_args { ++ int *errp; ++ struct dentry *dentry; ++ struct test_empty_arg *arg; ++}; ++ ++static void call_do_test_empty(void *args) ++{ ++ struct do_test_empty_args *a = args; ++ *a->errp = do_test_empty(a->dentry, a->arg); ++} ++ ++static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ int err, wkq_err; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct user_namespace *h_userns; ++ ++ h_userns = au_sbr_userns(dentry->d_sb, arg->bindex); ++ h_dentry = au_h_dptr(dentry, arg->bindex); ++ h_inode = d_inode(h_dentry); ++ /* todo: i_mode changes anytime? */ ++ inode_lock_shared_nested(h_inode, AuLsc_I_CHILD); ++ err = au_test_h_perm_sio(h_userns, h_inode, MAY_EXEC | MAY_READ); ++ inode_unlock_shared(h_inode); ++ if (!err) ++ err = do_test_empty(dentry, arg); ++ else { ++ struct do_test_empty_args args = { ++ .errp = &err, ++ .dentry = dentry, ++ .arg = arg ++ }; ++ unsigned int flags = arg->flags; ++ ++ wkq_err = au_wkq_wait(call_do_test_empty, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ arg->flags = flags; ++ } ++ ++ return err; ++} ++ ++int au_test_empty_lower(struct dentry *dentry) ++{ ++ int err; ++ unsigned int rdhash; ++ aufs_bindex_t bindex, btop, btail; ++ struct au_nhash whlist; ++ struct test_empty_arg arg = { ++ .ctx = { ++ .actor = test_empty_cb ++ } ++ }; ++ int (*test_empty)(struct dentry *dentry, struct test_empty_arg *arg); ++ ++ SiMustAnyLock(dentry->d_sb); ++ ++ rdhash = au_sbi(dentry->d_sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, dentry)); ++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ ++ arg.flags = 0; ++ arg.whlist = &whlist; ++ btop = au_dbtop(dentry); ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) ++ au_fset_testempty(arg.flags, SHWH); ++ test_empty = do_test_empty; ++ if (au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1)) ++ test_empty = sio_test_empty; ++ arg.bindex = btop; ++ err = test_empty(dentry, &arg); ++ if (unlikely(err)) ++ goto out_whlist; ++ ++ au_fset_testempty(arg.flags, WHONLY); ++ btail = au_dbtaildir(dentry); ++ for (bindex = btop + 1; !err && bindex <= btail; bindex++) { ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) { ++ arg.bindex = bindex; ++ err = test_empty(dentry, &arg); ++ } ++ } ++ ++out_whlist: ++ au_nhash_wh_free(&whlist); ++out: ++ return err; ++} ++ ++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist) ++{ ++ int err; ++ struct test_empty_arg arg = { ++ .ctx = { ++ .actor = test_empty_cb ++ } ++ }; ++ aufs_bindex_t bindex, btail; ++ ++ err = 0; ++ arg.whlist = whlist; ++ arg.flags = AuTestEmpty_WHONLY; ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) ++ au_fset_testempty(arg.flags, SHWH); ++ btail = au_dbtaildir(dentry); ++ for (bindex = au_dbtop(dentry); !err && bindex <= btail; bindex++) { ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) { ++ arg.bindex = bindex; ++ err = sio_test_empty(dentry, &arg); ++ } ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++const struct file_operations aufs_dir_fop = { ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++ .read = generic_read_dir, ++ .iterate_shared = aufs_iterate_shared, ++ .unlocked_ioctl = aufs_ioctl_dir, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = aufs_compat_ioctl_dir, ++#endif ++ .open = aufs_open_dir, ++ .release = aufs_release_dir, ++ .flush = aufs_flush_dir, ++ .fsync = aufs_fsync_dir ++}; +diff -Naur null/fs/aufs/dir.h linux-5.15.36/fs/aufs/dir.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/dir.h 2022-05-10 16:51:39.869744219 +0300 +@@ -0,0 +1,134 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * directory operations ++ */ ++ ++#ifndef __AUFS_DIR_H__ ++#define __AUFS_DIR_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* need to be faster and smaller */ ++ ++struct au_nhash { ++ unsigned int nh_num; ++ struct hlist_head *nh_head; ++}; ++ ++struct au_vdir_destr { ++ unsigned char len; ++ unsigned char name[]; ++} __packed; ++ ++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 { ++ ino_t de_ino; ++ unsigned char de_type; ++ /* caution: packed */ ++ struct au_vdir_destr de_str; ++} __packed; ++ ++struct au_vdir_wh { ++ struct hlist_node wh_hash; ++#ifdef CONFIG_AUFS_SHWH ++ ino_t wh_ino; ++ aufs_bindex_t wh_bindex; ++ unsigned char wh_type; ++#else ++ aufs_bindex_t wh_bindex; ++#endif ++ /* caution: packed */ ++ struct au_vdir_destr wh_str; ++} __packed; ++ ++union au_vdir_deblk_p { ++ unsigned char *deblk; ++ struct au_vdir_de *de; ++}; ++ ++struct au_vdir { ++ unsigned char **vd_deblk; ++ unsigned long vd_nblk; ++ struct { ++ unsigned long ul; ++ union au_vdir_deblk_p p; ++ } vd_last; ++ ++ u64 vd_version; ++ unsigned int vd_deblk_sz; ++ unsigned long vd_jiffy; ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dir.c */ ++extern const struct file_operations aufs_dir_fop; ++void au_add_nlink(struct inode *dir, struct inode *h_dir); ++void au_sub_nlink(struct inode *dir, struct inode *h_dir); ++loff_t au_dir_size(struct file *file, struct dentry *dentry); ++void au_dir_ts(struct inode *dir, aufs_bindex_t bsrc); ++int au_test_empty_lower(struct dentry *dentry); ++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist); ++ ++/* vdir.c */ ++unsigned int au_rdhash_est(loff_t sz); ++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp); ++void au_nhash_wh_free(struct au_nhash *whlist); ++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, ++ int limit); ++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen); ++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, ++ unsigned int d_type, aufs_bindex_t bindex, ++ unsigned char shwh); ++void au_vdir_free(struct au_vdir *vdir); ++int au_vdir_init(struct file *file); ++int au_vdir_fill_de(struct file *file, struct dir_context *ctx); ++ ++/* ioctl.c */ ++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg); ++ ++#ifdef CONFIG_AUFS_RDU ++/* rdu.c */ ++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg); ++#endif ++#else ++AuStub(long, au_rdu_ioctl, return -EINVAL, struct file *file, ++ unsigned int cmd, unsigned long arg) ++#ifdef CONFIG_COMPAT ++AuStub(long, au_rdu_compat_ioctl, return -EINVAL, struct file *file, ++ unsigned int cmd, unsigned long arg) ++#endif ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DIR_H__ */ +diff -Naur null/fs/aufs/dirren.c linux-5.15.36/fs/aufs/dirren.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/dirren.c 2022-05-10 16:51:39.869744219 +0300 +@@ -0,0 +1,1315 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2017-2021 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 . ++ */ ++ ++/* ++ * special handling in renaming a directory ++ * in order to support looking-up the before-renamed name on the lower readonly ++ * branches ++ */ ++ ++#include ++#include "aufs.h" ++ ++static void au_dr_hino_del(struct au_dr_br *dr, struct au_dr_hino *ent) ++{ ++ int idx; ++ ++ idx = au_dr_ihash(ent->dr_h_ino); ++ au_hbl_del(&ent->dr_hnode, dr->dr_h_ino + idx); ++} ++ ++static int au_dr_hino_test_empty(struct au_dr_br *dr) ++{ ++ int ret, i; ++ struct hlist_bl_head *hbl; ++ ++ ret = 1; ++ for (i = 0; ret && i < AuDirren_NHASH; i++) { ++ hbl = dr->dr_h_ino + i; ++ hlist_bl_lock(hbl); ++ ret &= hlist_bl_empty(hbl); ++ hlist_bl_unlock(hbl); ++ } ++ ++ return ret; ++} ++ ++static struct au_dr_hino *au_dr_hino_find(struct au_dr_br *dr, ino_t ino) ++{ ++ struct au_dr_hino *found, *ent; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ int idx; ++ ++ found = NULL; ++ idx = au_dr_ihash(ino); ++ hbl = dr->dr_h_ino + idx; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(ent, pos, hbl, dr_hnode) ++ if (ent->dr_h_ino == ino) { ++ found = ent; ++ break; ++ } ++ hlist_bl_unlock(hbl); ++ ++ return found; ++} ++ ++int au_dr_hino_test_add(struct au_dr_br *dr, ino_t ino, ++ struct au_dr_hino *add_ent) ++{ ++ int found, idx; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_dr_hino *ent; ++ ++ found = 0; ++ idx = au_dr_ihash(ino); ++ hbl = dr->dr_h_ino + idx; ++#if 0 /* debug print */ ++ { ++ struct hlist_bl_node *tmp; ++ ++ hlist_bl_for_each_entry_safe(ent, pos, tmp, hbl, dr_hnode) ++ AuDbg("hi%llu\n", (unsigned long long)ent->dr_h_ino); ++ } ++#endif ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(ent, pos, hbl, dr_hnode) ++ if (ent->dr_h_ino == ino) { ++ found = 1; ++ break; ++ } ++ if (!found && add_ent) ++ hlist_bl_add_head(&add_ent->dr_hnode, hbl); ++ hlist_bl_unlock(hbl); ++ ++ if (!found && add_ent) ++ AuDbg("i%llu added\n", (unsigned long long)add_ent->dr_h_ino); ++ ++ return found; ++} ++ ++void au_dr_hino_free(struct au_dr_br *dr) ++{ ++ int i; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *tmp; ++ struct au_dr_hino *ent; ++ ++ /* SiMustWriteLock(sb); */ ++ ++ for (i = 0; i < AuDirren_NHASH; i++) { ++ 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) ++ au_kfree_rcu(ent); ++ INIT_HLIST_BL_HEAD(hbl); ++ } ++} ++ ++/* returns the number of inodes or an error */ ++static int au_dr_hino_store(struct super_block *sb, struct au_branch *br, ++ struct file *hinofile) ++{ ++ int err, i; ++ ssize_t ssz; ++ loff_t pos, oldsize; ++ __be64 u64; ++ struct inode *hinoinode; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *n1, *n2; ++ struct au_dr_hino *ent; ++ ++ SiMustWriteLock(sb); ++ AuDebugOn(!au_br_writable(br->br_perm)); ++ ++ hinoinode = file_inode(hinofile); ++ oldsize = i_size_read(hinoinode); ++ ++ err = 0; ++ pos = 0; ++ hbl = br->br_dirren.dr_h_ino; ++ for (i = 0; !err && i < AuDirren_NHASH; i++, hbl++) { ++ /* no bit-lock since sbinfo must be write-locked */ ++ hlist_bl_for_each_entry_safe(ent, n1, n2, hbl, dr_hnode) { ++ AuDbg("hi%llu, %pD2\n", ++ (unsigned long long)ent->dr_h_ino, hinofile); ++ u64 = cpu_to_be64(ent->dr_h_ino); ++ ssz = vfsub_write_k(hinofile, &u64, sizeof(u64), &pos); ++ if (ssz == sizeof(u64)) ++ continue; ++ ++ /* write error */ ++ pr_err("ssz %zd, %pD2\n", ssz, hinofile); ++ err = -ENOSPC; ++ if (ssz < 0) ++ err = ssz; ++ break; ++ } ++ } ++ /* regardless the error */ ++ if (pos < oldsize) { ++ err = vfsub_trunc(&hinofile->f_path, pos, /*attr*/0, hinofile); ++ AuTraceErr(err); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_dr_hino_load(struct au_dr_br *dr, struct file *hinofile) ++{ ++ int err, hidx; ++ ssize_t ssz; ++ size_t sz, n; ++ loff_t pos; ++ uint64_t u64; ++ struct au_dr_hino *ent; ++ struct inode *hinoinode; ++ struct hlist_bl_head *hbl; ++ ++ err = 0; ++ pos = 0; ++ hbl = dr->dr_h_ino; ++ hinoinode = file_inode(hinofile); ++ sz = i_size_read(hinoinode); ++ AuDebugOn(sz % sizeof(u64)); ++ n = sz / sizeof(u64); ++ while (n--) { ++ ssz = vfsub_read_k(hinofile, &u64, sizeof(u64), &pos); ++ if (unlikely(ssz != sizeof(u64))) { ++ pr_err("ssz %zd, %pD2\n", ssz, hinofile); ++ err = -EINVAL; ++ if (ssz < 0) ++ err = ssz; ++ goto out_free; ++ } ++ ++ ent = kmalloc(sizeof(*ent), GFP_NOFS); ++ if (!ent) { ++ err = -ENOMEM; ++ AuTraceErr(err); ++ goto out_free; ++ } ++ ent->dr_h_ino = be64_to_cpu((__force __be64)u64); ++ AuDbg("hi%llu, %pD2\n", ++ (unsigned long long)ent->dr_h_ino, hinofile); ++ hidx = au_dr_ihash(ent->dr_h_ino); ++ au_hbl_add(&ent->dr_hnode, hbl + hidx); ++ } ++ goto out; /* success */ ++ ++out_free: ++ au_dr_hino_free(dr); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * @bindex/@br is a switch to distinguish whether suspending hnotify or not. ++ * @path is a switch to distinguish load and store. ++ */ ++static int au_dr_hino(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_branch *br, const struct path *path) ++{ ++ int err, flags; ++ unsigned char load, suspend; ++ struct file *hinofile; ++ struct au_hinode *hdir; ++ struct inode *dir, *delegated; ++ struct path hinopath; ++ struct qstr hinoname = QSTR_INIT(AUFS_WH_DR_BRHINO, ++ sizeof(AUFS_WH_DR_BRHINO) - 1); ++ ++ AuDebugOn(bindex < 0 && !br); ++ AuDebugOn(bindex >= 0 && br); ++ ++ err = -EINVAL; ++ suspend = !br; ++ if (suspend) ++ br = au_sbr(sb, bindex); ++ load = !!path; ++ if (!load) { ++ path = &br->br_path; ++ AuDebugOn(!au_br_writable(br->br_perm)); ++ if (unlikely(!au_br_writable(br->br_perm))) ++ goto out; ++ } ++ ++ hdir = NULL; ++ if (suspend) { ++ dir = d_inode(sb->s_root); ++ hdir = au_hinode(au_ii(dir), bindex); ++ dir = hdir->hi_inode; ++ au_hn_inode_lock_nested(hdir, AuLsc_I_CHILD); ++ } else { ++ dir = d_inode(path->dentry); ++ inode_lock_nested(dir, AuLsc_I_CHILD); ++ } ++ hinopath.mnt = path->mnt; ++ hinopath.dentry = vfsub_lkup_one(&hinoname, (struct path *)path); ++ err = PTR_ERR(hinopath.dentry); ++ if (IS_ERR(hinopath.dentry)) ++ goto out_unlock; ++ ++ err = 0; ++ flags = O_RDONLY; ++ if (load) { ++ if (d_is_negative(hinopath.dentry)) ++ goto out_dput; /* success */ ++ } else { ++ if (au_dr_hino_test_empty(&br->br_dirren)) { ++ if (d_is_positive(hinopath.dentry)) { ++ delegated = NULL; ++ err = vfsub_unlink(dir, &hinopath, &delegated, ++ /*force*/0); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ pr_err("ignored err %d, %pd2\n", ++ err, hinopath.dentry); ++ if (unlikely(err == -EWOULDBLOCK)) ++ iput(delegated); ++ err = 0; ++ } ++ goto out_dput; ++ } else if (!d_is_positive(hinopath.dentry)) { ++ err = vfsub_create(dir, &hinopath, 0600, ++ /*want_excl*/false); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out_dput; ++ } ++ flags = O_WRONLY; ++ } ++ hinofile = vfsub_dentry_open(&hinopath, flags); ++ if (suspend) ++ au_hn_inode_unlock(hdir); ++ else ++ inode_unlock(dir); ++ dput(hinopath.dentry); ++ AuTraceErrPtr(hinofile); ++ if (IS_ERR(hinofile)) { ++ err = PTR_ERR(hinofile); ++ goto out; ++ } ++ ++ if (load) ++ err = au_dr_hino_load(&br->br_dirren, hinofile); ++ else ++ err = au_dr_hino_store(sb, br, hinofile); ++ fput(hinofile); ++ goto out; ++ ++out_dput: ++ dput(hinopath.dentry); ++out_unlock: ++ if (suspend) ++ au_hn_inode_unlock(hdir); ++ else ++ inode_unlock(dir); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_dr_brid_init(struct au_dr_brid *brid, const struct path *path) ++{ ++ int err; ++ struct kstatfs kstfs; ++ dev_t dev; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ err = vfs_statfs((void *)path, &kstfs); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ /* todo: support for UUID */ ++ ++ if (kstfs.f_fsid.val[0] || kstfs.f_fsid.val[1]) { ++ brid->type = AuBrid_FSID; ++ brid->fsid = kstfs.f_fsid; ++ } else { ++ dentry = path->dentry; ++ sb = dentry->d_sb; ++ dev = sb->s_dev; ++ if (dev) { ++ brid->type = AuBrid_DEV; ++ brid->dev = dev; ++ } ++ } ++ ++out: ++ return err; ++} ++ ++int au_dr_br_init(struct super_block *sb, struct au_branch *br, ++ const struct path *path) ++{ ++ int err, i; ++ struct au_dr_br *dr; ++ struct hlist_bl_head *hbl; ++ ++ dr = &br->br_dirren; ++ hbl = dr->dr_h_ino; ++ for (i = 0; i < AuDirren_NHASH; i++, hbl++) ++ INIT_HLIST_BL_HEAD(hbl); ++ ++ err = au_dr_brid_init(&dr->dr_brid, path); ++ if (unlikely(err)) ++ goto out; ++ ++ if (au_opt_test(au_mntflags(sb), DIRREN)) ++ err = au_dr_hino(sb, /*bindex*/-1, br, path); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_dr_br_fin(struct super_block *sb, struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ if (au_br_writable(br->br_perm)) ++ err = au_dr_hino(sb, /*bindex*/-1, br, /*path*/NULL); ++ if (!err) ++ au_dr_hino_free(&br->br_dirren); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_brid_str(struct au_dr_brid *brid, struct inode *h_inode, ++ char *buf, size_t sz) ++{ ++ int err; ++ unsigned int major, minor; ++ char *p; ++ ++ p = buf; ++ err = snprintf(p, sz, "%d_", brid->type); ++ AuDebugOn(err > sz); ++ p += err; ++ sz -= err; ++ switch (brid->type) { ++ case AuBrid_Unset: ++ return -EINVAL; ++ case AuBrid_UUID: ++ err = snprintf(p, sz, "%pU", brid->uuid.b); ++ break; ++ case AuBrid_FSID: ++ err = snprintf(p, sz, "%08x-%08x", ++ brid->fsid.val[0], brid->fsid.val[1]); ++ break; ++ case AuBrid_DEV: ++ major = MAJOR(brid->dev); ++ minor = MINOR(brid->dev); ++ if (major <= 0xff && minor <= 0xff) ++ err = snprintf(p, sz, "%02x%02x", major, minor); ++ else ++ err = snprintf(p, sz, "%03x:%05x", major, minor); ++ break; ++ } ++ AuDebugOn(err > sz); ++ p += err; ++ sz -= err; ++ err = snprintf(p, sz, "_%llu", (unsigned long long)h_inode->i_ino); ++ AuDebugOn(err > sz); ++ p += err; ++ sz -= err; ++ ++ return p - buf; ++} ++ ++static int au_drinfo_name(struct au_branch *br, char *name, int len) ++{ ++ int rlen; ++ struct dentry *br_dentry; ++ struct inode *br_inode; ++ ++ br_dentry = au_br_dentry(br); ++ br_inode = d_inode(br_dentry); ++ rlen = au_brid_str(&br->br_dirren.dr_brid, br_inode, name, len); ++ AuDebugOn(rlen >= AUFS_DIRREN_ENV_VAL_SZ); ++ AuDebugOn(rlen > len); ++ ++ return rlen; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * from the given @h_dentry, construct drinfo at @*fdata. ++ * when the size of @*fdata is not enough, reallocate and return new @fdata and ++ * @allocated. ++ */ ++static int au_drinfo_construct(struct au_drinfo_fdata **fdata, ++ struct dentry *h_dentry, ++ unsigned char *allocated) ++{ ++ int err, v; ++ struct au_drinfo_fdata *f, *p; ++ struct au_drinfo *drinfo; ++ struct inode *h_inode; ++ struct qstr *qname; ++ ++ err = 0; ++ f = *fdata; ++ h_inode = d_inode(h_dentry); ++ qname = &h_dentry->d_name; ++ drinfo = &f->drinfo; ++ drinfo->ino = (__force uint64_t)cpu_to_be64(h_inode->i_ino); ++ drinfo->oldnamelen = qname->len; ++ if (*allocated < sizeof(*f) + qname->len) { ++ v = roundup_pow_of_two(*allocated + qname->len); ++ p = au_krealloc(f, v, GFP_NOFS, /*may_shrink*/0); ++ if (unlikely(!p)) { ++ err = -ENOMEM; ++ AuTraceErr(err); ++ goto out; ++ } ++ f = p; ++ *fdata = f; ++ *allocated = v; ++ drinfo = &f->drinfo; ++ } ++ memcpy(drinfo->oldname, qname->name, qname->len); ++ AuDbg("i%llu, %.*s\n", ++ be64_to_cpu((__force __be64)drinfo->ino), drinfo->oldnamelen, ++ drinfo->oldname); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* callers have to free the return value */ ++static struct au_drinfo *au_drinfo_read_k(struct file *file, ino_t h_ino) ++{ ++ struct au_drinfo *ret, *drinfo; ++ struct au_drinfo_fdata fdata; ++ int len; ++ loff_t pos; ++ ssize_t ssz; ++ ++ ret = ERR_PTR(-EIO); ++ pos = 0; ++ ssz = vfsub_read_k(file, &fdata, sizeof(fdata), &pos); ++ if (unlikely(ssz != sizeof(fdata))) { ++ AuIOErr("ssz %zd, %u, %pD2\n", ++ ssz, (unsigned int)sizeof(fdata), file); ++ goto out; ++ } ++ ++ fdata.magic = ntohl((__force __be32)fdata.magic); ++ switch (fdata.magic) { ++ case AUFS_DRINFO_MAGIC_V1: ++ break; ++ default: ++ AuIOErr("magic-num 0x%x, 0x%x, %pD2\n", ++ fdata.magic, AUFS_DRINFO_MAGIC_V1, file); ++ goto out; ++ } ++ ++ drinfo = &fdata.drinfo; ++ len = drinfo->oldnamelen; ++ if (!len) { ++ AuIOErr("broken drinfo %pD2\n", file); ++ goto out; ++ } ++ ++ ret = NULL; ++ drinfo->ino = be64_to_cpu((__force __be64)drinfo->ino); ++ if (unlikely(h_ino && drinfo->ino != h_ino)) { ++ AuDbg("ignored i%llu, i%llu, %pD2\n", ++ (unsigned long long)drinfo->ino, ++ (unsigned long long)h_ino, file); ++ goto out; /* success */ ++ } ++ ++ ret = kmalloc(sizeof(*ret) + len, GFP_NOFS); ++ if (unlikely(!ret)) { ++ ret = ERR_PTR(-ENOMEM); ++ AuTraceErrPtr(ret); ++ goto out; ++ } ++ ++ *ret = *drinfo; ++ ssz = vfsub_read_k(file, (void *)ret->oldname, len, &pos); ++ if (unlikely(ssz != len)) { ++ au_kfree_rcu(ret); ++ ret = ERR_PTR(-EIO); ++ AuIOErr("ssz %zd, %u, %pD2\n", ssz, len, file); ++ goto out; ++ } ++ ++ AuDbg("oldname %.*s\n", ret->oldnamelen, ret->oldname); ++ ++out: ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* in order to be revertible */ ++struct au_drinfo_rev_elm { ++ int created; ++ struct dentry *info_dentry; ++ struct au_drinfo *info_last; ++}; ++ ++struct au_drinfo_rev { ++ unsigned char already; ++ aufs_bindex_t nelm; ++ struct au_drinfo_rev_elm elm[]; ++}; ++ ++/* todo: isn't it too large? */ ++struct au_drinfo_store { ++ struct path h_ppath; ++ struct dentry *h_dentry; ++ struct au_drinfo_fdata *fdata; ++ char *infoname; /* inside of whname, just after PFX */ ++ char whname[sizeof(AUFS_WH_DR_INFO_PFX) + AUFS_DIRREN_ENV_VAL_SZ]; ++ aufs_bindex_t btgt, btail; ++ unsigned char no_sio, ++ allocated, /* current size of *fdata */ ++ infonamelen, /* room size for p */ ++ whnamelen, /* length of the generated name */ ++ renameback; /* renamed back */ ++}; ++ ++/* on rename(2) error, the caller should revert it using @elm */ ++static int au_drinfo_do_store(struct au_drinfo_store *w, ++ struct au_drinfo_rev_elm *elm) ++{ ++ int err, len; ++ ssize_t ssz; ++ loff_t pos; ++ struct path infopath = { ++ .mnt = w->h_ppath.mnt ++ }; ++ struct inode *h_dir, *h_inode, *delegated; ++ struct file *infofile; ++ struct qstr *qname; ++ ++ AuDebugOn(elm ++ && memcmp(elm, page_address(ZERO_PAGE(0)), sizeof(*elm))); ++ ++ infopath.dentry = vfsub_lookup_one_len(w->whname, &w->h_ppath, ++ w->whnamelen); ++ AuTraceErrPtr(infopath.dentry); ++ if (IS_ERR(infopath.dentry)) { ++ err = PTR_ERR(infopath.dentry); ++ goto out; ++ } ++ ++ err = 0; ++ h_dir = d_inode(w->h_ppath.dentry); ++ if (elm && d_is_negative(infopath.dentry)) { ++ err = vfsub_create(h_dir, &infopath, 0600, /*want_excl*/true); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out_dput; ++ elm->created = 1; ++ elm->info_dentry = dget(infopath.dentry); ++ } ++ ++ infofile = vfsub_dentry_open(&infopath, O_RDWR); ++ AuTraceErrPtr(infofile); ++ if (IS_ERR(infofile)) { ++ err = PTR_ERR(infofile); ++ goto out_dput; ++ } ++ ++ h_inode = d_inode(infopath.dentry); ++ if (elm && i_size_read(h_inode)) { ++ h_inode = d_inode(w->h_dentry); ++ elm->info_last = au_drinfo_read_k(infofile, h_inode->i_ino); ++ AuTraceErrPtr(elm->info_last); ++ if (IS_ERR(elm->info_last)) { ++ err = PTR_ERR(elm->info_last); ++ elm->info_last = NULL; ++ AuDebugOn(elm->info_dentry); ++ goto out_fput; ++ } ++ } ++ ++ if (elm && w->renameback) { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &infopath, &delegated, /*force*/0); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) ++ iput(delegated); ++ goto out_fput; ++ } ++ ++ pos = 0; ++ qname = &w->h_dentry->d_name; ++ len = sizeof(*w->fdata) + qname->len; ++ if (!elm) ++ len = sizeof(*w->fdata) + w->fdata->drinfo.oldnamelen; ++ ssz = vfsub_write_k(infofile, w->fdata, len, &pos); ++ if (ssz == len) { ++ AuDbg("hi%llu, %.*s\n", w->fdata->drinfo.ino, ++ w->fdata->drinfo.oldnamelen, w->fdata->drinfo.oldname); ++ goto out_fput; /* success */ ++ } else { ++ err = -EIO; ++ if (ssz < 0) ++ err = ssz; ++ /* the caller should revert it using @elm */ ++ } ++ ++out_fput: ++ fput(infofile); ++out_dput: ++ dput(infopath.dentry); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++struct au_call_drinfo_do_store_args { ++ int *errp; ++ struct au_drinfo_store *w; ++ struct au_drinfo_rev_elm *elm; ++}; ++ ++static void au_call_drinfo_do_store(void *args) ++{ ++ struct au_call_drinfo_do_store_args *a = args; ++ ++ *a->errp = au_drinfo_do_store(a->w, a->elm); ++} ++ ++static int au_drinfo_store_sio(struct au_drinfo_store *w, ++ struct au_drinfo_rev_elm *elm) ++{ ++ int err, wkq_err; ++ ++ if (w->no_sio) ++ err = au_drinfo_do_store(w, elm); ++ else { ++ struct au_call_drinfo_do_store_args a = { ++ .errp = &err, ++ .w = w, ++ .elm = elm ++ }; ++ wkq_err = au_wkq_wait(au_call_drinfo_do_store, &a); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ AuTraceErr(err); ++ ++ return err; ++} ++ ++static int au_drinfo_store_work_init(struct au_drinfo_store *w, ++ aufs_bindex_t btgt) ++{ ++ int err; ++ ++ memset(w, 0, sizeof(*w)); ++ w->allocated = roundup_pow_of_two(sizeof(*w->fdata) + 40); ++ strcpy(w->whname, AUFS_WH_DR_INFO_PFX); ++ w->infoname = w->whname + sizeof(AUFS_WH_DR_INFO_PFX) - 1; ++ w->infonamelen = sizeof(w->whname) - sizeof(AUFS_WH_DR_INFO_PFX); ++ w->btgt = btgt; ++ w->no_sio = !!uid_eq(current_fsuid(), GLOBAL_ROOT_UID); ++ ++ err = -ENOMEM; ++ w->fdata = kcalloc(1, w->allocated, GFP_NOFS); ++ if (unlikely(!w->fdata)) { ++ AuTraceErr(err); ++ goto out; ++ } ++ w->fdata->magic = (__force uint32_t)htonl(AUFS_DRINFO_MAGIC_V1); ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static void au_drinfo_store_work_fin(struct au_drinfo_store *w) ++{ ++ au_kfree_rcu(w->fdata); ++} ++ ++static void au_drinfo_store_rev(struct au_drinfo_rev *rev, ++ struct au_drinfo_store *w) ++{ ++ struct au_drinfo_rev_elm *elm; ++ struct inode *h_dir, *delegated; ++ int err, nelm; ++ struct path infopath = { ++ .mnt = w->h_ppath.mnt ++ }; ++ ++ h_dir = d_inode(w->h_ppath.dentry); ++ IMustLock(h_dir); ++ ++ err = 0; ++ elm = rev->elm; ++ for (nelm = rev->nelm; nelm > 0; nelm--, elm++) { ++ AuDebugOn(elm->created && elm->info_last); ++ if (elm->created) { ++ AuDbg("here\n"); ++ delegated = NULL; ++ infopath.dentry = elm->info_dentry; ++ err = vfsub_unlink(h_dir, &infopath, &delegated, ++ !w->no_sio); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) ++ iput(delegated); ++ dput(elm->info_dentry); ++ } else if (elm->info_last) { ++ AuDbg("here\n"); ++ w->fdata->drinfo = *elm->info_last; ++ memcpy(w->fdata->drinfo.oldname, ++ elm->info_last->oldname, ++ elm->info_last->oldnamelen); ++ err = au_drinfo_store_sio(w, /*elm*/NULL); ++ au_kfree_rcu(elm->info_last); ++ } ++ if (unlikely(err)) ++ AuIOErr("%d, %s\n", err, w->whname); ++ /* go on even if err */ ++ } ++} ++ ++/* caller has to call au_dr_rename_fin() later */ ++static int au_drinfo_store(struct dentry *dentry, aufs_bindex_t btgt, ++ struct qstr *dst_name, void *_rev) ++{ ++ int err, sz, nelm; ++ aufs_bindex_t bindex, btail; ++ struct au_drinfo_store work; ++ struct au_drinfo_rev *rev, **p; ++ struct au_drinfo_rev_elm *elm; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_hinode *hdir; ++ ++ err = au_drinfo_store_work_init(&work, btgt); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -ENOMEM; ++ btail = au_dbtaildir(dentry); ++ nelm = btail - btgt; ++ sz = sizeof(*rev) + sizeof(*elm) * nelm; ++ rev = kcalloc(1, sz, GFP_NOFS); ++ if (unlikely(!rev)) { ++ AuTraceErr(err); ++ goto out_args; ++ } ++ rev->nelm = nelm; ++ elm = rev->elm; ++ p = _rev; ++ *p = rev; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ work.h_ppath.dentry = au_h_dptr(dentry, btgt); ++ work.h_ppath.mnt = au_sbr_mnt(sb, btgt); ++ hdir = au_hi(d_inode(dentry), btgt); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_CHILD); ++ for (bindex = btgt + 1; bindex <= btail; bindex++, elm++) { ++ work.h_dentry = au_h_dptr(dentry, bindex); ++ if (!work.h_dentry) ++ continue; ++ ++ err = au_drinfo_construct(&work.fdata, work.h_dentry, ++ &work.allocated); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ break; ++ ++ work.renameback = au_qstreq(&work.h_dentry->d_name, dst_name); ++ br = au_sbr(sb, bindex); ++ work.whnamelen = sizeof(AUFS_WH_DR_INFO_PFX) - 1; ++ work.whnamelen += au_drinfo_name(br, work.infoname, ++ work.infonamelen); ++ AuDbg("whname %.*s, i%llu, %.*s\n", ++ work.whnamelen, work.whname, ++ be64_to_cpu((__force __be64)work.fdata->drinfo.ino), ++ work.fdata->drinfo.oldnamelen, ++ work.fdata->drinfo.oldname); ++ ++ err = au_drinfo_store_sio(&work, elm); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ break; ++ } ++ if (unlikely(err)) { ++ /* revert all drinfo */ ++ au_drinfo_store_rev(rev, &work); ++ au_kfree_try_rcu(rev); ++ *p = NULL; ++ } ++ au_hn_inode_unlock(hdir); ++ ++out_args: ++ au_drinfo_store_work_fin(&work); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dr_rename(struct dentry *src, aufs_bindex_t bindex, ++ struct qstr *dst_name, void *_rev) ++{ ++ int err, already; ++ ino_t ino; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_dr_br *dr; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_dr_hino *ent; ++ struct au_drinfo_rev *rev, **p; ++ ++ AuDbg("bindex %d\n", bindex); ++ ++ err = -ENOMEM; ++ ent = kmalloc(sizeof(*ent), GFP_NOFS); ++ if (unlikely(!ent)) ++ goto out; ++ ++ sb = src->d_sb; ++ br = au_sbr(sb, bindex); ++ dr = &br->br_dirren; ++ h_dentry = au_h_dptr(src, bindex); ++ h_inode = d_inode(h_dentry); ++ ino = h_inode->i_ino; ++ ent->dr_h_ino = ino; ++ already = au_dr_hino_test_add(dr, ino, ent); ++ AuDbg("b%d, hi%llu, already %d\n", ++ bindex, (unsigned long long)ino, already); ++ ++ err = au_drinfo_store(src, bindex, dst_name, _rev); ++ AuTraceErr(err); ++ if (!err) { ++ p = _rev; ++ rev = *p; ++ rev->already = already; ++ goto out; /* success */ ++ } ++ ++ /* revert */ ++ if (!already) ++ au_dr_hino_del(dr, ent); ++ au_kfree_rcu(ent); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_dr_rename_fin(struct dentry *src, aufs_bindex_t btgt, void *_rev) ++{ ++ struct au_drinfo_rev *rev; ++ struct au_drinfo_rev_elm *elm; ++ int nelm; ++ ++ rev = _rev; ++ elm = rev->elm; ++ for (nelm = rev->nelm; nelm > 0; nelm--, elm++) { ++ dput(elm->info_dentry); ++ au_kfree_rcu(elm->info_last); ++ } ++ au_kfree_try_rcu(rev); ++} ++ ++void au_dr_rename_rev(struct dentry *src, aufs_bindex_t btgt, void *_rev) ++{ ++ int err; ++ struct au_drinfo_store work; ++ struct au_drinfo_rev *rev = _rev; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct inode *h_inode; ++ struct au_dr_br *dr; ++ struct au_dr_hino *ent; ++ ++ err = au_drinfo_store_work_init(&work, btgt); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = src->d_sb; ++ br = au_sbr(sb, btgt); ++ work.h_ppath.dentry = au_h_dptr(src, btgt); ++ work.h_ppath.mnt = au_br_mnt(br); ++ au_drinfo_store_rev(rev, &work); ++ au_drinfo_store_work_fin(&work); ++ if (rev->already) ++ goto out; ++ ++ dr = &br->br_dirren; ++ h_inode = d_inode(work.h_ppath.dentry); ++ ent = au_dr_hino_find(dr, h_inode->i_ino); ++ BUG_ON(!ent); ++ au_dr_hino_del(dr, ent); ++ au_kfree_rcu(ent); ++ ++out: ++ au_kfree_try_rcu(rev); ++ if (unlikely(err)) ++ pr_err("failed to remove dirren info\n"); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct au_drinfo *au_drinfo_do_load(struct path *h_ppath, ++ char *whname, int whnamelen, ++ struct dentry **info_dentry) ++{ ++ struct au_drinfo *drinfo; ++ struct file *f; ++ struct inode *h_dir; ++ struct path infopath; ++ int unlocked; ++ ++ AuDbg("%pd/%.*s\n", h_ppath->dentry, whnamelen, whname); ++ ++ *info_dentry = NULL; ++ drinfo = NULL; ++ unlocked = 0; ++ h_dir = d_inode(h_ppath->dentry); ++ inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); ++ infopath.dentry = vfsub_lookup_one_len(whname, h_ppath, whnamelen); ++ if (IS_ERR(infopath.dentry)) { ++ drinfo = (void *)infopath.dentry; ++ goto out; ++ } ++ ++ if (d_is_negative(infopath.dentry)) ++ goto out_dput; /* success */ ++ ++ infopath.mnt = h_ppath->mnt; ++ f = vfsub_dentry_open(&infopath, O_RDONLY); ++ inode_unlock_shared(h_dir); ++ unlocked = 1; ++ if (IS_ERR(f)) { ++ drinfo = (void *)f; ++ goto out_dput; ++ } ++ ++ drinfo = au_drinfo_read_k(f, /*h_ino*/0); ++ if (IS_ERR_OR_NULL(drinfo)) ++ goto out_fput; ++ ++ AuDbg("oldname %.*s\n", drinfo->oldnamelen, drinfo->oldname); ++ *info_dentry = dget(infopath.dentry); /* keep it alive */ ++ ++out_fput: ++ fput(f); ++out_dput: ++ dput(infopath.dentry); ++out: ++ if (!unlocked) ++ inode_unlock_shared(h_dir); ++ AuTraceErrPtr(drinfo); ++ return drinfo; ++} ++ ++struct au_drinfo_do_load_args { ++ struct au_drinfo **drinfop; ++ struct path *h_ppath; ++ char *whname; ++ int whnamelen; ++ struct dentry **info_dentry; ++}; ++ ++static void au_call_drinfo_do_load(void *args) ++{ ++ struct au_drinfo_do_load_args *a = args; ++ ++ *a->drinfop = au_drinfo_do_load(a->h_ppath, a->whname, a->whnamelen, ++ a->info_dentry); ++} ++ ++struct au_drinfo_load { ++ struct path h_ppath; ++ struct qstr *qname; ++ unsigned char no_sio; ++ ++ aufs_bindex_t ninfo; ++ struct au_drinfo **drinfo; ++}; ++ ++static int au_drinfo_load(struct au_drinfo_load *w, aufs_bindex_t bindex, ++ struct au_branch *br) ++{ ++ int err, wkq_err, whnamelen, e; ++ char whname[sizeof(AUFS_WH_DR_INFO_PFX) + AUFS_DIRREN_ENV_VAL_SZ] ++ = AUFS_WH_DR_INFO_PFX; ++ struct au_drinfo *drinfo; ++ struct qstr oldname; ++ struct inode *h_dir, *delegated; ++ struct dentry *info_dentry; ++ struct path infopath; ++ ++ whnamelen = sizeof(AUFS_WH_DR_INFO_PFX) - 1; ++ whnamelen += au_drinfo_name(br, whname + whnamelen, ++ sizeof(whname) - whnamelen); ++ if (w->no_sio) ++ drinfo = au_drinfo_do_load(&w->h_ppath, whname, whnamelen, ++ &info_dentry); ++ else { ++ struct au_drinfo_do_load_args args = { ++ .drinfop = &drinfo, ++ .h_ppath = &w->h_ppath, ++ .whname = whname, ++ .whnamelen = whnamelen, ++ .info_dentry = &info_dentry ++ }; ++ wkq_err = au_wkq_wait(au_call_drinfo_do_load, &args); ++ if (unlikely(wkq_err)) ++ drinfo = ERR_PTR(wkq_err); ++ } ++ err = PTR_ERR(drinfo); ++ if (IS_ERR_OR_NULL(drinfo)) ++ goto out; ++ ++ err = 0; ++ oldname.len = drinfo->oldnamelen; ++ oldname.name = drinfo->oldname; ++ if (au_qstreq(w->qname, &oldname)) { ++ /* the name is renamed back */ ++ au_kfree_rcu(drinfo); ++ drinfo = NULL; ++ ++ infopath.dentry = info_dentry; ++ infopath.mnt = w->h_ppath.mnt; ++ h_dir = d_inode(w->h_ppath.dentry); ++ delegated = NULL; ++ inode_lock_nested(h_dir, AuLsc_I_PARENT); ++ e = vfsub_unlink(h_dir, &infopath, &delegated, !w->no_sio); ++ inode_unlock(h_dir); ++ if (unlikely(e)) ++ AuIOErr("ignored %d, %pd2\n", e, &infopath.dentry); ++ if (unlikely(e == -EWOULDBLOCK)) ++ iput(delegated); ++ } ++ au_kfree_rcu(w->drinfo[bindex]); ++ w->drinfo[bindex] = drinfo; ++ dput(info_dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_dr_lkup_free(struct au_drinfo **drinfo, int n) ++{ ++ struct au_drinfo **p = drinfo; ++ ++ while (n-- > 0) ++ au_kfree_rcu(*drinfo++); ++ au_kfree_try_rcu(p); ++} ++ ++int au_dr_lkup(struct au_do_lookup_args *lkup, struct dentry *dentry, ++ aufs_bindex_t btgt) ++{ ++ int err, ninfo; ++ struct au_drinfo_load w; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ struct inode *h_dir; ++ struct au_dr_hino *ent; ++ struct super_block *sb; ++ ++ AuDbg("%.*s, name %.*s, whname %.*s, b%d\n", ++ AuLNPair(&dentry->d_name), AuLNPair(&lkup->dirren.dr_name), ++ AuLNPair(&lkup->whname), btgt); ++ ++ sb = dentry->d_sb; ++ bbot = au_sbbot(sb); ++ w.ninfo = bbot + 1; ++ if (!lkup->dirren.drinfo) { ++ lkup->dirren.drinfo = kcalloc(w.ninfo, ++ sizeof(*lkup->dirren.drinfo), ++ GFP_NOFS); ++ if (unlikely(!lkup->dirren.drinfo)) { ++ err = -ENOMEM; ++ goto out; ++ } ++ lkup->dirren.ninfo = w.ninfo; ++ } ++ w.drinfo = lkup->dirren.drinfo; ++ w.no_sio = !!uid_eq(current_fsuid(), GLOBAL_ROOT_UID); ++ w.h_ppath.dentry = au_h_dptr(dentry, btgt); ++ AuDebugOn(!w.h_ppath.dentry); ++ w.h_ppath.mnt = au_sbr_mnt(sb, btgt); ++ w.qname = &dentry->d_name; ++ ++ ninfo = 0; ++ for (bindex = btgt + 1; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_drinfo_load(&w, bindex, br); ++ if (unlikely(err)) ++ goto out_free; ++ if (w.drinfo[bindex]) ++ ninfo++; ++ } ++ if (!ninfo) { ++ br = au_sbr(sb, btgt); ++ h_dir = d_inode(w.h_ppath.dentry); ++ ent = au_dr_hino_find(&br->br_dirren, h_dir->i_ino); ++ AuDebugOn(!ent); ++ au_dr_hino_del(&br->br_dirren, ent); ++ au_kfree_rcu(ent); ++ } ++ goto out; /* success */ ++ ++out_free: ++ au_dr_lkup_free(lkup->dirren.drinfo, lkup->dirren.ninfo); ++ lkup->dirren.ninfo = 0; ++ lkup->dirren.drinfo = NULL; ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_dr_lkup_fin(struct au_do_lookup_args *lkup) ++{ ++ au_dr_lkup_free(lkup->dirren.drinfo, lkup->dirren.ninfo); ++} ++ ++int au_dr_lkup_name(struct au_do_lookup_args *lkup, aufs_bindex_t btgt) ++{ ++ int err; ++ struct au_drinfo *drinfo; ++ ++ err = 0; ++ if (!lkup->dirren.drinfo) ++ goto out; ++ AuDebugOn(lkup->dirren.ninfo <= btgt); ++ drinfo = lkup->dirren.drinfo[btgt]; ++ if (!drinfo) ++ goto out; ++ ++ 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; ++ lkup->name = &lkup->dirren.dr_name; ++ err = au_wh_name_alloc(&lkup->whname, lkup->name); ++ if (!err) ++ AuDbg("name %.*s, whname %.*s, b%d\n", ++ AuLNPair(lkup->name), AuLNPair(&lkup->whname), ++ btgt); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_dr_lkup_h_ino(struct au_do_lookup_args *lkup, aufs_bindex_t bindex, ++ ino_t h_ino) ++{ ++ int match; ++ struct au_drinfo *drinfo; ++ ++ match = 1; ++ if (!lkup->dirren.drinfo) ++ goto out; ++ AuDebugOn(lkup->dirren.ninfo <= bindex); ++ drinfo = lkup->dirren.drinfo[bindex]; ++ if (!drinfo) ++ goto out; ++ ++ match = (drinfo->ino == h_ino); ++ AuDbg("match %d\n", match); ++ ++out: ++ return match; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dr_opt_set(struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_dr_hino(sb, bindex, /*br*/NULL, &br->br_path); ++ } ++ ++ return err; ++} ++ ++int au_dr_opt_flush(struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm)) ++ err = au_dr_hino(sb, bindex, /*br*/NULL, /*path*/NULL); ++ } ++ ++ return err; ++} ++ ++int au_dr_opt_clr(struct super_block *sb, int no_flush) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ err = 0; ++ if (!no_flush) { ++ err = au_dr_opt_flush(sb); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ au_dr_hino_free(&br->br_dirren); ++ } ++ ++out: ++ return err; ++} +diff -Naur null/fs/aufs/dirren.h linux-5.15.36/fs/aufs/dirren.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/dirren.h 2022-05-10 16:51:39.869744219 +0300 +@@ -0,0 +1,140 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2017-2021 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 . ++ */ ++ ++/* ++ * renamed dir info ++ */ ++ ++#ifndef __AUFS_DIRREN_H__ ++#define __AUFS_DIRREN_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include "hbl.h" ++ ++#define AuDirren_NHASH 100 ++ ++#ifdef CONFIG_AUFS_DIRREN ++enum au_brid_type { ++ AuBrid_Unset, ++ AuBrid_UUID, ++ AuBrid_FSID, ++ AuBrid_DEV ++}; ++ ++struct au_dr_brid { ++ enum au_brid_type type; ++ union { ++ uuid_t uuid; /* unimplemented yet */ ++ fsid_t fsid; ++ dev_t dev; ++ }; ++}; ++ ++/* 20 is the max digits length of ulong 64 */ ++/* brid-type "_" uuid "_" inum */ ++#define AUFS_DIRREN_FNAME_SZ (1 + 1 + UUID_STRING_LEN + 20) ++#define AUFS_DIRREN_ENV_VAL_SZ (AUFS_DIRREN_FNAME_SZ + 1 + 20) ++ ++struct au_dr_hino { ++ struct hlist_bl_node dr_hnode; ++ ino_t dr_h_ino; ++}; ++ ++struct au_dr_br { ++ struct hlist_bl_head dr_h_ino[AuDirren_NHASH]; ++ struct au_dr_brid dr_brid; ++}; ++ ++struct au_dr_lookup { ++ /* dr_name is pointed by struct au_do_lookup_args.name */ ++ struct qstr dr_name; /* subset of dr_info */ ++ aufs_bindex_t ninfo; ++ struct au_drinfo **drinfo; ++}; ++#else ++struct au_dr_hino; ++/* empty */ ++struct au_dr_br { }; ++struct au_dr_lookup { }; ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_branch; ++struct au_do_lookup_args; ++struct au_hinode; ++#ifdef CONFIG_AUFS_DIRREN ++int au_dr_hino_test_add(struct au_dr_br *dr, ino_t h_ino, ++ struct au_dr_hino *add_ent); ++void au_dr_hino_free(struct au_dr_br *dr); ++int au_dr_br_init(struct super_block *sb, struct au_branch *br, ++ const struct path *path); ++int au_dr_br_fin(struct super_block *sb, struct au_branch *br); ++int au_dr_rename(struct dentry *src, aufs_bindex_t bindex, ++ struct qstr *dst_name, void *_rev); ++void au_dr_rename_fin(struct dentry *src, aufs_bindex_t btgt, void *rev); ++void au_dr_rename_rev(struct dentry *src, aufs_bindex_t bindex, void *rev); ++int au_dr_lkup(struct au_do_lookup_args *lkup, struct dentry *dentry, ++ aufs_bindex_t bindex); ++int au_dr_lkup_name(struct au_do_lookup_args *lkup, aufs_bindex_t btgt); ++int au_dr_lkup_h_ino(struct au_do_lookup_args *lkup, aufs_bindex_t bindex, ++ ino_t h_ino); ++void au_dr_lkup_fin(struct au_do_lookup_args *lkup); ++int au_dr_opt_set(struct super_block *sb); ++int au_dr_opt_flush(struct super_block *sb); ++int au_dr_opt_clr(struct super_block *sb, int no_flush); ++#else ++AuStubInt0(au_dr_hino_test_add, struct au_dr_br *dr, ino_t h_ino, ++ struct au_dr_hino *add_ent); ++AuStubVoid(au_dr_hino_free, struct au_dr_br *dr); ++AuStubInt0(au_dr_br_init, struct super_block *sb, struct au_branch *br, ++ const struct path *path); ++AuStubInt0(au_dr_br_fin, struct super_block *sb, struct au_branch *br); ++AuStubInt0(au_dr_rename, struct dentry *src, aufs_bindex_t bindex, ++ struct qstr *dst_name, void *_rev); ++AuStubVoid(au_dr_rename_fin, struct dentry *src, aufs_bindex_t btgt, void *rev); ++AuStubVoid(au_dr_rename_rev, struct dentry *src, aufs_bindex_t bindex, ++ void *rev); ++AuStubInt0(au_dr_lkup, struct au_do_lookup_args *lkup, struct dentry *dentry, ++ aufs_bindex_t bindex); ++AuStubInt0(au_dr_lkup_name, struct au_do_lookup_args *lkup, aufs_bindex_t btgt); ++AuStubInt0(au_dr_lkup_h_ino, struct au_do_lookup_args *lkup, ++ aufs_bindex_t bindex, ino_t h_ino); ++AuStubVoid(au_dr_lkup_fin, struct au_do_lookup_args *lkup); ++AuStubInt0(au_dr_opt_set, struct super_block *sb); ++AuStubInt0(au_dr_opt_flush, struct super_block *sb); ++AuStubInt0(au_dr_opt_clr, struct super_block *sb, int no_flush); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DIRREN ++static inline int au_dr_ihash(ino_t h_ino) ++{ ++ return h_ino % AuDirren_NHASH; ++} ++#else ++AuStubInt0(au_dr_ihash, ino_t h_ino); ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DIRREN_H__ */ +diff -Naur null/fs/aufs/dynop.c linux-5.15.36/fs/aufs/dynop.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/dynop.c 2022-05-10 16:51:39.869744219 +0300 +@@ -0,0 +1,368 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2021 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 . ++ */ ++ ++/* ++ * dynamically customizable operations for regular files ++ */ ++ ++#include "aufs.h" ++ ++#define DyPrSym(key) AuDbgSym(key->dk_op.dy_hop) ++ ++/* ++ * How large will these lists be? ++ * Usually just a few elements, 20-30 at most for each, I guess. ++ */ ++static struct hlist_bl_head dynop[AuDyLast]; ++ ++static struct au_dykey *dy_gfind_get(struct hlist_bl_head *hbl, ++ const void *h_op) ++{ ++ struct au_dykey *key, *tmp; ++ struct hlist_bl_node *pos; ++ ++ key = NULL; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(tmp, pos, hbl, dk_hnode) ++ if (tmp->dk_op.dy_hop == h_op) { ++ if (kref_get_unless_zero(&tmp->dk_kref)) ++ key = tmp; ++ break; ++ } ++ hlist_bl_unlock(hbl); ++ ++ return key; ++} ++ ++static struct au_dykey *dy_bradd(struct au_branch *br, struct au_dykey *key) ++{ ++ struct au_dykey **k, *found; ++ const void *h_op = key->dk_op.dy_hop; ++ int i; ++ ++ found = NULL; ++ k = br->br_dykey; ++ for (i = 0; i < AuBrDynOp; i++) ++ if (k[i]) { ++ if (k[i]->dk_op.dy_hop == h_op) { ++ found = k[i]; ++ break; ++ } ++ } else ++ break; ++ if (!found) { ++ spin_lock(&br->br_dykey_lock); ++ for (; i < AuBrDynOp; i++) ++ if (k[i]) { ++ if (k[i]->dk_op.dy_hop == h_op) { ++ found = k[i]; ++ break; ++ } ++ } else { ++ k[i] = key; ++ break; ++ } ++ spin_unlock(&br->br_dykey_lock); ++ BUG_ON(i == AuBrDynOp); /* expand the array */ ++ } ++ ++ return found; ++} ++ ++/* kref_get() if @key is already added */ ++static struct au_dykey *dy_gadd(struct hlist_bl_head *hbl, struct au_dykey *key) ++{ ++ struct au_dykey *tmp, *found; ++ struct hlist_bl_node *pos; ++ const void *h_op = key->dk_op.dy_hop; ++ ++ found = NULL; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(tmp, pos, hbl, dk_hnode) ++ if (tmp->dk_op.dy_hop == h_op) { ++ if (kref_get_unless_zero(&tmp->dk_kref)) ++ found = tmp; ++ break; ++ } ++ if (!found) ++ hlist_bl_add_head(&key->dk_hnode, hbl); ++ hlist_bl_unlock(hbl); ++ ++ if (!found) ++ DyPrSym(key); ++ return found; ++} ++ ++static void dy_free_rcu(struct rcu_head *rcu) ++{ ++ struct au_dykey *key; ++ ++ key = container_of(rcu, struct au_dykey, dk_rcu); ++ DyPrSym(key); ++ kfree(key); ++} ++ ++static void dy_free(struct kref *kref) ++{ ++ struct au_dykey *key; ++ struct hlist_bl_head *hbl; ++ ++ key = container_of(kref, struct au_dykey, dk_kref); ++ hbl = dynop + key->dk_op.dy_type; ++ au_hbl_del(&key->dk_hnode, hbl); ++ call_rcu(&key->dk_rcu, dy_free_rcu); ++} ++ ++void au_dy_put(struct au_dykey *key) ++{ ++ kref_put(&key->dk_kref, dy_free); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define DyDbgSize(cnt, op) AuDebugOn(cnt != sizeof(op)/sizeof(void *)) ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define DyDbgDeclare(cnt) unsigned int cnt = 0 ++#define DyDbgInc(cnt) do { cnt++; } while (0) ++#else ++#define DyDbgDeclare(cnt) do {} while (0) ++#define DyDbgInc(cnt) do {} while (0) ++#endif ++ ++#define DySet(func, dst, src, h_op, h_sb) do { \ ++ DyDbgInc(cnt); \ ++ if (h_op->func) { \ ++ if (src.func) \ ++ dst.func = src.func; \ ++ else \ ++ AuDbg("%s %s\n", au_sbtype(h_sb), #func); \ ++ } \ ++} while (0) ++ ++#define DySetForce(func, dst, src) do { \ ++ AuDebugOn(!src.func); \ ++ DyDbgInc(cnt); \ ++ dst.func = src.func; \ ++} while (0) ++ ++#define DySetAop(func) \ ++ DySet(func, dyaop->da_op, aufs_aop, h_aop, h_sb) ++#define DySetAopForce(func) \ ++ DySetForce(func, dyaop->da_op, aufs_aop) ++ ++static void dy_aop(struct au_dykey *key, const void *h_op, ++ struct super_block *h_sb __maybe_unused) ++{ ++ struct au_dyaop *dyaop = (void *)key; ++ const struct address_space_operations *h_aop = h_op; ++ DyDbgDeclare(cnt); ++ ++ AuDbg("%s\n", au_sbtype(h_sb)); ++ ++ DySetAop(writepage); ++ DySetAopForce(readpage); /* force */ ++ DySetAop(writepages); ++ DySetAop(set_page_dirty); ++ DySetAop(readpages); ++ DySetAop(readahead); ++ DySetAop(write_begin); ++ DySetAop(write_end); ++ DySetAop(bmap); ++ DySetAop(invalidatepage); ++ DySetAop(releasepage); ++ DySetAop(freepage); ++ /* this one will be changed according to an aufs mount option */ ++ DySetAop(direct_IO); ++ DySetAop(migratepage); ++ DySetAop(isolate_page); ++ DySetAop(putback_page); ++ DySetAop(launder_page); ++ DySetAop(is_partially_uptodate); ++ DySetAop(is_dirty_writeback); ++ DySetAop(error_remove_page); ++ DySetAop(swap_activate); ++ DySetAop(swap_deactivate); ++ ++ DyDbgSize(cnt, *h_aop); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void dy_bug(struct kref *kref) ++{ ++ BUG(); ++} ++ ++static struct au_dykey *dy_get(struct au_dynop *op, struct au_branch *br) ++{ ++ struct au_dykey *key, *old; ++ struct hlist_bl_head *hbl; ++ struct op { ++ unsigned int sz; ++ void (*set)(struct au_dykey *key, const void *h_op, ++ struct super_block *h_sb __maybe_unused); ++ }; ++ static const struct op a[] = { ++ [AuDy_AOP] = { ++ .sz = sizeof(struct au_dyaop), ++ .set = dy_aop ++ } ++ }; ++ const struct op *p; ++ ++ hbl = dynop + op->dy_type; ++ key = dy_gfind_get(hbl, op->dy_hop); ++ if (key) ++ goto out_add; /* success */ ++ ++ p = a + op->dy_type; ++ key = kzalloc(p->sz, GFP_NOFS); ++ if (unlikely(!key)) { ++ key = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ key->dk_op.dy_hop = op->dy_hop; ++ kref_init(&key->dk_kref); ++ p->set(key, op->dy_hop, au_br_sb(br)); ++ old = dy_gadd(hbl, key); ++ if (old) { ++ au_kfree_rcu(key); ++ key = old; ++ } ++ ++out_add: ++ old = dy_bradd(br, key); ++ if (old) ++ /* its ref-count should never be zero here */ ++ kref_put(&key->dk_kref, dy_bug); ++out: ++ return key; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * 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. ++ * See the aufs manual in detail. ++ */ ++static void dy_adx(struct au_dyaop *dyaop, int do_dx) ++{ ++ if (!do_dx) ++ dyaop->da_op.direct_IO = NULL; ++ else ++ dyaop->da_op.direct_IO = aufs_aop.direct_IO; ++} ++ ++static struct au_dyaop *dy_aget(struct au_branch *br, ++ const struct address_space_operations *h_aop, ++ int do_dx) ++{ ++ struct au_dyaop *dyaop; ++ struct au_dynop op; ++ ++ op.dy_type = AuDy_AOP; ++ op.dy_haop = h_aop; ++ dyaop = (void *)dy_get(&op, br); ++ if (IS_ERR(dyaop)) ++ goto out; ++ dy_adx(dyaop, do_dx); ++ ++out: ++ return dyaop; ++} ++ ++int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode) ++{ ++ int err, do_dx; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_dyaop *dyaop; ++ ++ AuDebugOn(!S_ISREG(h_inode->i_mode)); ++ IiMustWriteLock(inode); ++ ++ sb = inode->i_sb; ++ br = au_sbr(sb, bindex); ++ do_dx = !!au_opt_test(au_mntflags(sb), DIO); ++ dyaop = dy_aget(br, h_inode->i_mapping->a_ops, do_dx); ++ err = PTR_ERR(dyaop); ++ if (IS_ERR(dyaop)) ++ /* unnecessary to call dy_fput() */ ++ goto out; ++ ++ err = 0; ++ inode->i_mapping->a_ops = &dyaop->da_op; ++ ++out: ++ return err; ++} ++ ++/* ++ * Is it safe to replace a_ops during the inode/file is in operation? ++ * Yes, I hope so. ++ */ ++int au_dy_irefresh(struct inode *inode) ++{ ++ int err; ++ aufs_bindex_t btop; ++ struct inode *h_inode; ++ ++ err = 0; ++ if (S_ISREG(inode->i_mode)) { ++ btop = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, btop); ++ err = au_dy_iaop(inode, btop, h_inode); ++ } ++ return err; ++} ++ ++void au_dy_arefresh(int do_dx) ++{ ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_dykey *key; ++ ++ hbl = dynop + AuDy_AOP; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(key, pos, hbl, dk_hnode) ++ dy_adx((void *)key, do_dx); ++ hlist_bl_unlock(hbl); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void __init au_dy_init(void) ++{ ++ int i; ++ ++ for (i = 0; i < AuDyLast; i++) ++ INIT_HLIST_BL_HEAD(dynop + i); ++} ++ ++void au_dy_fin(void) ++{ ++ int i; ++ ++ for (i = 0; i < AuDyLast; i++) ++ WARN_ON(!hlist_bl_empty(dynop + i)); ++} +diff -Naur null/fs/aufs/dynop.h linux-5.15.36/fs/aufs/dynop.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/dynop.h 2022-05-10 16:51:39.870744219 +0300 +@@ -0,0 +1,77 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2010-2021 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 . ++ */ ++ ++/* ++ * dynamically customizable operations (for regular files only) ++ */ ++ ++#ifndef __AUFS_DYNOP_H__ ++#define __AUFS_DYNOP_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++enum {AuDy_AOP, AuDyLast}; ++ ++struct au_dynop { ++ int dy_type; ++ union { ++ const void *dy_hop; ++ const struct address_space_operations *dy_haop; ++ }; ++}; ++ ++struct au_dykey { ++ union { ++ struct hlist_bl_node dk_hnode; ++ struct rcu_head dk_rcu; ++ }; ++ struct au_dynop dk_op; ++ ++ /* ++ * during I am in the branch local array, kref is gotten. when the ++ * branch is removed, kref is put. ++ */ ++ struct kref dk_kref; ++}; ++ ++/* stop unioning since their sizes are very different from each other */ ++struct au_dyaop { ++ struct au_dykey da_key; ++ struct address_space_operations da_op; /* not const */ ++}; ++/* make sure that 'struct au_dykey *' can be any type */ ++static_assert(!offsetof(struct au_dyaop, da_key)); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dynop.c */ ++struct au_branch; ++void au_dy_put(struct au_dykey *key); ++int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode); ++int au_dy_irefresh(struct inode *inode); ++void au_dy_arefresh(int do_dio); ++ ++void __init au_dy_init(void); ++void au_dy_fin(void); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DYNOP_H__ */ +diff -Naur null/fs/aufs/export.c linux-5.15.36/fs/aufs/export.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/export.c 2022-05-10 16:51:39.870744219 +0300 +@@ -0,0 +1,830 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * export via nfs ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++union conv { ++#ifdef CONFIG_AUFS_INO_T_64 ++ __u32 a[2]; ++#else ++ __u32 a[1]; ++#endif ++ ino_t ino; ++}; ++ ++static ino_t decode_ino(__u32 *a) ++{ ++ union conv u; ++ ++ BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a)); ++ u.a[0] = a[0]; ++#ifdef CONFIG_AUFS_INO_T_64 ++ u.a[1] = a[1]; ++#endif ++ return u.ino; ++} ++ ++static void encode_ino(__u32 *a, ino_t ino) ++{ ++ union conv u; ++ ++ u.ino = ino; ++ a[0] = u.a[0]; ++#ifdef CONFIG_AUFS_INO_T_64 ++ a[1] = u.a[1]; ++#endif ++} ++ ++/* NFS file handle */ ++enum { ++ Fh_br_id, ++ Fh_sigen, ++#ifdef CONFIG_AUFS_INO_T_64 ++ /* support 64bit inode number */ ++ Fh_ino1, ++ Fh_ino2, ++ Fh_dir_ino1, ++ Fh_dir_ino2, ++#else ++ Fh_ino1, ++ Fh_dir_ino1, ++#endif ++ Fh_igen, ++ Fh_h_type, ++ Fh_tail, ++ ++ Fh_ino = Fh_ino1, ++ Fh_dir_ino = Fh_dir_ino1 ++}; ++ ++static int au_test_anon(struct dentry *dentry) ++{ ++ /* note: read d_flags without d_lock */ ++ return !!(dentry->d_flags & DCACHE_DISCONNECTED); ++} ++ ++int au_test_nfsd(void) ++{ ++ int ret; ++ struct task_struct *tsk = current; ++ char comm[sizeof(tsk->comm)]; ++ ++ ret = 0; ++ if (tsk->flags & PF_KTHREAD) { ++ get_task_comm(comm, tsk); ++ ret = !strcmp(comm, "nfsd"); ++ } ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* inode generation external table */ ++ ++void au_xigen_inc(struct inode *inode) ++{ ++ loff_t pos; ++ ssize_t sz; ++ __u32 igen; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ sb = inode->i_sb; ++ AuDebugOn(!au_opt_test(au_mntflags(sb), XINO)); ++ ++ sbinfo = au_sbi(sb); ++ pos = inode->i_ino; ++ pos *= sizeof(igen); ++ igen = inode->i_generation + 1; ++ sz = xino_fwrite(sbinfo->si_xigen, &igen, sizeof(igen), &pos); ++ if (sz == sizeof(igen)) ++ return; /* success */ ++ ++ if (unlikely(sz >= 0)) ++ AuIOErr("xigen error (%zd)\n", sz); ++} ++ ++int au_xigen_new(struct inode *inode) ++{ ++ int err; ++ loff_t pos; ++ ssize_t sz; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ ++ err = 0; ++ /* todo: dirty, at mount time */ ++ if (inode->i_ino == AUFS_ROOT_INO) ++ goto out; ++ sb = inode->i_sb; ++ SiMustAnyLock(sb); ++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) ++ goto out; ++ ++ err = -EFBIG; ++ pos = inode->i_ino; ++ if (unlikely(au_loff_max / sizeof(inode->i_generation) - 1 < pos)) { ++ AuIOErr1("too large i%lld\n", pos); ++ goto out; ++ } ++ pos *= sizeof(inode->i_generation); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ file = sbinfo->si_xigen; ++ BUG_ON(!file); ++ ++ if (vfsub_f_size_read(file) ++ < pos + sizeof(inode->i_generation)) { ++ inode->i_generation = atomic_inc_return(&sbinfo->si_xigen_next); ++ sz = xino_fwrite(file, &inode->i_generation, ++ sizeof(inode->i_generation), &pos); ++ } else ++ sz = xino_fread(file, &inode->i_generation, ++ sizeof(inode->i_generation), &pos); ++ if (sz == sizeof(inode->i_generation)) ++ goto out; /* success */ ++ ++ err = sz; ++ if (unlikely(sz >= 0)) { ++ err = -EIO; ++ AuIOErr("xigen error (%zd)\n", sz); ++ } ++ ++out: ++ return err; ++} ++ ++int au_xigen_set(struct super_block *sb, struct path *path) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ file = au_xino_create2(sb, path, sbinfo->si_xigen); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ err = 0; ++ if (sbinfo->si_xigen) ++ fput(sbinfo->si_xigen); ++ sbinfo->si_xigen = file; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_xigen_clr(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ if (sbinfo->si_xigen) { ++ fput(sbinfo->si_xigen); ++ sbinfo->si_xigen = NULL; ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino, ++ ino_t dir_ino) ++{ ++ struct dentry *dentry, *d; ++ struct inode *inode; ++ unsigned int sigen; ++ ++ dentry = NULL; ++ inode = ilookup(sb, ino); ++ if (!inode) ++ goto out; ++ ++ dentry = ERR_PTR(-ESTALE); ++ sigen = au_sigen(sb); ++ if (unlikely(au_is_bad_inode(inode) ++ || IS_DEADDIR(inode) ++ || sigen != au_iigen(inode, NULL))) ++ goto out_iput; ++ ++ dentry = NULL; ++ if (!dir_ino || S_ISDIR(inode->i_mode)) ++ dentry = d_find_alias(inode); ++ else { ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) { ++ spin_lock(&d->d_lock); ++ if (!au_test_anon(d) ++ && d_inode(d->d_parent)->i_ino == dir_ino) { ++ dentry = dget_dlock(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ spin_unlock(&d->d_lock); ++ } ++ spin_unlock(&inode->i_lock); ++ } ++ if (unlikely(dentry && au_digen_test(dentry, sigen))) { ++ /* need to refresh */ ++ dput(dentry); ++ dentry = NULL; ++ } ++ ++out_iput: ++ iput(inode); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: dirty? */ ++/* if exportfs_decode_fh() passed vfsmount*, we could be happy */ ++ ++struct au_compare_mnt_args { ++ /* input */ ++ struct super_block *sb; ++ ++ /* output */ ++ struct vfsmount *mnt; ++}; ++ ++static int au_compare_mnt(struct vfsmount *mnt, void *arg) ++{ ++ struct au_compare_mnt_args *a = arg; ++ ++ if (mnt->mnt_sb != a->sb) ++ return 0; ++ a->mnt = mntget(mnt); ++ return 1; ++} ++ ++static struct vfsmount *au_mnt_get(struct super_block *sb) ++{ ++ int err; ++ struct path root; ++ struct au_compare_mnt_args args = { ++ .sb = sb ++ }; ++ ++ get_fs_root(current->fs, &root); ++ rcu_read_lock(); ++ err = iterate_mounts(au_compare_mnt, &args, root.mnt); ++ rcu_read_unlock(); ++ path_put(&root); ++ AuDebugOn(!err); ++ AuDebugOn(!args.mnt); ++ return args.mnt; ++} ++ ++struct au_nfsd_si_lock { ++ unsigned int sigen; ++ aufs_bindex_t bindex, br_id; ++ unsigned char force_lock; ++}; ++ ++static int si_nfsd_read_lock(struct super_block *sb, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ ++ si_read_lock(sb, AuLock_FLUSH); ++ ++ /* branch id may be wrapped around */ ++ err = 0; ++ bindex = au_br_index(sb, nsi_lock->br_id); ++ if (bindex >= 0 && nsi_lock->sigen + AUFS_BRANCH_MAX > au_sigen(sb)) ++ goto out; /* success */ ++ ++ err = -ESTALE; ++ bindex = -1; ++ if (!nsi_lock->force_lock) ++ si_read_unlock(sb); ++ ++out: ++ nsi_lock->bindex = bindex; ++ return err; ++} ++ ++struct find_name_by_ino { ++ struct dir_context ctx; ++ int called, found; ++ ino_t ino; ++ char *name; ++ int namelen; ++}; ++ ++static int ++find_name_by_ino(struct dir_context *ctx, const char *name, int namelen, ++ loff_t offset, u64 ino, unsigned int d_type) ++{ ++ struct find_name_by_ino *a = container_of(ctx, struct find_name_by_ino, ++ ctx); ++ ++ a->called++; ++ if (a->ino != ino) ++ return 0; ++ ++ memcpy(a->name, name, namelen); ++ a->namelen = namelen; ++ a->found = 1; ++ return 1; ++} ++ ++static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry, *parent; ++ struct file *file; ++ struct inode *dir; ++ struct find_name_by_ino arg = { ++ .ctx = { ++ .actor = find_name_by_ino ++ } ++ }; ++ int err; ++ ++ parent = path->dentry; ++ if (nsi_lock) ++ si_read_unlock(parent->d_sb); ++ file = vfsub_dentry_open(path, au_dir_roflags); ++ dentry = (void *)file; ++ if (IS_ERR(file)) ++ goto out; ++ ++ dentry = ERR_PTR(-ENOMEM); ++ arg.name = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!arg.name)) ++ goto out_file; ++ arg.ino = ino; ++ arg.found = 0; ++ do { ++ arg.called = 0; ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(file, &arg.ctx); ++ } while (!err && !arg.found && arg.called); ++ dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_name; ++ /* instead of ENOENT */ ++ dentry = ERR_PTR(-ESTALE); ++ if (!arg.found) ++ goto out_name; ++ ++ /* do not call vfsub_lkup_one() */ ++ dir = d_inode(parent); ++ dentry = vfsub_lookup_one_len_unlocked(arg.name, path, arg.namelen); ++ AuTraceErrPtr(dentry); ++ if (IS_ERR(dentry)) ++ goto out_name; ++ AuDebugOn(au_test_anon(dentry)); ++ if (unlikely(d_really_is_negative(dentry))) { ++ dput(dentry); ++ dentry = ERR_PTR(-ENOENT); ++ } ++ ++out_name: ++ free_page((unsigned long)arg.name); ++out_file: ++ fput(file); ++out: ++ if (unlikely(nsi_lock ++ && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0)) ++ if (!IS_ERR(dentry)) { ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++ } ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino, ++ ino_t dir_ino, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry; ++ struct path path; ++ ++ if (dir_ino != AUFS_ROOT_INO) { ++ path.dentry = decode_by_ino(sb, dir_ino, 0); ++ dentry = path.dentry; ++ if (!path.dentry || IS_ERR(path.dentry)) ++ goto out; ++ AuDebugOn(au_test_anon(path.dentry)); ++ } else ++ path.dentry = dget(sb->s_root); ++ ++ path.mnt = au_mnt_get(sb); ++ dentry = au_lkup_by_ino(&path, ino, nsi_lock); ++ path_put(&path); ++ ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int h_acceptable(void *expv, struct dentry *dentry) ++{ ++ return 1; ++} ++ ++static char *au_build_path(struct dentry *h_parent, struct path *h_rootpath, ++ char *buf, int len, struct super_block *sb) ++{ ++ char *p; ++ int n; ++ struct path path; ++ ++ p = d_path(h_rootpath, buf, len); ++ if (IS_ERR(p)) ++ goto out; ++ n = strlen(p); ++ ++ path.mnt = h_rootpath->mnt; ++ path.dentry = h_parent; ++ p = d_path(&path, buf, len); ++ if (IS_ERR(p)) ++ goto out; ++ if (n != 1) ++ p += n; ++ ++ path.mnt = au_mnt_get(sb); ++ path.dentry = sb->s_root; ++ p = d_path(&path, buf, len - strlen(p)); ++ mntput(path.mnt); ++ if (IS_ERR(p)) ++ goto out; ++ if (n != 1) ++ p[strlen(p)] = '/'; ++ ++out: ++ AuTraceErrPtr(p); ++ return p; ++} ++ ++static ++struct dentry *decode_by_path(struct super_block *sb, ino_t ino, __u32 *fh, ++ int fh_len, struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry, *h_parent, *root; ++ struct super_block *h_sb; ++ char *pathname, *p; ++ struct vfsmount *h_mnt; ++ struct au_branch *br; ++ int err; ++ struct path path; ++ ++ br = au_sbr(sb, nsi_lock->bindex); ++ h_mnt = au_br_mnt(br); ++ h_sb = h_mnt->mnt_sb; ++ /* todo: call lower fh_to_dentry()? fh_to_parent()? */ ++ lockdep_off(); ++ h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail), ++ fh_len - Fh_tail, fh[Fh_h_type], ++ h_acceptable, /*context*/NULL); ++ lockdep_on(); ++ dentry = h_parent; ++ if (unlikely(!h_parent || IS_ERR(h_parent))) { ++ AuWarn1("%s decode_fh failed, %ld\n", ++ au_sbtype(h_sb), PTR_ERR(h_parent)); ++ goto out; ++ } ++ dentry = NULL; ++ if (unlikely(au_test_anon(h_parent))) { ++ AuWarn1("%s decode_fh returned a disconnected dentry\n", ++ au_sbtype(h_sb)); ++ goto out_h_parent; ++ } ++ ++ dentry = ERR_PTR(-ENOMEM); ++ pathname = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!pathname)) ++ goto out_h_parent; ++ ++ root = sb->s_root; ++ path.mnt = h_mnt; ++ di_read_lock_parent(root, !AuLock_IR); ++ path.dentry = au_h_dptr(root, nsi_lock->bindex); ++ di_read_unlock(root, !AuLock_IR); ++ p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb); ++ dentry = (void *)p; ++ if (IS_ERR(p)) ++ goto out_pathname; ++ ++ si_read_unlock(sb); ++ err = vfsub_kern_path(p, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); ++ dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_relock; ++ ++ dentry = ERR_PTR(-ENOENT); ++ AuDebugOn(au_test_anon(path.dentry)); ++ if (unlikely(d_really_is_negative(path.dentry))) ++ goto out_path; ++ ++ if (ino != d_inode(path.dentry)->i_ino) ++ dentry = au_lkup_by_ino(&path, ino, /*nsi_lock*/NULL); ++ else ++ dentry = dget(path.dentry); ++ ++out_path: ++ path_put(&path); ++out_relock: ++ if (unlikely(si_nfsd_read_lock(sb, nsi_lock) < 0)) ++ if (!IS_ERR(dentry)) { ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++ } ++out_pathname: ++ free_page((unsigned long)pathname); ++out_h_parent: ++ dput(h_parent); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry * ++aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, ++ int fh_type) ++{ ++ struct dentry *dentry; ++ __u32 *fh = fid->raw; ++ struct au_branch *br; ++ ino_t ino, dir_ino; ++ struct au_nfsd_si_lock nsi_lock = { ++ .force_lock = 0 ++ }; ++ ++ dentry = ERR_PTR(-ESTALE); ++ /* it should never happen, but the file handle is unreliable */ ++ if (unlikely(fh_len < Fh_tail)) ++ goto out; ++ nsi_lock.sigen = fh[Fh_sigen]; ++ nsi_lock.br_id = fh[Fh_br_id]; ++ ++ /* branch id may be wrapped around */ ++ br = NULL; ++ if (unlikely(si_nfsd_read_lock(sb, &nsi_lock))) ++ goto out; ++ nsi_lock.force_lock = 1; ++ ++ /* is this inode still cached? */ ++ ino = decode_ino(fh + Fh_ino); ++ /* it should never happen */ ++ if (unlikely(ino == AUFS_ROOT_INO)) ++ goto out_unlock; ++ ++ dir_ino = decode_ino(fh + Fh_dir_ino); ++ dentry = decode_by_ino(sb, ino, dir_ino); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (dentry) ++ goto accept; ++ ++ /* is the parent dir cached? */ ++ br = au_sbr(sb, nsi_lock.bindex); ++ au_lcnt_inc(&br->br_nfiles); ++ dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (dentry) ++ goto accept; ++ ++ /* lookup path */ ++ dentry = decode_by_path(sb, ino, fh, fh_len, &nsi_lock); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (unlikely(!dentry)) ++ /* todo?: make it ESTALE */ ++ goto out_unlock; ++ ++accept: ++ if (!au_digen_test(dentry, au_sigen(sb)) ++ && d_inode(dentry)->i_generation == fh[Fh_igen]) ++ goto out_unlock; /* success */ ++ ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++out_unlock: ++ if (br) ++ au_lcnt_dec(&br->br_nfiles); ++ si_read_unlock(sb); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++#if 0 /* reserved for future use */ ++/* support subtreecheck option */ ++static struct dentry *aufs_fh_to_parent(struct super_block *sb, struct fid *fid, ++ int fh_len, int fh_type) ++{ ++ struct dentry *parent; ++ __u32 *fh = fid->raw; ++ ino_t dir_ino; ++ ++ dir_ino = decode_ino(fh + Fh_dir_ino); ++ parent = decode_by_ino(sb, dir_ino, 0); ++ if (IS_ERR(parent)) ++ goto out; ++ if (!parent) ++ parent = decode_by_path(sb, au_br_index(sb, fh[Fh_br_id]), ++ dir_ino, fh, fh_len); ++ ++out: ++ AuTraceErrPtr(parent); ++ return parent; ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_encode_fh(struct inode *inode, __u32 *fh, int *max_len, ++ struct inode *dir) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb, *h_sb; ++ struct dentry *dentry, *parent, *h_parent; ++ struct inode *h_dir; ++ struct au_branch *br; ++ ++ err = -ENOSPC; ++ if (unlikely(*max_len <= Fh_tail)) { ++ AuWarn1("NFSv2 client (max_len %d)?\n", *max_len); ++ goto out; ++ } ++ ++ err = FILEID_ROOT; ++ if (inode->i_ino == AUFS_ROOT_INO) { ++ AuDebugOn(inode->i_ino != AUFS_ROOT_INO); ++ goto out; ++ } ++ ++ h_parent = NULL; ++ sb = inode->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH); ++ if (unlikely(err)) ++ goto out; ++ ++#ifdef CONFIG_AUFS_DEBUG ++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) ++ AuWarn1("NFS-exporting requires xino\n"); ++#endif ++ err = -EIO; ++ parent = NULL; ++ ii_read_lock_child(inode); ++ bindex = au_ibtop(inode); ++ if (!dir) { ++ dentry = d_find_any_alias(inode); ++ if (unlikely(!dentry)) ++ goto out_unlock; ++ AuDebugOn(au_test_anon(dentry)); ++ parent = dget_parent(dentry); ++ dput(dentry); ++ if (unlikely(!parent)) ++ goto out_unlock; ++ if (d_really_is_positive(parent)) ++ dir = d_inode(parent); ++ } ++ ++ ii_read_lock_parent(dir); ++ h_dir = au_h_iptr(dir, bindex); ++ ii_read_unlock(dir); ++ if (unlikely(!h_dir)) ++ goto out_parent; ++ h_parent = d_find_any_alias(h_dir); ++ if (unlikely(!h_parent)) ++ goto out_hparent; ++ ++ err = -EPERM; ++ br = au_sbr(sb, bindex); ++ h_sb = au_br_sb(br); ++ if (unlikely(!h_sb->s_export_op)) { ++ AuErr1("%s branch is not exportable\n", au_sbtype(h_sb)); ++ goto out_hparent; ++ } ++ ++ fh[Fh_br_id] = br->br_id; ++ fh[Fh_sigen] = au_sigen(sb); ++ encode_ino(fh + Fh_ino, inode->i_ino); ++ encode_ino(fh + Fh_dir_ino, dir->i_ino); ++ fh[Fh_igen] = inode->i_generation; ++ ++ *max_len -= Fh_tail; ++ fh[Fh_h_type] = exportfs_encode_fh(h_parent, (void *)(fh + Fh_tail), ++ max_len, ++ /*connectable or subtreecheck*/0); ++ err = fh[Fh_h_type]; ++ *max_len += Fh_tail; ++ /* todo: macros? */ ++ if (err != FILEID_INVALID) ++ err = 99; ++ else ++ AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb)); ++ ++out_hparent: ++ dput(h_parent); ++out_parent: ++ dput(parent); ++out_unlock: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++out: ++ if (unlikely(err < 0)) ++ err = FILEID_INVALID; ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_commit_metadata(struct inode *inode) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct inode *h_inode; ++ int (*f)(struct inode *inode); ++ ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ii_write_lock_child(inode); ++ bindex = au_ibtop(inode); ++ AuDebugOn(bindex < 0); ++ h_inode = au_h_iptr(inode, bindex); ++ ++ f = h_inode->i_sb->s_export_op->commit_metadata; ++ if (f) ++ err = f(h_inode); ++ else ++ err = sync_inode_metadata(h_inode, /*wait*/1); ++ ++ au_cpup_attr_timesizes(inode); ++ ii_write_unlock(inode); ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct export_operations aufs_export_op = { ++ .fh_to_dentry = aufs_fh_to_dentry, ++ /* .fh_to_parent = aufs_fh_to_parent, */ ++ .encode_fh = aufs_encode_fh, ++ .commit_metadata = aufs_commit_metadata ++}; ++ ++void au_export_init(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ __u32 u; ++ ++ BUILD_BUG_ON_MSG(IS_BUILTIN(CONFIG_AUFS_FS) ++ && IS_MODULE(CONFIG_EXPORTFS), ++ AUFS_NAME ": unsupported configuration " ++ "CONFIG_EXPORTFS=m and CONFIG_AUFS_FS=y"); ++ ++ sb->s_export_op = &aufs_export_op; ++ sbinfo = au_sbi(sb); ++ sbinfo->si_xigen = NULL; ++ get_random_bytes(&u, sizeof(u)); ++ BUILD_BUG_ON(sizeof(u) != sizeof(int)); ++ atomic_set(&sbinfo->si_xigen_next, u); ++} +diff -Naur null/fs/aufs/fhsm.c linux-5.15.36/fs/aufs/fhsm.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/fhsm.c 2022-05-10 16:51:39.870744219 +0300 +@@ -0,0 +1,427 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2011-2021 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, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * File-based Hierarchy Storage Management ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++static aufs_bindex_t au_fhsm_bottom(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ AuDebugOn(!fhsm); ++ return fhsm->fhsm_bottom; ++} ++ ++void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ AuDebugOn(!fhsm); ++ fhsm->fhsm_bottom = bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_fhsm_test_jiffy(struct au_sbinfo *sbinfo, struct au_branch *br) ++{ ++ struct au_br_fhsm *bf; ++ ++ bf = br->br_fhsm; ++ MtxMustLock(&bf->bf_lock); ++ ++ return !bf->bf_readable ++ || time_after(jiffies, ++ bf->bf_jiffy + sbinfo->si_fhsm.fhsm_expire); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_fhsm_notify(struct super_block *sb, int val) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ if (au_fhsm_pid(fhsm) ++ && atomic_read(&fhsm->fhsm_readable) != -1) { ++ atomic_set(&fhsm->fhsm_readable, val); ++ if (val) ++ wake_up(&fhsm->fhsm_wqh); ++ } ++} ++ ++static int au_fhsm_stfs(struct super_block *sb, aufs_bindex_t bindex, ++ struct aufs_stfs *rstfs, int do_lock, int do_notify) ++{ ++ int err; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(au_br_rdonly(br)); ++ bf = br->br_fhsm; ++ AuDebugOn(!bf); ++ ++ if (do_lock) ++ mutex_lock(&bf->bf_lock); ++ else ++ MtxMustLock(&bf->bf_lock); ++ ++ /* sb->s_root for NFS is unreliable */ ++ err = au_br_stfs(br, &bf->bf_stfs); ++ if (unlikely(err)) { ++ AuErr1("FHSM failed (%d), b%d, ignored.\n", bindex, err); ++ goto out; ++ } ++ ++ bf->bf_jiffy = jiffies; ++ bf->bf_readable = 1; ++ if (do_notify) ++ au_fhsm_notify(sb, /*val*/1); ++ if (rstfs) ++ *rstfs = bf->bf_stfs; ++ ++out: ++ if (do_lock) ++ mutex_unlock(&bf->bf_lock); ++ au_fhsm_notify(sb, /*val*/1); ++ ++ return err; ++} ++ ++void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ AuDbg("b%d, force %d\n", bindex, force); ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ if (!au_ftest_si(sbinfo, FHSM) ++ || fhsm->fhsm_bottom == bindex) ++ return; ++ ++ br = au_sbr(sb, bindex); ++ bf = br->br_fhsm; ++ AuDebugOn(!bf); ++ mutex_lock(&bf->bf_lock); ++ if (force ++ || au_fhsm_pid(fhsm) ++ || au_fhsm_test_jiffy(sbinfo, br)) ++ err = au_fhsm_stfs(sb, bindex, /*rstfs*/NULL, /*do_lock*/0, ++ /*do_notify*/1); ++ mutex_unlock(&bf->bf_lock); ++} ++ ++void au_fhsm_wrote_all(struct super_block *sb, int force) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ /* exclude the bottom */ ++ bbot = au_fhsm_bottom(sb); ++ for (bindex = 0; bindex < bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) ++ au_fhsm_wrote(sb, bindex, force); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static __poll_t au_fhsm_poll(struct file *file, struct poll_table_struct *wait) ++{ ++ __poll_t mask; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ mask = 0; ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++ poll_wait(file, &fhsm->fhsm_wqh, wait); ++ if (atomic_read(&fhsm->fhsm_readable)) ++ mask = EPOLLIN /* | EPOLLRDNORM */; ++ ++ if (!mask) ++ AuDbg("mask 0x%x\n", mask); ++ return mask; ++} ++ ++static int au_fhsm_do_read_one(struct aufs_stbr __user *stbr, ++ struct aufs_stfs *stfs, __s16 brid) ++{ ++ int err; ++ ++ err = copy_to_user(&stbr->stfs, stfs, sizeof(*stfs)); ++ if (!err) ++ err = __put_user(brid, &stbr->brid); ++ if (unlikely(err)) ++ err = -EFAULT; ++ ++ return err; ++} ++ ++static ssize_t au_fhsm_do_read(struct super_block *sb, ++ struct aufs_stbr __user *stbr, size_t count) ++{ ++ ssize_t err; ++ int nstbr; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ /* except the bottom branch */ ++ err = 0; ++ nstbr = 0; ++ bbot = au_fhsm_bottom(sb); ++ for (bindex = 0; !err && bindex < bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_fhsm(br->br_perm)) ++ continue; ++ ++ bf = br->br_fhsm; ++ mutex_lock(&bf->bf_lock); ++ if (bf->bf_readable) { ++ err = -EFAULT; ++ if (count >= sizeof(*stbr)) ++ err = au_fhsm_do_read_one(stbr++, &bf->bf_stfs, ++ br->br_id); ++ if (!err) { ++ bf->bf_readable = 0; ++ count -= sizeof(*stbr); ++ nstbr++; ++ } ++ } ++ mutex_unlock(&bf->bf_lock); ++ } ++ if (!err) ++ err = sizeof(*stbr) * nstbr; ++ ++ return err; ++} ++ ++static ssize_t au_fhsm_read(struct file *file, char __user *buf, size_t count, ++ loff_t *pos) ++{ ++ ssize_t err; ++ int readable; ++ aufs_bindex_t nfhsm, bindex, bbot; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ struct au_branch *br; ++ struct super_block *sb; ++ ++ err = 0; ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++need_data: ++ spin_lock_irq(&fhsm->fhsm_wqh.lock); ++ if (!atomic_read(&fhsm->fhsm_readable)) { ++ if (vfsub_file_flags(file) & O_NONBLOCK) ++ err = -EAGAIN; ++ else ++ err = wait_event_interruptible_locked_irq ++ (fhsm->fhsm_wqh, ++ atomic_read(&fhsm->fhsm_readable)); ++ } ++ spin_unlock_irq(&fhsm->fhsm_wqh.lock); ++ if (unlikely(err)) ++ goto out; ++ ++ /* sb may already be dead */ ++ au_rw_read_lock(&sbinfo->si_rwsem); ++ readable = atomic_read(&fhsm->fhsm_readable); ++ if (readable > 0) { ++ sb = sbinfo->si_sb; ++ AuDebugOn(!sb); ++ /* exclude the bottom branch */ ++ nfhsm = 0; ++ bbot = au_fhsm_bottom(sb); ++ for (bindex = 0; bindex < bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) ++ nfhsm++; ++ } ++ err = -EMSGSIZE; ++ if (nfhsm * sizeof(struct aufs_stbr) <= count) { ++ atomic_set(&fhsm->fhsm_readable, 0); ++ err = au_fhsm_do_read(sbinfo->si_sb, (void __user *)buf, ++ count); ++ } ++ } ++ au_rw_read_unlock(&sbinfo->si_rwsem); ++ if (!readable) ++ goto need_data; ++ ++out: ++ return err; ++} ++ ++static int au_fhsm_release(struct inode *inode, struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ /* sb may already be dead */ ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock(&fhsm->fhsm_spin); ++ fhsm->fhsm_pid = 0; ++ spin_unlock(&fhsm->fhsm_spin); ++ kobject_put(&sbinfo->si_kobj); ++ ++ return 0; ++} ++ ++static const struct file_operations au_fhsm_fops = { ++ .owner = THIS_MODULE, ++ .llseek = noop_llseek, ++ .read = au_fhsm_read, ++ .poll = au_fhsm_poll, ++ .release = au_fhsm_release ++}; ++ ++int au_fhsm_fd(struct super_block *sb, int oflags) ++{ ++ int err, fd; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(oflags & ~(O_CLOEXEC | O_NONBLOCK))) ++ goto out; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock(&fhsm->fhsm_spin); ++ if (!fhsm->fhsm_pid) ++ fhsm->fhsm_pid = current->pid; ++ else ++ err = -EBUSY; ++ spin_unlock(&fhsm->fhsm_spin); ++ if (unlikely(err)) ++ goto out; ++ ++ oflags |= O_RDONLY; ++ /* oflags |= FMODE_NONOTIFY; */ ++ fd = anon_inode_getfd("[aufs_fhsm]", &au_fhsm_fops, sbinfo, oflags); ++ err = fd; ++ if (unlikely(fd < 0)) ++ goto out_pid; ++ ++ /* succeed regardless 'fhsm' status */ ++ kobject_get(&sbinfo->si_kobj); ++ si_noflush_read_lock(sb); ++ if (au_ftest_si(sbinfo, FHSM)) ++ au_fhsm_wrote_all(sb, /*force*/0); ++ si_read_unlock(sb); ++ goto out; /* success */ ++ ++out_pid: ++ spin_lock(&fhsm->fhsm_spin); ++ fhsm->fhsm_pid = 0; ++ spin_unlock(&fhsm->fhsm_spin); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_fhsm_br_alloc(struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ br->br_fhsm = kmalloc(sizeof(*br->br_fhsm), GFP_NOFS); ++ if (br->br_fhsm) ++ au_br_fhsm_init(br->br_fhsm); ++ else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_fhsm_fin(struct super_block *sb) ++{ ++ au_fhsm_notify(sb, /*val*/-1); ++} ++ ++void au_fhsm_init(struct au_sbinfo *sbinfo) ++{ ++ struct au_fhsm *fhsm; ++ ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock_init(&fhsm->fhsm_spin); ++ init_waitqueue_head(&fhsm->fhsm_wqh); ++ atomic_set(&fhsm->fhsm_readable, 0); ++ fhsm->fhsm_expire ++ = msecs_to_jiffies(AUFS_FHSM_CACHE_DEF_SEC * MSEC_PER_SEC); ++ fhsm->fhsm_bottom = -1; ++} ++ ++void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec) ++{ ++ sbinfo->si_fhsm.fhsm_expire ++ = msecs_to_jiffies(sec * MSEC_PER_SEC); ++} ++ ++void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo) ++{ ++ unsigned int u; ++ ++ if (!au_ftest_si(sbinfo, FHSM)) ++ return; ++ ++ u = jiffies_to_msecs(sbinfo->si_fhsm.fhsm_expire) / MSEC_PER_SEC; ++ if (u != AUFS_FHSM_CACHE_DEF_SEC) ++ seq_printf(seq, ",fhsm_sec=%u", u); ++} +diff -Naur null/fs/aufs/file.c linux-5.15.36/fs/aufs/file.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/file.c 2022-05-10 16:51:39.870744219 +0300 +@@ -0,0 +1,863 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * handling file/dir, and address_space operation ++ */ ++ ++#ifdef CONFIG_AUFS_DEBUG ++#include ++#endif ++#include ++#include "aufs.h" ++ ++/* drop flags for writing */ ++unsigned int au_file_roflags(unsigned int flags) ++{ ++ flags &= ~(O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC); ++ flags |= O_RDONLY | O_NOATIME; ++ return flags; ++} ++ ++/* common functions to regular file and dir */ ++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, ++ struct file *file, int force_wr) ++{ ++ struct file *h_file; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct path h_path; ++ int err; ++ ++ /* a race condition can happen between open and unlink/rmdir */ ++ h_file = ERR_PTR(-ENOENT); ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (au_test_nfsd() && (!h_dentry || d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ spin_lock(&h_dentry->d_lock); ++ err = (!d_unhashed(dentry) && d_unlinked(h_dentry)) ++ /* || !d_inode(dentry)->i_nlink */ ++ ; ++ spin_unlock(&h_dentry->d_lock); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bindex); ++ err = au_br_test_oflag(flags, br); ++ h_file = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ /* drop flags for writing */ ++ if (au_test_ro(sb, bindex, d_inode(dentry))) { ++ if (force_wr && !(flags & O_WRONLY)) ++ force_wr = 0; ++ flags = au_file_roflags(flags); ++ if (force_wr) { ++ h_file = ERR_PTR(-EROFS); ++ flags = au_file_roflags(flags); ++ if (unlikely(vfsub_native_ro(h_inode) ++ || IS_APPEND(h_inode))) ++ goto out; ++ flags &= ~O_ACCMODE; ++ flags |= O_WRONLY; ++ } ++ } ++ flags &= ~O_CREAT; ++ 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); ++ if (IS_ERR(h_file)) ++ goto out_br; ++ ++ if (flags & __FMODE_EXEC) { ++ err = deny_write_access(h_file); ++ if (unlikely(err)) { ++ fput(h_file); ++ h_file = ERR_PTR(err); ++ goto out_br; ++ } ++ } ++ fsnotify_open(h_file); ++ goto out; /* success */ ++ ++out_br: ++ au_lcnt_dec(&br->br_nfiles); ++out: ++ return h_file; ++} ++ ++static int au_cmoo(struct dentry *dentry) ++{ ++ int err, cmoo, matched; ++ unsigned int udba; ++ struct path h_path; ++ struct au_pin pin; ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ struct inode *delegated; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ pid_t pid; ++ struct au_branch *br; ++ struct dentry *parent; ++ struct au_hinode *hdir; ++ ++ DiMustWriteLock(dentry); ++ IiMustWriteLock(d_inode(dentry)); ++ ++ err = 0; ++ if (IS_ROOT(dentry)) ++ goto out; ++ cpg.bsrc = au_dbtop(dentry); ++ if (!cpg.bsrc) ++ goto out; ++ ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ pid = au_fhsm_pid(fhsm); ++ rcu_read_lock(); ++ matched = (pid ++ && (current->pid == pid ++ || rcu_dereference(current->real_parent)->pid == pid)); ++ rcu_read_unlock(); ++ if (matched) ++ goto out; ++ ++ br = au_sbr(sb, cpg.bsrc); ++ cmoo = au_br_cmoo(br->br_perm); ++ if (!cmoo) ++ goto out; ++ if (!d_is_reg(dentry)) ++ cmoo &= AuBrAttr_COO_ALL; ++ if (!cmoo) ++ goto out; ++ ++ parent = dget_parent(dentry); ++ di_write_lock_parent(parent); ++ err = au_wbr_do_copyup_bu(dentry, cpg.bsrc - 1); ++ cpg.bdst = err; ++ if (unlikely(err < 0)) { ++ err = 0; /* there is no upper writable branch */ ++ goto out_dgrade; ++ } ++ AuDbg("bsrc %d, bdst %d\n", cpg.bsrc, cpg.bdst); ++ ++ /* do not respect the coo attrib for the target branch */ ++ err = au_cpup_dirs(dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_dgrade; ++ ++ di_downgrade_lock(parent, AuLock_IR); ++ udba = au_opt_udba(sb); ++ err = au_pin(&pin, dentry, cpg.bdst, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ if (unlikely(err)) ++ goto out_parent; ++ if (!(cmoo & AuBrWAttr_MOO)) ++ goto out_parent; /* success */ ++ ++ err = au_pin(&pin, dentry, cpg.bsrc, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ h_path.mnt = au_br_mnt(br); ++ h_path.dentry = au_h_dptr(dentry, cpg.bsrc); ++ hdir = au_hi(d_inode(parent), cpg.bsrc); ++ delegated = NULL; ++ err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, /*force*/1); ++ au_unpin(&pin); ++ /* todo: keep h_dentry or not? */ ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) { ++ pr_err("unlink %pd after coo failed (%d), ignored\n", ++ dentry, err); ++ err = 0; ++ } ++ goto out_parent; /* success */ ++ ++out_dgrade: ++ di_downgrade_lock(parent, AuLock_IR); ++out_parent: ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_do_open(struct file *file, struct au_do_open_args *args) ++{ ++ int err, aopen = args->aopen; ++ struct dentry *dentry; ++ struct au_finfo *finfo; ++ ++ if (!aopen) ++ err = au_finfo_init(file, args->fidir); ++ else { ++ lockdep_off(); ++ err = au_finfo_init(file, args->fidir); ++ lockdep_on(); ++ } ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_path.dentry; ++ AuDebugOn(IS_ERR_OR_NULL(dentry)); ++ di_write_lock_child(dentry); ++ err = au_cmoo(dentry); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (!err) { ++ if (!aopen) ++ err = args->open(file, vfsub_file_flags(file), NULL); ++ else { ++ lockdep_off(); ++ err = args->open(file, vfsub_file_flags(file), ++ args->h_file); ++ lockdep_on(); ++ } ++ } ++ di_read_unlock(dentry, AuLock_IR); ++ ++ finfo = au_fi(file); ++ if (!err) { ++ finfo->fi_file = file; ++ au_hbl_add(&finfo->fi_hlist, ++ &au_sbi(file->f_path.dentry->d_sb)->si_files); ++ } ++ if (!aopen) ++ fi_write_unlock(file); ++ else { ++ lockdep_off(); ++ fi_write_unlock(file); ++ lockdep_on(); ++ } ++ if (unlikely(err)) { ++ finfo->fi_hdir = NULL; ++ au_finfo_fin(file); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_reopen_nondir(struct file *file) ++{ ++ 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); ++ if (file->f_mode == h_file->f_mode) ++ 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); ++ /* ++ * it can happen ++ * file exists on both of rw and ro ++ * open --> dbtop and fbtop are both 0 ++ * prepend a branch as rw, "rw" become ro ++ * remove rw/file ++ * delete the top branch, "rw" becomes rw again ++ * --> dbtop is 1, fbtop is still 0 ++ * write --> fbtop is 0 but dbtop is 1 ++ */ ++ /* AuDebugOn(au_fbtop(file) < btop); */ ++ ++ h_file = au_h_open(dentry, btop, vfsub_file_flags(file) & ~O_TRUNC, ++ file, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) { ++ if (h_file_tmp) { ++ /* revert */ ++ au_set_h_fptr(file, btop, h_file_tmp); ++ h_file_tmp = NULL; ++ } ++ goto out; /* todo: close all? */ ++ } ++ ++ err = 0; ++ au_set_fbtop(file, btop); ++ au_set_h_fptr(file, btop, h_file); ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ ++out: ++ if (h_file_tmp) { ++ fput(h_file_tmp); ++ au_lcnt_dec(&br->br_nfiles); ++ } ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_reopen_wh(struct file *file, aufs_bindex_t btgt, ++ struct dentry *hi_wh) ++{ ++ int err; ++ aufs_bindex_t btop; ++ struct au_dinfo *dinfo; ++ struct dentry *h_dentry; ++ struct au_hdentry *hdp; ++ ++ dinfo = au_di(file->f_path.dentry); ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ btop = dinfo->di_btop; ++ dinfo->di_btop = btgt; ++ hdp = au_hdentry(dinfo, btgt); ++ h_dentry = hdp->hd_dentry; ++ hdp->hd_dentry = hi_wh; ++ err = au_reopen_nondir(file); ++ hdp->hd_dentry = h_dentry; ++ dinfo->di_btop = btop; ++ ++ return err; ++} ++ ++static int au_ready_to_write_wh(struct file *file, loff_t len, ++ aufs_bindex_t bcpup, struct au_pin *pin) ++{ ++ int err; ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry, *hi_wh; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_path.dentry, ++ .bdst = bcpup, ++ .bsrc = -1, ++ .len = len, ++ .pin = pin ++ }; ++ ++ au_update_dbtop(cpg.dentry); ++ inode = d_inode(cpg.dentry); ++ h_inode = NULL; ++ if (au_dbtop(cpg.dentry) <= bcpup ++ && au_dbbot(cpg.dentry) >= bcpup) { ++ h_dentry = au_h_dptr(cpg.dentry, bcpup); ++ if (h_dentry && d_is_positive(h_dentry)) ++ h_inode = d_inode(h_dentry); ++ } ++ hi_wh = au_hi_wh(inode, bcpup); ++ if (!hi_wh && !h_inode) ++ err = au_sio_cpup_wh(&cpg, file); ++ else ++ /* already copied-up after unlink */ ++ err = au_reopen_wh(file, bcpup, hi_wh); ++ ++ if (!err ++ && (inode->i_nlink > 1 ++ || (inode->i_state & I_LINKABLE)) ++ && au_opt_test(au_mntflags(cpg.dentry->d_sb), PLINK)) ++ au_plink_append(inode, bcpup, au_h_dptr(cpg.dentry, bcpup)); ++ ++ return err; ++} ++ ++/* ++ * prepare the @file for writing. ++ */ ++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin) ++{ ++ int err; ++ aufs_bindex_t dbtop; ++ struct dentry *parent; ++ struct inode *inode; ++ struct super_block *sb; ++ struct file *h_file; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_path.dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = len, ++ .pin = pin, ++ .flags = AuCpup_DTIME ++ }; ++ ++ sb = cpg.dentry->d_sb; ++ inode = d_inode(cpg.dentry); ++ cpg.bsrc = au_fbtop(file); ++ err = au_test_ro(sb, cpg.bsrc, inode); ++ if (!err && (au_hf_top(file)->f_mode & FMODE_WRITE)) { ++ err = au_pin(pin, cpg.dentry, cpg.bsrc, AuOpt_UDBA_NONE, ++ /*flags*/0); ++ goto out; ++ } ++ ++ /* need to cpup or reopen */ ++ parent = dget_parent(cpg.dentry); ++ di_write_lock_parent(parent); ++ err = AuWbrCopyup(au_sbi(sb), cpg.dentry); ++ cpg.bdst = err; ++ if (unlikely(err < 0)) ++ goto out_dgrade; ++ err = 0; ++ ++ if (!d_unhashed(cpg.dentry) && !au_h_dptr(parent, cpg.bdst)) { ++ err = au_cpup_dirs(cpg.dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_dgrade; ++ } ++ ++ err = au_pin(pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_dgrade; ++ ++ dbtop = au_dbtop(cpg.dentry); ++ if (dbtop <= cpg.bdst) ++ cpg.bsrc = cpg.bdst; ++ ++ if (dbtop <= cpg.bdst /* just reopen */ ++ || !d_unhashed(cpg.dentry) /* copyup and reopen */ ++ ) { ++ h_file = au_h_open_pre(cpg.dentry, cpg.bsrc, /*force_wr*/0); ++ if (IS_ERR(h_file)) ++ err = PTR_ERR(h_file); ++ else { ++ di_downgrade_lock(parent, AuLock_IR); ++ if (dbtop > cpg.bdst) ++ err = au_sio_cpup_simple(&cpg); ++ if (!err) ++ err = au_reopen_nondir(file); ++ au_h_open_post(cpg.dentry, cpg.bsrc, h_file); ++ } ++ } else { /* copyup as wh and reopen */ ++ /* ++ * since writable hfsplus branch is not supported, ++ * h_open_pre/post() are unnecessary. ++ */ ++ err = au_ready_to_write_wh(file, len, cpg.bdst, pin); ++ di_downgrade_lock(parent, AuLock_IR); ++ } ++ ++ if (!err) { ++ au_pin_set_parent_lflag(pin, /*lflag*/0); ++ goto out_dput; /* success */ ++ } ++ au_unpin(pin); ++ goto out_unlock; ++ ++out_dgrade: ++ di_downgrade_lock(parent, AuLock_IR); ++out_unlock: ++ di_read_unlock(parent, AuLock_IR); ++out_dput: ++ dput(parent); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_do_flush(struct file *file, fl_owner_t id, ++ int (*flush)(struct file *file, fl_owner_t id)) ++{ ++ int err; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_noflush_read_lock(sb); ++ fi_read_lock(file); ++ ii_read_lock_child(inode); ++ ++ err = flush(file, id); ++ au_cpup_attr_timesizes(inode); ++ ++ ii_read_unlock(inode); ++ fi_read_unlock(file); ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_file_refresh_by_inode(struct file *file, int *need_reopen) ++{ ++ int err; ++ struct au_pin pin; ++ struct au_finfo *finfo; ++ struct dentry *parent, *hi_wh; ++ struct inode *inode; ++ struct super_block *sb; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_path.dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME ++ }; ++ ++ FiMustWriteLock(file); ++ ++ err = 0; ++ finfo = au_fi(file); ++ sb = cpg.dentry->d_sb; ++ inode = d_inode(cpg.dentry); ++ cpg.bdst = au_ibtop(inode); ++ if (cpg.bdst == finfo->fi_btop || IS_ROOT(cpg.dentry)) ++ goto out; ++ ++ parent = dget_parent(cpg.dentry); ++ if (au_test_ro(sb, cpg.bdst, inode)) { ++ di_read_lock_parent(parent, !AuLock_IR); ++ err = AuWbrCopyup(au_sbi(sb), cpg.dentry); ++ cpg.bdst = err; ++ di_read_unlock(parent, !AuLock_IR); ++ if (unlikely(err < 0)) ++ goto out_parent; ++ err = 0; ++ } ++ ++ di_read_lock_parent(parent, AuLock_IR); ++ hi_wh = au_hi_wh(inode, cpg.bdst); ++ if (!S_ISDIR(inode->i_mode) ++ && au_opt_test(au_mntflags(sb), PLINK) ++ && au_plink_test(inode) ++ && !d_unhashed(cpg.dentry) ++ && cpg.bdst < au_dbtop(cpg.dentry)) { ++ err = au_test_and_cpup_dirs(cpg.dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ /* always superio. */ ++ err = au_pin(&pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ } else if (hi_wh) { ++ /* already copied-up after unlink */ ++ err = au_reopen_wh(file, cpg.bdst, hi_wh); ++ *need_reopen = 0; ++ } ++ ++out_unlock: ++ di_read_unlock(parent, AuLock_IR); ++out_parent: ++ dput(parent); ++out: ++ return err; ++} ++ ++static void au_do_refresh_dir(struct file *file) ++{ ++ aufs_bindex_t bindex, bbot, new_bindex, brid; ++ struct au_hfile *p, tmp, *q; ++ struct au_finfo *finfo; ++ struct super_block *sb; ++ struct au_fidir *fidir; ++ ++ FiMustWriteLock(file); ++ ++ sb = file->f_path.dentry->d_sb; ++ finfo = au_fi(file); ++ fidir = finfo->fi_hdir; ++ AuDebugOn(!fidir); ++ p = fidir->fd_hfile + finfo->fi_btop; ++ brid = p->hf_br->br_id; ++ bbot = fidir->fd_bbot; ++ for (bindex = finfo->fi_btop; bindex <= bbot; bindex++, p++) { ++ if (!p->hf_file) ++ continue; ++ ++ new_bindex = au_br_index(sb, p->hf_br->br_id); ++ if (new_bindex == bindex) ++ continue; ++ if (new_bindex < 0) { ++ au_set_h_fptr(file, bindex, NULL); ++ continue; ++ } ++ ++ /* swap two lower inode, and loop again */ ++ q = fidir->fd_hfile + new_bindex; ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hf_file) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ p = fidir->fd_hfile; ++ if (!au_test_mmapped(file) && !d_unlinked(file->f_path.dentry)) { ++ bbot = au_sbbot(sb); ++ for (finfo->fi_btop = 0; finfo->fi_btop <= bbot; ++ finfo->fi_btop++, p++) ++ if (p->hf_file) { ++ if (file_inode(p->hf_file)) ++ break; ++ au_hfput(p, /*execed*/0); ++ } ++ } else { ++ bbot = au_br_index(sb, brid); ++ for (finfo->fi_btop = 0; finfo->fi_btop < bbot; ++ finfo->fi_btop++, p++) ++ if (p->hf_file) ++ au_hfput(p, /*execed*/0); ++ bbot = au_sbbot(sb); ++ } ++ ++ p = fidir->fd_hfile + bbot; ++ for (fidir->fd_bbot = bbot; fidir->fd_bbot >= finfo->fi_btop; ++ fidir->fd_bbot--, p--) ++ if (p->hf_file) { ++ if (file_inode(p->hf_file)) ++ break; ++ au_hfput(p, /*execed*/0); ++ } ++ AuDebugOn(fidir->fd_bbot < finfo->fi_btop); ++} ++ ++/* ++ * after branch manipulating, refresh the file. ++ */ ++static int refresh_file(struct file *file, int (*reopen)(struct file *file)) ++{ ++ int err, need_reopen, nbr; ++ aufs_bindex_t bbot, bindex; ++ struct dentry *dentry; ++ struct super_block *sb; ++ struct au_finfo *finfo; ++ struct au_hfile *hfile; ++ ++ dentry = file->f_path.dentry; ++ sb = dentry->d_sb; ++ nbr = au_sbbot(sb) + 1; ++ finfo = au_fi(file); ++ if (!finfo->fi_hdir) { ++ hfile = &finfo->fi_htop; ++ AuDebugOn(!hfile->hf_file); ++ bindex = au_br_index(sb, hfile->hf_br->br_id); ++ AuDebugOn(bindex < 0); ++ if (bindex != finfo->fi_btop) ++ au_set_fbtop(file, bindex); ++ } else { ++ err = au_fidir_realloc(finfo, nbr, /*may_shrink*/0); ++ if (unlikely(err)) ++ goto out; ++ au_do_refresh_dir(file); ++ } ++ ++ err = 0; ++ need_reopen = 1; ++ if (!au_test_mmapped(file)) ++ err = au_file_refresh_by_inode(file, &need_reopen); ++ if (finfo->fi_hdir) ++ /* harmless if err */ ++ au_fidir_realloc(finfo, nbr, /*may_shrink*/1); ++ if (!err && need_reopen && !d_unlinked(dentry)) ++ err = reopen(file); ++ if (!err) { ++ au_update_figen(file); ++ goto out; /* success */ ++ } ++ ++ /* error, close all lower files */ ++ if (finfo->fi_hdir) { ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); bindex <= bbot; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ } ++ ++out: ++ return err; ++} ++ ++/* common function to regular file and dir */ ++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), ++ int wlock, unsigned int fi_lsc) ++{ ++ int err; ++ unsigned int sigen, figen; ++ aufs_bindex_t btop; ++ unsigned char pseudo_link; ++ struct dentry *dentry; ++ struct inode *inode; ++ ++ err = 0; ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ sigen = au_sigen(dentry->d_sb); ++ fi_write_lock_nested(file, fi_lsc); ++ figen = au_figen(file); ++ if (!fi_lsc) ++ di_write_lock_child(dentry); ++ else ++ di_write_lock_child2(dentry); ++ btop = au_dbtop(dentry); ++ pseudo_link = (btop != au_ibtop(inode)); ++ if (sigen == figen && !pseudo_link && au_fbtop(file) == btop) { ++ if (!wlock) { ++ di_downgrade_lock(dentry, AuLock_IR); ++ fi_downgrade_lock(file); ++ } ++ goto out; /* success */ ++ } ++ ++ AuDbg("sigen %d, figen %d\n", sigen, figen); ++ if (au_digen_test(dentry, sigen)) { ++ err = au_reval_dpath(dentry, sigen); ++ AuDebugOn(!err && au_digen_test(dentry, sigen)); ++ } ++ ++ if (!err) ++ err = refresh_file(file, reopen); ++ if (!err) { ++ if (!wlock) { ++ di_downgrade_lock(dentry, AuLock_IR); ++ fi_downgrade_lock(file); ++ } ++ } else { ++ di_write_unlock(dentry); ++ fi_write_unlock(file); ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* cf. aufs_nopage() */ ++/* for madvise(2) */ ++static int aufs_readpage(struct file *file __maybe_unused, struct page *page) ++{ ++ unlock_page(page); ++ return 0; ++} ++ ++/* it will never be called, but necessary to support O_DIRECT */ ++static ssize_t aufs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ++{ BUG(); return 0; } ++ ++/* they will never be called. */ ++#ifdef CONFIG_AUFS_DEBUG ++static int aufs_write_begin(struct file *file, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned flags, ++ struct page **pagep, void **fsdata) ++{ AuUnsupport(); return 0; } ++static int aufs_write_end(struct file *file, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned copied, ++ struct page *page, void *fsdata) ++{ AuUnsupport(); return 0; } ++static int aufs_writepage(struct page *page, struct writeback_control *wbc) ++{ AuUnsupport(); return 0; } ++ ++static int aufs_set_page_dirty(struct page *page) ++{ AuUnsupport(); return 0; } ++static void aufs_invalidatepage(struct page *page, unsigned int offset, ++ unsigned int length) ++{ AuUnsupport(); } ++static int aufs_releasepage(struct page *page, gfp_t gfp) ++{ AuUnsupport(); return 0; } ++#if 0 /* called by memory compaction regardless file */ ++static int aufs_migratepage(struct address_space *mapping, struct page *newpage, ++ struct page *page, enum migrate_mode mode) ++{ AuUnsupport(); return 0; } ++#endif ++static bool aufs_isolate_page(struct page *page, isolate_mode_t mode) ++{ AuUnsupport(); return true; } ++static void aufs_putback_page(struct page *page) ++{ AuUnsupport(); } ++static int aufs_launder_page(struct page *page) ++{ AuUnsupport(); return 0; } ++static int aufs_is_partially_uptodate(struct page *page, ++ unsigned long from, ++ unsigned long count) ++{ AuUnsupport(); return 0; } ++static void aufs_is_dirty_writeback(struct page *page, bool *dirty, ++ bool *writeback) ++{ AuUnsupport(); } ++static int aufs_error_remove_page(struct address_space *mapping, ++ struct page *page) ++{ AuUnsupport(); return 0; } ++static int aufs_swap_activate(struct swap_info_struct *sis, struct file *file, ++ sector_t *span) ++{ AuUnsupport(); return 0; } ++static void aufs_swap_deactivate(struct file *file) ++{ AuUnsupport(); } ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++const struct address_space_operations aufs_aop = { ++ .readpage = aufs_readpage, ++ .direct_IO = aufs_direct_IO, ++#ifdef CONFIG_AUFS_DEBUG ++ .writepage = aufs_writepage, ++ /* no writepages, because of writepage */ ++ .set_page_dirty = aufs_set_page_dirty, ++ /* no readpages, because of readpage */ ++ .write_begin = aufs_write_begin, ++ .write_end = aufs_write_end, ++ /* no bmap, no block device */ ++ .invalidatepage = aufs_invalidatepage, ++ .releasepage = aufs_releasepage, ++ /* is fallback_migrate_page ok? */ ++ /* .migratepage = aufs_migratepage, */ ++ .isolate_page = aufs_isolate_page, ++ .putback_page = aufs_putback_page, ++ .launder_page = aufs_launder_page, ++ .is_partially_uptodate = aufs_is_partially_uptodate, ++ .is_dirty_writeback = aufs_is_dirty_writeback, ++ .error_remove_page = aufs_error_remove_page, ++ .swap_activate = aufs_swap_activate, ++ .swap_deactivate = aufs_swap_deactivate ++#endif /* CONFIG_AUFS_DEBUG */ ++}; +diff -Naur null/fs/aufs/file.h linux-5.15.36/fs/aufs/file.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/file.h 2022-05-10 16:51:39.871744219 +0300 +@@ -0,0 +1,342 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * file operations ++ */ ++ ++#ifndef __AUFS_FILE_H__ ++#define __AUFS_FILE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include "rwsem.h" ++ ++struct au_branch; ++struct au_hfile { ++ struct file *hf_file; ++ struct au_branch *hf_br; ++}; ++ ++struct au_vdir; ++struct au_fidir { ++ aufs_bindex_t fd_bbot; ++ aufs_bindex_t fd_nent; ++ struct au_vdir *fd_vdir_cache; ++ struct au_hfile fd_hfile[]; ++}; ++ ++static inline int au_fidir_sz(int nent) ++{ ++ AuDebugOn(nent < 0); ++ return sizeof(struct au_fidir) + sizeof(struct au_hfile) * nent; ++} ++ ++struct au_finfo { ++ atomic_t fi_generation; ++ ++ struct au_rwsem fi_rwsem; ++ aufs_bindex_t fi_btop; ++ ++ /* do not union them */ ++ struct { /* for non-dir */ ++ struct au_hfile fi_htop; ++ atomic_t fi_mmapped; ++ }; ++ struct au_fidir *fi_hdir; /* for dir only */ ++ ++ struct hlist_bl_node fi_hlist; ++ struct file *fi_file; /* very ugly */ ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* file.c */ ++extern const struct address_space_operations aufs_aop; ++unsigned int au_file_roflags(unsigned int flags); ++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, ++ struct file *file, int force_wr); ++struct au_do_open_args { ++ int aopen; ++ int (*open)(struct file *file, int flags, ++ struct file *h_file); ++ struct au_fidir *fidir; ++ struct file *h_file; ++}; ++int au_do_open(struct file *file, struct au_do_open_args *args); ++int au_reopen_nondir(struct file *file); ++struct au_pin; ++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin); ++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), ++ int wlock, unsigned int fi_lsc); ++int au_do_flush(struct file *file, fl_owner_t id, ++ int (*flush)(struct file *file, fl_owner_t id)); ++ ++/* poll.c */ ++#ifdef CONFIG_AUFS_POLL ++__poll_t aufs_poll(struct file *file, struct poll_table_struct *pt); ++#endif ++ ++#ifdef CONFIG_AUFS_BR_HFSPLUS ++/* hfsplus.c */ ++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, ++ int force_wr); ++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file); ++#else ++AuStub(struct file *, au_h_open_pre, return NULL, struct dentry *dentry, ++ aufs_bindex_t bindex, int force_wr) ++AuStubVoid(au_h_open_post, struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file); ++#endif ++ ++/* f_op.c */ ++extern const struct file_operations aufs_file_fop; ++int au_do_open_nondir(struct file *file, int flags, struct file *h_file); ++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file); ++struct file *au_read_pre(struct file *file, int keep_fi, unsigned int lsc); ++ ++/* finfo.c */ ++void au_hfput(struct au_hfile *hf, int execed); ++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, ++ struct file *h_file); ++ ++void au_update_figen(struct file *file); ++struct au_fidir *au_fidir_alloc(struct super_block *sb); ++int au_fidir_realloc(struct au_finfo *finfo, int nbr, int may_shrink); ++ ++void au_fi_init_once(void *_fi); ++void au_finfo_fin(struct file *file); ++int au_finfo_init(struct file *file, struct au_fidir *fidir); ++ ++/* ioctl.c */ ++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, ++ unsigned long arg); ++long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, ++ unsigned long arg); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_finfo *au_fi(struct file *file) ++{ ++ return file->private_data; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define fi_read_lock(f) au_rw_read_lock(&au_fi(f)->fi_rwsem) ++#define fi_write_lock(f) au_rw_write_lock(&au_fi(f)->fi_rwsem) ++#define fi_read_trylock(f) au_rw_read_trylock(&au_fi(f)->fi_rwsem) ++#define fi_write_trylock(f) au_rw_write_trylock(&au_fi(f)->fi_rwsem) ++/* ++#define fi_read_trylock_nested(f) \ ++ au_rw_read_trylock_nested(&au_fi(f)->fi_rwsem) ++#define fi_write_trylock_nested(f) \ ++ au_rw_write_trylock_nested(&au_fi(f)->fi_rwsem) ++*/ ++ ++#define fi_read_unlock(f) au_rw_read_unlock(&au_fi(f)->fi_rwsem) ++#define fi_write_unlock(f) au_rw_write_unlock(&au_fi(f)->fi_rwsem) ++#define fi_downgrade_lock(f) au_rw_dgrade_lock(&au_fi(f)->fi_rwsem) ++ ++/* lock subclass for finfo */ ++enum { ++ AuLsc_FI_1, ++ AuLsc_FI_2 ++}; ++ ++static inline void fi_read_lock_nested(struct file *f, unsigned int lsc) ++{ ++ au_rw_read_lock_nested(&au_fi(f)->fi_rwsem, lsc); ++} ++ ++static inline void fi_write_lock_nested(struct file *f, unsigned int lsc) ++{ ++ au_rw_write_lock_nested(&au_fi(f)->fi_rwsem, lsc); ++} ++ ++/* ++ * fi_read_lock_1, fi_write_lock_1, ++ * fi_read_lock_2, fi_write_lock_2 ++ */ ++#define AuReadLockFunc(name) \ ++static inline void fi_read_lock_##name(struct file *f) \ ++{ fi_read_lock_nested(f, AuLsc_FI_##name); } ++ ++#define AuWriteLockFunc(name) \ ++static inline void fi_write_lock_##name(struct file *f) \ ++{ fi_write_lock_nested(f, AuLsc_FI_##name); } ++ ++#define AuRWLockFuncs(name) \ ++ AuReadLockFunc(name) \ ++ AuWriteLockFunc(name) ++ ++AuRWLockFuncs(1); ++AuRWLockFuncs(2); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++#define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem) ++#define FiMustAnyLock(f) AuRwMustAnyLock(&au_fi(f)->fi_rwsem) ++#define FiMustWriteLock(f) AuRwMustWriteLock(&au_fi(f)->fi_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: hard/soft set? */ ++static inline aufs_bindex_t au_fbtop(struct file *file) ++{ ++ FiMustAnyLock(file); ++ return au_fi(file)->fi_btop; ++} ++ ++static inline aufs_bindex_t au_fbbot_dir(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_bbot; ++} ++ ++static inline struct au_vdir *au_fvdir_cache(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_vdir_cache; ++} ++ ++static inline void au_set_fbtop(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ au_fi(file)->fi_btop = bindex; ++} ++ ++static inline void au_set_fbbot_dir(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ au_fi(file)->fi_hdir->fd_bbot = bindex; ++} ++ ++static inline void au_set_fvdir_cache(struct file *file, ++ struct au_vdir *vdir_cache) ++{ ++ FiMustWriteLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ au_fi(file)->fi_hdir->fd_vdir_cache = vdir_cache; ++} ++ ++static inline struct file *au_hf_top(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_htop.hf_file; ++} ++ ++static inline struct file *au_hf_dir(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_hfile[0 + bindex].hf_file; ++} ++ ++/* todo: memory barrier? */ ++static inline unsigned int au_figen(struct file *f) ++{ ++ return atomic_read(&au_fi(f)->fi_generation); ++} ++ ++static inline void au_set_mmapped(struct file *f) ++{ ++ if (atomic_inc_return(&au_fi(f)->fi_mmapped)) ++ return; ++ pr_warn("fi_mmapped wrapped around\n"); ++ while (!atomic_inc_return(&au_fi(f)->fi_mmapped)) ++ ; ++} ++ ++static inline void au_unset_mmapped(struct file *f) ++{ ++ atomic_dec(&au_fi(f)->fi_mmapped); ++} ++ ++static inline int au_test_mmapped(struct file *f) ++{ ++ return atomic_read(&au_fi(f)->fi_mmapped); ++} ++ ++/* customize vma->vm_file */ ++ ++static inline void au_do_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ struct file *f; ++ ++ f = vma->vm_file; ++ get_file(file); ++ vma->vm_file = file; ++ fput(f); ++} ++ ++#ifdef CONFIG_MMU ++#define AuDbgVmRegion(file, vma) do {} while (0) ++ ++static inline void au_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ au_do_vm_file_reset(vma, file); ++} ++#else ++#define AuDbgVmRegion(file, vma) \ ++ AuDebugOn((vma)->vm_region && (vma)->vm_region->vm_file != (file)) ++ ++static inline void au_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ struct file *f; ++ ++ au_do_vm_file_reset(vma, file); ++ f = vma->vm_region->vm_file; ++ get_file(file); ++ vma->vm_region->vm_file = file; ++ fput(f); ++} ++#endif /* CONFIG_MMU */ ++ ++/* handle vma->vm_prfile */ ++static inline void au_vm_prfile_set(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ get_file(file); ++ vma->vm_prfile = file; ++#ifndef CONFIG_MMU ++ get_file(file); ++ vma->vm_region->vm_prfile = file; ++#endif ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_FILE_H__ */ +diff -Naur null/fs/aufs/finfo.c linux-5.15.36/fs/aufs/finfo.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/finfo.c 2022-05-10 16:51:39.871744219 +0300 +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * file private data ++ */ ++ ++#include "aufs.h" ++ ++void au_hfput(struct au_hfile *hf, int execed) ++{ ++ if (execed) ++ allow_write_access(hf->hf_file); ++ fput(hf->hf_file); ++ hf->hf_file = NULL; ++ au_lcnt_dec(&hf->hf_br->br_nfiles); ++ hf->hf_br = NULL; ++} ++ ++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *val) ++{ ++ struct au_finfo *finfo = au_fi(file); ++ struct au_hfile *hf; ++ struct au_fidir *fidir; ++ ++ fidir = finfo->fi_hdir; ++ if (!fidir) { ++ AuDebugOn(finfo->fi_btop != bindex); ++ hf = &finfo->fi_htop; ++ } else ++ hf = fidir->fd_hfile + bindex; ++ ++ if (hf && hf->hf_file) ++ au_hfput(hf, vfsub_file_execed(file)); ++ if (val) { ++ FiMustWriteLock(file); ++ AuDebugOn(IS_ERR_OR_NULL(file->f_path.dentry)); ++ hf->hf_file = val; ++ hf->hf_br = au_sbr(file->f_path.dentry->d_sb, bindex); ++ } ++} ++ ++void au_update_figen(struct file *file) ++{ ++ atomic_set(&au_fi(file)->fi_generation, au_digen(file->f_path.dentry)); ++ /* smp_mb(); */ /* atomic_set */ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_fidir *au_fidir_alloc(struct super_block *sb) ++{ ++ struct au_fidir *fidir; ++ int nbr; ++ ++ nbr = au_sbbot(sb) + 1; ++ if (nbr < 2) ++ nbr = 2; /* initial allocate for 2 branches */ ++ fidir = kzalloc(au_fidir_sz(nbr), GFP_NOFS); ++ if (fidir) { ++ fidir->fd_bbot = -1; ++ fidir->fd_nent = nbr; ++ } ++ ++ return fidir; ++} ++ ++int au_fidir_realloc(struct au_finfo *finfo, int nbr, int may_shrink) ++{ ++ int err; ++ struct au_fidir *fidir, *p; ++ ++ AuRwMustWriteLock(&finfo->fi_rwsem); ++ fidir = finfo->fi_hdir; ++ AuDebugOn(!fidir); ++ ++ err = -ENOMEM; ++ p = au_kzrealloc(fidir, au_fidir_sz(fidir->fd_nent), au_fidir_sz(nbr), ++ GFP_NOFS, may_shrink); ++ if (p) { ++ p->fd_nent = nbr; ++ finfo->fi_hdir = p; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_finfo_fin(struct file *file) ++{ ++ struct au_finfo *finfo; ++ ++ au_lcnt_dec(&au_sbi(file->f_path.dentry->d_sb)->si_nfiles); ++ ++ finfo = au_fi(file); ++ AuDebugOn(finfo->fi_hdir); ++ AuRwDestroy(&finfo->fi_rwsem); ++ au_cache_free_finfo(finfo); ++} ++ ++void au_fi_init_once(void *_finfo) ++{ ++ struct au_finfo *finfo = _finfo; ++ ++ au_rw_init(&finfo->fi_rwsem); ++} ++ ++int au_finfo_init(struct file *file, struct au_fidir *fidir) ++{ ++ int err; ++ struct au_finfo *finfo; ++ struct dentry *dentry; ++ ++ err = -ENOMEM; ++ dentry = file->f_path.dentry; ++ finfo = au_cache_alloc_finfo(); ++ if (unlikely(!finfo)) ++ goto out; ++ ++ err = 0; ++ 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; ++ atomic_set(&finfo->fi_generation, au_digen(dentry)); ++ /* smp_mb(); */ /* atomic_set */ ++ ++ file->private_data = finfo; ++ ++out: ++ return err; ++} +diff -Naur null/fs/aufs/f_op.c linux-5.15.36/fs/aufs/f_op.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/f_op.c 2022-05-10 16:51:39.870744219 +0300 +@@ -0,0 +1,771 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * file and vm operations ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++int au_do_open_nondir(struct file *file, int flags, struct file *h_file) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct dentry *dentry, *h_dentry; ++ struct au_finfo *finfo; ++ struct inode *h_inode; ++ ++ FiMustWriteLock(file); ++ ++ err = 0; ++ dentry = file->f_path.dentry; ++ AuDebugOn(IS_ERR_OR_NULL(dentry)); ++ finfo = au_fi(file); ++ memset(&finfo->fi_htop, 0, sizeof(finfo->fi_htop)); ++ atomic_set(&finfo->fi_mmapped, 0); ++ bindex = au_dbtop(dentry); ++ if (!h_file) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ err = vfsub_test_mntns(file->f_path.mnt, h_dentry->d_sb); ++ 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; ++ /* br ref is already inc-ed */ ++ } ++ ++ 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; ++} ++ ++static int aufs_open_nondir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_do_open_args args = { ++ .open = au_do_open_nondir ++ }; ++ ++ AuDbg("%pD, f_flags 0x%x, f_mode 0x%x\n", ++ file, vfsub_file_flags(file), file->f_mode); ++ ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_do_open(file, &args); ++ si_read_unlock(sb); ++ return err; ++} ++ ++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file) ++{ ++ struct au_finfo *finfo; ++ aufs_bindex_t bindex; ++ ++ finfo = au_fi(file); ++ au_hbl_del(&finfo->fi_hlist, ++ &au_sbi(file->f_path.dentry->d_sb)->si_files); ++ bindex = finfo->fi_btop; ++ if (bindex >= 0) ++ au_set_h_fptr(file, bindex, NULL); ++ ++ au_finfo_fin(file); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_flush_nondir(struct file *file, fl_owner_t id) ++{ ++ int err; ++ struct file *h_file; ++ ++ err = 0; ++ h_file = au_hf_top(file); ++ if (h_file) ++ err = vfsub_flush(h_file, id); ++ return err; ++} ++ ++static int aufs_flush_nondir(struct file *file, fl_owner_t id) ++{ ++ return au_do_flush(file, id, au_do_flush_nondir); ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * 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-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. ++ */ ++ ++/* Callers should call au_read_post() or fput() in the end */ ++struct file *au_read_pre(struct file *file, int keep_fi, unsigned int lsc) ++{ ++ struct file *h_file; ++ int err; ++ ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0, lsc); ++ if (!err) { ++ di_read_unlock(file->f_path.dentry, AuLock_IR); ++ h_file = au_hf_top(file); ++ get_file(h_file); ++ if (!keep_fi) ++ fi_read_unlock(file); ++ } else ++ h_file = ERR_PTR(err); ++ ++ return h_file; ++} ++ ++static void au_read_post(struct inode *inode, struct file *h_file) ++{ ++ /* update without lock, I don't think it a problem */ ++ fsstack_copy_attr_atime(inode, file_inode(h_file)); ++ fput(h_file); ++} ++ ++struct au_write_pre { ++ /* input */ ++ unsigned int lsc; ++ ++ /* output */ ++ blkcnt_t blks; ++ aufs_bindex_t btop; ++}; ++ ++/* ++ * return with iinfo is write-locked ++ * callers should call au_write_post() or iinfo_write_unlock() + fput() in the ++ * end ++ */ ++static struct file *au_write_pre(struct file *file, int do_ready, ++ struct au_write_pre *wpre) ++{ ++ struct file *h_file; ++ struct dentry *dentry; ++ int err; ++ unsigned int lsc; ++ struct au_pin pin; ++ ++ lsc = 0; ++ if (wpre) ++ lsc = wpre->lsc; ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1, lsc); ++ h_file = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_path.dentry; ++ if (do_ready) { ++ err = au_ready_to_write(file, -1, &pin); ++ if (unlikely(err)) { ++ h_file = ERR_PTR(err); ++ di_write_unlock(dentry); ++ goto out_fi; ++ } ++ } ++ ++ di_downgrade_lock(dentry, /*flags*/0); ++ if (wpre) ++ wpre->btop = au_fbtop(file); ++ h_file = au_hf_top(file); ++ get_file(h_file); ++ if (wpre) ++ wpre->blks = file_inode(h_file)->i_blocks; ++ if (do_ready) ++ au_unpin(&pin); ++ di_read_unlock(dentry, /*flags*/0); ++ ++out_fi: ++ fi_write_unlock(file); ++out: ++ return h_file; ++} ++ ++static void au_write_post(struct inode *inode, struct file *h_file, ++ struct au_write_pre *wpre, ssize_t written) ++{ ++ struct inode *h_inode; ++ ++ au_cpup_attr_timesizes(inode); ++ AuDebugOn(au_ibtop(inode) != wpre->btop); ++ h_inode = file_inode(h_file); ++ inode->i_mode = h_inode->i_mode; ++ ii_write_unlock(inode); ++ /* AuDbg("blks %llu, %llu\n", (u64)blks, (u64)h_inode->i_blocks); */ ++ if (written > 0) ++ au_fhsm_wrote(inode->i_sb, wpre->btop, ++ /*force*/h_inode->i_blocks > wpre->blks); ++ fput(h_file); ++} ++ ++/* ++ * todo: very ugly ++ * it locks both of i_mutex and si_rwsem for read in safe. ++ * if the plink maintenance mode continues forever (that is the problem), ++ * may loop forever. ++ */ ++static void au_mtx_and_read_lock(struct inode *inode) ++{ ++ int err; ++ struct super_block *sb = inode->i_sb; ++ ++ while (1) { ++ inode_lock(inode); ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (!err) ++ break; ++ inode_unlock(inode); ++ si_read_lock(sb, AuLock_NOPLMW); ++ si_read_unlock(sb); ++ } ++} ++ ++static ssize_t au_do_iter(struct file *h_file, int rw, struct kiocb *kio, ++ struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct file *file; ++ ssize_t (*iter)(struct kiocb *, struct iov_iter *); ++ ++ err = security_file_permission(h_file, rw); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -ENOSYS; /* the branch doesn't have its ->(read|write)_iter() */ ++ iter = NULL; ++ if (rw == MAY_READ) ++ iter = h_file->f_op->read_iter; ++ else if (rw == MAY_WRITE) ++ iter = h_file->f_op->write_iter; ++ ++ file = kio->ki_filp; ++ kio->ki_filp = h_file; ++ if (iter) { ++ lockdep_off(); ++ err = iter(kio, iov_iter); ++ lockdep_on(); ++ } else ++ /* currently there is no such fs */ ++ WARN_ON_ONCE(1); ++ kio->ki_filp = file; ++ ++out: ++ return err; ++} ++ ++static ssize_t aufs_read_iter(struct kiocb *kio, struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct file *file, *h_file; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ file = kio->ki_filp; ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/1, /*lsc*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ if (au_test_loopback_kthread()) { ++ au_warn_loopback(h_file->f_path.dentry->d_sb); ++ if (file->f_mapping != h_file->f_mapping) { ++ file->f_mapping = h_file->f_mapping; ++ smp_mb(); /* unnecessary? */ ++ } ++ } ++ fi_read_unlock(file); ++ ++ err = au_do_iter(h_file, MAY_READ, kio, iov_iter); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ au_read_post(inode, h_file); ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static ssize_t aufs_write_iter(struct kiocb *kio, struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *file, *h_file; ++ ++ file = kio->ki_filp; ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = au_do_iter(h_file, MAY_WRITE, kio, iov_iter); ++ au_write_post(inode, h_file, &wpre, err); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++/* ++ * We may be able to remove aufs_splice_{read,write}() since almost all FSes ++ * don't have their own .splice_{read,write} implimentations, and they use ++ * generic_file_splice_read() and iter_file_splice_write() who can act like the ++ * simple converters to f_op->iter_read() and ->iter_write(). ++ * But we keep our own implementations because some non-mainlined FSes may have ++ * their own .splice_{read,write} implimentations and aufs doesn't want to take ++ * away an opportunity to co-work with aufs from them. ++ */ ++static ssize_t aufs_splice_read(struct file *file, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) ++{ ++ ssize_t err; ++ struct file *h_file; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ 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)) ++ goto out; ++ ++ err = vfsub_splice_to(h_file, ppos, pipe, len, flags); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ au_read_post(inode, h_file); ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static ssize_t ++aufs_splice_write(struct pipe_inode_info *pipe, struct file *file, loff_t *ppos, ++ size_t len, unsigned int flags) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = vfsub_splice_from(pipe, h_file, ppos, len, flags); ++ au_write_post(inode, h_file, &wpre, err); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++static long aufs_fallocate(struct file *file, int mode, loff_t offset, ++ loff_t len) ++{ ++ long err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_fallocate(h_file, mode, offset, len); ++ lockdep_on(); ++ au_write_post(inode, h_file, &wpre, /*written*/1); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++static ssize_t aufs_copy_file_range(struct file *src, loff_t src_pos, ++ struct file *dst, loff_t dst_pos, ++ size_t len, unsigned int flags) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ enum { SRC, DST }; ++ struct { ++ struct inode *inode; ++ struct file *h_file; ++ struct super_block *h_sb; ++ } a[2]; ++#define a_src a[SRC] ++#define a_dst a[DST] ++ ++ err = -EINVAL; ++ a_src.inode = file_inode(src); ++ if (unlikely(!S_ISREG(a_src.inode->i_mode))) ++ goto out; ++ a_dst.inode = file_inode(dst); ++ if (unlikely(!S_ISREG(a_dst.inode->i_mode))) ++ goto out; ++ ++ 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 comparison. ++ */ ++ if (src->f_path.dentry < dst->f_path.dentry) { ++ a_src.h_file = au_read_pre(src, /*keep_fi*/1, AuLsc_FI_1); ++ err = PTR_ERR(a_src.h_file); ++ if (IS_ERR(a_src.h_file)) ++ goto out_si; ++ ++ wpre.lsc = AuLsc_FI_2; ++ a_dst.h_file = au_write_pre(dst, /*do_ready*/1, &wpre); ++ err = PTR_ERR(a_dst.h_file); ++ if (IS_ERR(a_dst.h_file)) { ++ au_read_post(a_src.inode, a_src.h_file); ++ goto out_si; ++ } ++ } else { ++ wpre.lsc = AuLsc_FI_1; ++ a_dst.h_file = au_write_pre(dst, /*do_ready*/1, &wpre); ++ err = PTR_ERR(a_dst.h_file); ++ if (IS_ERR(a_dst.h_file)) ++ goto out_si; ++ ++ a_src.h_file = au_read_pre(src, /*keep_fi*/1, AuLsc_FI_2); ++ err = PTR_ERR(a_src.h_file); ++ if (IS_ERR(a_src.h_file)) { ++ au_write_post(a_dst.inode, a_dst.h_file, &wpre, ++ /*written*/0); ++ goto out_si; ++ } ++ } ++ ++ err = -EXDEV; ++ a_src.h_sb = file_inode(a_src.h_file)->i_sb; ++ a_dst.h_sb = file_inode(a_dst.h_file)->i_sb; ++ if (unlikely(a_src.h_sb != a_dst.h_sb)) { ++ AuDbgFile(src); ++ AuDbgFile(dst); ++ goto out_file; ++ } ++ ++ err = vfsub_copy_file_range(a_src.h_file, src_pos, a_dst.h_file, ++ dst_pos, len, flags); ++ ++out_file: ++ au_write_post(a_dst.inode, a_dst.h_file, &wpre, err); ++ fi_read_unlock(src); ++ au_read_post(a_src.inode, a_src.h_file); ++out_si: ++ si_read_unlock(a_dst.inode->i_sb); ++ inode_unlock(a_dst.inode); ++out: ++ return err; ++#undef a_src ++#undef a_dst ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * The locking order around current->mmap_sem. ++ * - in most and regular cases ++ * file I/O syscall -- aufs_read() or something ++ * -- si_rwsem for read -- mmap_sem ++ * (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 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. ++ * ++ * Actually aufs_iterate() holds [fdi]i_rwsem before mmap_sem, but this is not a ++ * problem either since any directory is not able to be mmap-ed. ++ * The similar scenario is applied to aufs_readlink() too. ++ */ ++ ++#if 0 /* stop calling security_file_mmap() */ ++/* cf. linux/include/linux/mman.h: calc_vm_prot_bits() */ ++#define AuConv_VM_PROT(f, b) _calc_vm_trans(f, VM_##b, PROT_##b) ++ ++static unsigned long au_arch_prot_conv(unsigned long flags) ++{ ++ /* currently ppc64 only */ ++#ifdef CONFIG_PPC64 ++ /* cf. linux/arch/powerpc/include/asm/mman.h */ ++ AuDebugOn(arch_calc_vm_prot_bits(-1) != VM_SAO); ++ return AuConv_VM_PROT(flags, SAO); ++#else ++ AuDebugOn(arch_calc_vm_prot_bits(-1)); ++ return 0; ++#endif ++} ++ ++static unsigned long au_prot_conv(unsigned long flags) ++{ ++ return AuConv_VM_PROT(flags, READ) ++ | AuConv_VM_PROT(flags, WRITE) ++ | AuConv_VM_PROT(flags, EXEC) ++ | au_arch_prot_conv(flags); ++} ++ ++/* cf. linux/include/linux/mman.h: calc_vm_flag_bits() */ ++#define AuConv_VM_MAP(f, b) _calc_vm_trans(f, VM_##b, MAP_##b) ++ ++static unsigned long au_flag_conv(unsigned long flags) ++{ ++ return AuConv_VM_MAP(flags, GROWSDOWN) ++ | AuConv_VM_MAP(flags, DENYWRITE) ++ | AuConv_VM_MAP(flags, LOCKED); ++} ++#endif ++ ++static int aufs_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ int err; ++ const unsigned char wlock ++ = (file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED); ++ struct super_block *sb; ++ struct file *h_file; ++ struct inode *inode; ++ ++ AuDbgVmRegion(file, vma); ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ lockdep_off(); ++ si_read_lock(sb, AuLock_NOPLMW); ++ ++ h_file = au_write_pre(file, wlock, /*wpre*/NULL); ++ lockdep_on(); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = 0; ++ au_set_mmapped(file); ++ au_vm_file_reset(vma, h_file); ++ /* ++ * we cannot call security_mmap_file() here since it may acquire ++ * mmap_sem or i_mutex. ++ * ++ * err = security_mmap_file(h_file, au_prot_conv(vma->vm_flags), ++ * au_flag_conv(vma->vm_flags)); ++ */ ++ if (!err) ++ err = call_mmap(h_file, vma); ++ if (!err) { ++ au_vm_prfile_set(vma, file); ++ fsstack_copy_attr_atime(inode, file_inode(h_file)); ++ goto out_fput; /* success */ ++ } ++ au_unset_mmapped(file); ++ au_vm_file_reset(vma, file); ++ ++out_fput: ++ lockdep_off(); ++ ii_write_unlock(inode); ++ lockdep_on(); ++ fput(h_file); ++out: ++ lockdep_off(); ++ si_read_unlock(sb); ++ lockdep_on(); ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_fsync_nondir(struct file *file, loff_t start, loff_t end, ++ int datasync) ++{ ++ int err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ err = 0; /* -EBADF; */ /* posix? */ ++ if (unlikely(!(file->f_mode & FMODE_WRITE))) ++ goto out; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out_unlock; ++ ++ err = vfsub_fsync(h_file, &h_file->f_path, datasync); ++ au_write_post(inode, h_file, &wpre, /*written*/0); ++ ++out_unlock: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++out: ++ return err; ++} ++ ++static int aufs_fasync(int fd, struct file *file, int flag) ++{ ++ int err; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ sb = file->f_path.dentry->d_sb; ++ 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)) ++ goto out; ++ ++ if (h_file->f_op->fasync) ++ err = h_file->f_op->fasync(fd, h_file, flag); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static int aufs_setfl(struct file *file, unsigned long arg) ++{ ++ int err; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ sb = file->f_path.dentry->d_sb; ++ 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)) ++ goto out; ++ ++ /* stop calling h_file->fasync */ ++ arg |= vfsub_file_flags(file) & FASYNC; ++ err = setfl(/*unused fd*/-1, h_file, arg); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* no one supports this operation, currently */ ++#if 0 /* reserved for future use */ ++static ssize_t aufs_sendpage(struct file *file, struct page *page, int offset, ++ size_t len, loff_t *pos, int more) ++{ ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++const struct file_operations aufs_file_fop = { ++ .owner = THIS_MODULE, ++ ++ .llseek = default_llseek, ++ ++ .read_iter = aufs_read_iter, ++ .write_iter = aufs_write_iter, ++ ++#ifdef CONFIG_AUFS_POLL ++ .poll = aufs_poll, ++#endif ++ .unlocked_ioctl = aufs_ioctl_nondir, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = aufs_compat_ioctl_nondir, ++#endif ++ .mmap = aufs_mmap, ++ .open = aufs_open_nondir, ++ .flush = aufs_flush_nondir, ++ .release = aufs_release_nondir, ++ .fsync = aufs_fsync_nondir, ++ .fasync = aufs_fasync, ++ /* .sendpage = aufs_sendpage, */ ++ .setfl = aufs_setfl, ++ .splice_write = aufs_splice_write, ++ .splice_read = aufs_splice_read, ++#if 0 /* reserved for future use */ ++ .aio_splice_write = aufs_aio_splice_write, ++ .aio_splice_read = aufs_aio_splice_read, ++#endif ++ .fallocate = aufs_fallocate, ++ .copy_file_range = aufs_copy_file_range ++}; +diff -Naur null/fs/aufs/fsctx.c linux-5.15.36/fs/aufs/fsctx.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/fsctx.c 2022-05-10 16:51:39.871744219 +0300 +@@ -0,0 +1,1242 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2022 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 . ++ */ ++ ++/* ++ * fs context, aka new mount api ++ */ ++ ++#include ++#include "aufs.h" ++ ++struct au_fsctx_opts { ++ aufs_bindex_t bindex; ++ unsigned char skipped; ++ struct au_opt *opt, *opt_tail; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct au_opts opts; ++}; ++ ++/* stop extra interpretation of errno in mount(8), and strange error messages */ ++static int cvt_err(int err) ++{ ++ AuTraceErr(err); ++ ++ switch (err) { ++ case -ENOENT: ++ case -ENOTDIR: ++ case -EEXIST: ++ case -EIO: ++ err = -EINVAL; ++ } ++ return err; ++} ++ ++static int au_fsctx_reconfigure(struct fs_context *fc) ++{ ++ int err, do_dx; ++ unsigned int mntflags; ++ struct dentry *root; ++ struct super_block *sb; ++ struct inode *inode; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ AuDbg("fc %p\n", fc); ++ ++ root = fc->root; ++ sb = root->d_sb; ++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (!err) { ++ di_write_lock_child(root); ++ err = au_opts_verify(sb, fc->sb_flags, /*pending*/0); ++ aufs_write_unlock(root); ++ } ++ ++ inode = d_inode(root); ++ inode_lock(inode); ++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ di_write_lock_child(root); ++ ++ /* au_opts_remount() may return an error */ ++ err = au_opts_remount(sb, &a->opts); ++ ++ if (au_ftest_opts(a->opts.flags, REFRESH)) ++ au_remount_refresh(sb, au_ftest_opts(a->opts.flags, ++ REFRESH_IDOP)); ++ ++ if (au_ftest_opts(a->opts.flags, REFRESH_DYAOP)) { ++ mntflags = au_mntflags(sb); ++ do_dx = !!au_opt_test(mntflags, DIO); ++ au_dy_arefresh(do_dx); ++ } ++ ++ au_fhsm_wrote_all(sb, /*force*/1); /* ?? */ ++ aufs_write_unlock(root); ++ ++out: ++ inode_unlock(inode); ++ err = cvt_err(err); ++ AuTraceErr(err); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_fsctx_fill_super(struct super_block *sb, struct fs_context *fc) ++{ ++ int err; ++ struct au_fsctx_opts *a = fc->fs_private; ++ struct au_sbinfo *sbinfo = a->sbinfo; ++ struct dentry *root; ++ struct inode *inode; ++ ++ sbinfo->si_sb = sb; ++ sb->s_fs_info = sbinfo; ++ kobject_get(&sbinfo->si_kobj); ++ ++ __si_write_lock(sb); ++ si_pid_set(sb); ++ au_sbilist_add(sb); ++ ++ /* all timestamps always follow the ones on the branch */ ++ sb->s_flags |= SB_NOATIME | SB_NODIRATIME; ++ sb->s_flags |= SB_I_VERSION; /* do we really need this? */ ++ sb->s_op = &aufs_sop; ++ sb->s_d_op = &aufs_dop; ++ sb->s_magic = AUFS_SUPER_MAGIC; ++ sb->s_maxbytes = 0; ++ sb->s_stack_depth = 1; ++ au_export_init(sb); ++ au_xattr_init(sb); ++ ++ err = au_alloc_root(sb); ++ if (unlikely(err)) { ++ si_write_unlock(sb); ++ goto out; ++ } ++ root = sb->s_root; ++ inode = d_inode(root); ++ ii_write_lock_parent(inode); ++ aufs_write_unlock(root); ++ ++ /* lock vfs_inode first, then aufs. */ ++ inode_lock(inode); ++ aufs_write_lock(root); ++ err = au_opts_mount(sb, &a->opts); ++ AuTraceErr(err); ++ if (!err && au_ftest_si(sbinfo, NO_DREVAL)) { ++ sb->s_d_op = &aufs_dop_noreval; ++ /* infofc(fc, "%ps", 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); ++ } ++ aufs_write_unlock(root); ++ inode_unlock(inode); ++ if (!err) ++ goto out; /* success */ ++ ++ dput(root); ++ sb->s_root = NULL; ++ ++out: ++ if (unlikely(err)) ++ kobject_put(&sbinfo->si_kobj); ++ AuTraceErr(err); ++ err = cvt_err(err); ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_fsctx_get_tree(struct fs_context *fc) ++{ ++ int err; ++ ++ AuDbg("fc %p\n", fc); ++ err = get_tree_nodev(fc, au_fsctx_fill_super); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_fsctx_dump(struct au_opts *opts) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++ /* reduce stack space */ ++ union { ++ struct au_opt_add *add; ++ struct au_opt_del *del; ++ struct au_opt_mod *mod; ++ struct au_opt_xino *xino; ++ struct au_opt_xino_itrunc *xino_itrunc; ++ struct au_opt_wbr_create *create; ++ } u; ++ struct au_opt *opt; ++ ++ opt = opts->opt; ++ while (opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ u.add = &opt->add; ++ AuDbg("add {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_del: ++ fallthrough; ++ case Opt_idel: ++ u.del = &opt->del; ++ AuDbg("del {%s, %p}\n", ++ u.del->pathname, u.del->h_path.dentry); ++ break; ++ case Opt_mod: ++ fallthrough; ++ case Opt_imod: ++ u.mod = &opt->mod; ++ AuDbg("mod {%s, 0x%x, %p}\n", ++ u.mod->path, u.mod->perm, u.mod->h_root); ++ break; ++ case Opt_append: ++ u.add = &opt->add; ++ AuDbg("append {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_prepend: ++ u.add = &opt->add; ++ AuDbg("prepend {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ ++ case Opt_dirwh: ++ AuDbg("dirwh %d\n", opt->dirwh); ++ break; ++ case Opt_rdcache: ++ AuDbg("rdcache %d\n", opt->rdcache); ++ break; ++ case Opt_rdblk: ++ AuDbg("rdblk %d\n", opt->rdblk); ++ break; ++ case Opt_rdhash: ++ AuDbg("rdhash %u\n", opt->rdhash); ++ break; ++ ++ case Opt_xino: ++ u.xino = &opt->xino; ++ AuDbg("xino {%s %pD}\n", u.xino->path, u.xino->file); ++ break; ++ ++#define au_fsctx_TF(name) \ ++ case Opt_##name: \ ++ if (opt->tf) \ ++ AuLabel(name); \ ++ else \ ++ AuLabel(no##name); \ ++ break; ++ ++ /* simple true/false flag */ ++ au_fsctx_TF(trunc_xino); ++ au_fsctx_TF(trunc_xib); ++ au_fsctx_TF(dirperm1); ++ au_fsctx_TF(plink); ++ au_fsctx_TF(shwh); ++ au_fsctx_TF(dio); ++ au_fsctx_TF(warn_perm); ++ au_fsctx_TF(verbose); ++ au_fsctx_TF(sum); ++ au_fsctx_TF(dirren); ++ au_fsctx_TF(acl); ++#undef au_fsctx_TF ++ ++ case Opt_trunc_xino_path: ++ fallthrough; ++ case Opt_itrunc_xino: ++ u.xino_itrunc = &opt->xino_itrunc; ++ AuDbg("trunc_xino %d\n", u.xino_itrunc->bindex); ++ break; ++ case Opt_noxino: ++ AuLabel(noxino); ++ break; ++ ++ case Opt_list_plink: ++ AuLabel(list_plink); ++ break; ++ case Opt_udba: ++ AuDbg("udba %d, %s\n", ++ opt->udba, au_optstr_udba(opt->udba)); ++ break; ++ case Opt_diropq_a: ++ AuLabel(diropq_a); ++ break; ++ case Opt_diropq_w: ++ AuLabel(diropq_w); ++ break; ++ case Opt_wsum: ++ AuLabel(wsum); ++ break; ++ case Opt_wbr_create: ++ u.create = &opt->wbr_create; ++ AuDbg("create %d, %s\n", u.create->wbr_create, ++ au_optstr_wbr_create(u.create->wbr_create)); ++ switch (u.create->wbr_create) { ++ case AuWbrCreate_MFSV: ++ fallthrough; ++ case AuWbrCreate_PMFSV: ++ AuDbg("%d sec\n", u.create->mfs_second); ++ break; ++ case AuWbrCreate_MFSRR: ++ fallthrough; ++ case AuWbrCreate_TDMFS: ++ AuDbg("%llu watermark\n", ++ u.create->mfsrr_watermark); ++ break; ++ case AuWbrCreate_MFSRRV: ++ fallthrough; ++ case AuWbrCreate_TDMFSV: ++ fallthrough; ++ case AuWbrCreate_PMFSRRV: ++ AuDbg("%llu watermark, %d sec\n", ++ u.create->mfsrr_watermark, ++ u.create->mfs_second); ++ break; ++ } ++ break; ++ case Opt_wbr_copyup: ++ AuDbg("copyup %d, %s\n", opt->wbr_copyup, ++ au_optstr_wbr_copyup(opt->wbr_copyup)); ++ break; ++ case Opt_fhsm_sec: ++ AuDbg("fhsm_sec %u\n", opt->fhsm_second); ++ break; ++ ++ default: ++ AuDbg("type %d\n", opt->type); ++ BUG(); ++ } ++ opt++; ++ } ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * For conditionally compiled mount options. ++ * Instead of fsparam_flag_no(), use this macro to distinguish ignore_silent. ++ */ ++#define au_ignore_flag(name, action) \ ++ fsparam_flag(name, action), \ ++ fsparam_flag("no" name, Opt_ignore_silent) ++ ++const struct fs_parameter_spec aufs_fsctx_paramspec[] = { ++ fsparam_string("br", Opt_br), ++ ++ /* "add=%d:%s" or "ins=%d:%s" */ ++ fsparam_string("add", Opt_add), ++ fsparam_string("ins", Opt_add), ++ fsparam_path("append", Opt_append), ++ fsparam_path("prepend", Opt_prepend), ++ ++ fsparam_path("del", Opt_del), ++ /* fsparam_s32("idel", Opt_idel), */ ++ fsparam_path("mod", Opt_mod), ++ /* fsparam_string("imod", Opt_imod), */ ++ ++ fsparam_s32("dirwh", Opt_dirwh), ++ ++ fsparam_path("xino", Opt_xino), ++ fsparam_flag("noxino", Opt_noxino), ++ fsparam_flag_no("trunc_xino", Opt_trunc_xino), ++ /* "trunc_xino_v=%d:%d" */ ++ /* fsparam_string("trunc_xino_v", Opt_trunc_xino_v), */ ++ fsparam_path("trunc_xino", Opt_trunc_xino_path), ++ fsparam_s32("itrunc_xino", Opt_itrunc_xino), ++ /* fsparam_path("zxino", Opt_zxino), */ ++ fsparam_flag_no("trunc_xib", Opt_trunc_xib), ++ ++#ifdef CONFIG_PROC_FS ++ fsparam_flag_no("plink", Opt_plink), ++#else ++ au_ignore_flag("plink", Opt_ignore), ++#endif ++ ++#ifdef CONFIG_AUFS_DEBUG ++ fsparam_flag("list_plink", Opt_list_plink), ++#endif ++ ++ fsparam_string("udba", Opt_udba), ++ ++ fsparam_flag_no("dio", Opt_dio), ++ ++#ifdef CONFIG_AUFS_DIRREN ++ fsparam_flag_no("dirren", Opt_dirren), ++#else ++ au_ignore_flag("dirren", Opt_ignore), ++#endif ++ ++#ifdef CONFIG_AUFS_FHSM ++ fsparam_s32("fhsm_sec", Opt_fhsm_sec), ++#else ++ fsparam_s32("fhsm_sec", Opt_ignore), ++#endif ++ ++ /* always | a | whiteouted | w */ ++ fsparam_string("diropq", Opt_diropq), ++ ++ fsparam_flag_no("warn_perm", Opt_warn_perm), ++ ++#ifdef CONFIG_AUFS_SHWH ++ fsparam_flag_no("shwh", Opt_shwh), ++#else ++ au_ignore_flag("shwh", Opt_err), ++#endif ++ ++ fsparam_flag_no("dirperm1", Opt_dirperm1), ++ ++ fsparam_flag_no("verbose", Opt_verbose), ++ fsparam_flag("v", Opt_verbose), ++ fsparam_flag("quiet", Opt_noverbose), ++ fsparam_flag("q", Opt_noverbose), ++ /* user-space may handle this */ ++ fsparam_flag("silent", Opt_noverbose), ++ ++ fsparam_flag_no("sum", Opt_sum), ++ fsparam_flag("wsum", Opt_wsum), ++ ++ fsparam_s32("rdcache", Opt_rdcache), ++ /* "def" or s32 */ ++ fsparam_string("rdblk", Opt_rdblk), ++ /* "def" or s32 */ ++ fsparam_string("rdhash", Opt_rdhash), ++ ++ fsparam_string("create", Opt_wbr_create), ++ fsparam_string("create_policy", Opt_wbr_create), ++ fsparam_string("cpup", Opt_wbr_copyup), ++ fsparam_string("copyup", Opt_wbr_copyup), ++ fsparam_string("copyup_policy", Opt_wbr_copyup), ++ ++ /* generic VFS flag */ ++#ifdef CONFIG_FS_POSIX_ACL ++ fsparam_flag_no("acl", Opt_acl), ++#else ++ au_ignore_flag("acl"), ++#endif ++ ++ /* internal use for the scripts */ ++ fsparam_string("si", Opt_ignore_silent), ++ ++ /* obsoleted, keep them temporary */ ++ fsparam_flag("nodlgt", Opt_ignore_silent), ++ fsparam_flag("clean_plink", Opt_ignore), ++ fsparam_string("dirs", Opt_br), ++ fsparam_u32("debug", Opt_ignore), ++ /* "whiteout" or "all" */ ++ fsparam_string("delete", Opt_ignore), ++ fsparam_string("imap", Opt_ignore), ++ ++ /* temporary workaround, due to old mount(8)? */ ++ fsparam_flag("relatime", Opt_ignore_silent), ++ ++ {} ++}; ++ ++static int au_fsctx_parse_do_add(struct fs_context *fc, struct au_opt *opt, ++ char *brspec, size_t speclen, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ char *p; ++ ++ AuDbg("brspec %s\n", brspec); ++ ++ err = -ENOMEM; ++ if (!speclen) ++ speclen = strlen(brspec); ++ /* will be freed by au_fsctx_free() */ ++ p = kmemdup_nul(brspec, speclen, GFP_NOFS); ++ if (unlikely(!p)) { ++ errorfc(fc, "failed in %s", brspec); ++ goto out; ++ } ++ err = au_opt_add(opt, p, fc->sb_flags, bindex); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_fsctx_parse_br(struct fs_context *fc, char *brspec) ++{ ++ int err; ++ char *p; ++ struct au_fsctx_opts *a = fc->fs_private; ++ struct au_opt *opt = a->opt; ++ aufs_bindex_t bindex = a->bindex; ++ ++ AuDbg("brspec %s\n", brspec); ++ ++ err = -EINVAL; ++ while ((p = strsep(&brspec, ":")) && *p) { ++ err = au_fsctx_parse_do_add(fc, opt, p, /*len*/0, bindex); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ break; ++ bindex++; ++ opt++; ++ if (unlikely(opt > a->opt_tail)) { ++ err = -E2BIG; ++ bindex--; ++ opt--; ++ break; ++ } ++ opt->type = Opt_tail; ++ a->skipped = 1; ++ } ++ a->bindex = bindex; ++ a->opt = opt; ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_fsctx_parse_add(struct fs_context *fc, char *addspec) ++{ ++ int err, n; ++ char *p; ++ struct au_fsctx_opts *a = fc->fs_private; ++ struct au_opt *opt = a->opt; ++ ++ err = -EINVAL; ++ p = strchr(addspec, ':'); ++ if (unlikely(!p)) { ++ errorfc(fc, "bad arg in %s", addspec); ++ goto out; ++ } ++ *p++ = '\0'; ++ err = kstrtoint(addspec, 0, &n); ++ if (unlikely(err)) { ++ errorfc(fc, "bad integer in %s", addspec); ++ goto out; ++ } ++ AuDbg("n %d\n", n); ++ err = au_fsctx_parse_do_add(fc, opt, p, /*len*/0, n); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_fsctx_parse_del(struct fs_context *fc, struct au_opt_del *del, ++ struct fs_parameter *param) ++{ ++ int err; ++ ++ err = -ENOMEM; ++ /* will be freed by au_fsctx_free() */ ++ del->pathname = kmemdup_nul(param->string, param->size, GFP_NOFS); ++ if (unlikely(!del->pathname)) ++ goto out; ++ AuDbg("del %s\n", del->pathname); ++ err = vfsub_kern_path(del->pathname, AuOpt_LkupDirFlags, &del->h_path); ++ if (unlikely(err)) ++ errorfc(fc, "lookup failed %s (%d)", del->pathname, err); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#if 0 /* reserved for future use */ ++static int au_fsctx_parse_idel(struct fs_context *fc, struct au_opt_del *del, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ struct super_block *sb; ++ struct dentry *root; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ sb = a->sb; ++ AuDebugOn(!sb); ++ ++ err = -EINVAL; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (bindex < 0 || au_sbbot(sb) < bindex) { ++ errorfc(fc, "out of bounds, %d", bindex); ++ goto out; ++ } ++ ++ err = 0; ++ del->h_path.dentry = dget(au_h_dptr(root, bindex)); ++ del->h_path.mnt = mntget(au_sbr_mnt(sb, bindex)); ++ ++out: ++ aufs_read_unlock(root, !AuLock_IR); ++ AuTraceErr(err); ++ return err; ++} ++#endif ++ ++static int au_fsctx_parse_mod(struct fs_context *fc, struct au_opt_mod *mod, ++ struct fs_parameter *param) ++{ ++ int err; ++ struct path path; ++ char *p; ++ ++ err = -ENOMEM; ++ /* will be freed by au_fsctx_free() */ ++ mod->path = kmemdup_nul(param->string, param->size, GFP_NOFS); ++ if (unlikely(!mod->path)) ++ goto out; ++ ++ err = -EINVAL; ++ p = strchr(mod->path, '='); ++ if (unlikely(!p)) { ++ errorfc(fc, "no permission %s", mod->path); ++ goto out; ++ } ++ ++ *p++ = 0; ++ err = vfsub_kern_path(mod->path, AuOpt_LkupDirFlags, &path); ++ if (unlikely(err)) { ++ errorfc(fc, "lookup failed %s (%d)", mod->path, err); ++ goto out; ++ } ++ ++ mod->perm = au_br_perm_val(p); ++ AuDbg("mod path %s, perm 0x%x, %s", mod->path, mod->perm, p); ++ mod->h_root = dget(path.dentry); ++ path_put(&path); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#if 0 /* reserved for future use */ ++static int au_fsctx_parse_imod(struct fs_context *fc, struct au_opt_mod *mod, ++ char *ibrspec) ++{ ++ int err, n; ++ char *p; ++ struct super_block *sb; ++ struct dentry *root; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ sb = a->sb; ++ AuDebugOn(!sb); ++ ++ err = -EINVAL; ++ p = strchr(ibrspec, ':'); ++ if (unlikely(!p)) { ++ errorfc(fc, "no index, %s", ibrspec); ++ goto out; ++ } ++ *p++ = '\0'; ++ err = kstrtoint(ibrspec, 0, &n); ++ if (unlikely(err)) { ++ errorfc(fc, "bad integer in %s", ibrspec); ++ goto out; ++ } ++ AuDbg("n %d\n", n); ++ ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (n < 0 || au_sbbot(sb) < n) { ++ errorfc(fc, "out of bounds, %d", bindex); ++ goto out_root; ++ } ++ ++ err = 0; ++ mod->perm = au_br_perm_val(p); ++ AuDbg("mod path %s, perm 0x%x, %s\n", ++ mod->path, mod->perm, p); ++ mod->h_root = dget(au_h_dptr(root, bindex)); ++ ++out_root: ++ aufs_read_unlock(root, !AuLock_IR); ++out: ++ AuTraceErr(err); ++ return err; ++} ++#endif ++ ++static int au_fsctx_parse_xino(struct fs_context *fc, ++ struct au_opt_xino *xino, ++ struct fs_parameter *param) ++{ ++ int err; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ err = -ENOMEM; ++ /* will be freed by au_opts_free() */ ++ xino->path = kmemdup_nul(param->string, param->size, GFP_NOFS); ++ if (unlikely(!xino->path)) ++ goto out; ++ AuDbg("path %s\n", xino->path); ++ ++ xino->file = au_xino_create(a->sb, xino->path, /*silent*/0, ++ /*wbrtop*/0); ++ err = PTR_ERR(xino->file); ++ if (IS_ERR(xino->file)) { ++ xino->file = NULL; ++ goto out; ++ } ++ ++ err = 0; ++ if (unlikely(a->sb && xino->file->f_path.dentry->d_sb == a->sb)) { ++ err = -EINVAL; ++ errorfc(fc, "%s must be outside", xino->path); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static ++int au_fsctx_parse_xino_itrunc_path(struct fs_context *fc, ++ struct au_opt_xino_itrunc *xino_itrunc, ++ char *pathname) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct path path; ++ struct dentry *root; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ AuDebugOn(!a->sb); ++ ++ err = vfsub_kern_path(pathname, AuOpt_LkupDirFlags, &path); ++ if (unlikely(err)) { ++ errorfc(fc, "lookup failed %s (%d)", pathname, err); ++ goto out; ++ } ++ ++ xino_itrunc->bindex = -1; ++ root = a->sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ bbot = au_sbbot(a->sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ if (au_h_dptr(root, bindex) == path.dentry) { ++ xino_itrunc->bindex = bindex; ++ break; ++ } ++ } ++ aufs_read_unlock(root, !AuLock_IR); ++ path_put(&path); ++ ++ if (unlikely(xino_itrunc->bindex < 0)) { ++ err = -EINVAL; ++ errorfc(fc, "no such branch %s", pathname); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_fsctx_parse_xino_itrunc(struct fs_context *fc, ++ struct au_opt_xino_itrunc *xino_itrunc, ++ unsigned int bindex) ++{ ++ int err; ++ aufs_bindex_t bbot; ++ struct super_block *sb; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ sb = a->sb; ++ AuDebugOn(!sb); ++ ++ err = 0; ++ si_noflush_read_lock(sb); ++ bbot = au_sbbot(sb); ++ si_read_unlock(sb); ++ if (bindex <= bbot) ++ xino_itrunc->bindex = bindex; ++ else { ++ err = -EINVAL; ++ errorfc(fc, "out of bounds, %u", bindex); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_fsctx_parse_param(struct fs_context *fc, struct fs_parameter *param) ++{ ++ int err, token; ++ struct fs_parse_result result; ++ struct au_fsctx_opts *a = fc->fs_private; ++ struct au_opt *opt = a->opt; ++ ++ AuDbg("fc %p, param {key %s, string %s}\n", ++ fc, param->key, param->string); ++ err = fs_parse(fc, aufs_fsctx_paramspec, param, &result); ++ if (unlikely(err < 0)) ++ goto out; ++ token = err; ++ AuDbg("token %d, res{negated %d, uint64 %llu}\n", ++ token, result.negated, result.uint_64); ++ ++ err = -EINVAL; ++ a->skipped = 0; ++ switch (token) { ++ case Opt_br: ++ err = au_fsctx_parse_br(fc, param->string); ++ break; ++ case Opt_add: ++ err = au_fsctx_parse_add(fc, param->string); ++ break; ++ case Opt_append: ++ err = au_fsctx_parse_do_add(fc, opt, param->string, param->size, ++ /*dummy bindex*/1); ++ break; ++ case Opt_prepend: ++ err = au_fsctx_parse_do_add(fc, opt, param->string, param->size, ++ /*bindex*/0); ++ break; ++ ++ case Opt_del: ++ err = au_fsctx_parse_del(fc, &opt->del, param); ++ break; ++#if 0 /* reserved for future use */ ++ case Opt_idel: ++ if (!a->sb) { ++ err = 0; ++ a->skipped = 1; ++ break; ++ } ++ del->pathname = "(indexed)"; ++ err = au_opts_parse_idel(fc, &opt->del, result.uint_32); ++ break; ++#endif ++ ++ case Opt_mod: ++ err = au_fsctx_parse_mod(fc, &opt->mod, param); ++ break; ++#ifdef IMOD /* reserved for future use */ ++ case Opt_imod: ++ if (!a->sb) { ++ err = 0; ++ a->skipped = 1; ++ break; ++ } ++ u.mod->path = "(indexed)"; ++ err = au_opts_parse_imod(fc, &opt->mod, param->string); ++ break; ++#endif ++ ++ case Opt_xino: ++ err = au_fsctx_parse_xino(fc, &opt->xino, param); ++ break; ++ case Opt_trunc_xino_path: ++ if (!a->sb) { ++ errorfc(fc, "no such branch %s", param->string); ++ break; ++ } ++ err = au_fsctx_parse_xino_itrunc_path(fc, &opt->xino_itrunc, ++ param->string); ++ break; ++#if 0 ++ case Opt_trunc_xino_v: ++ if (!a->sb) { ++ err = 0; ++ a->skipped = 1; ++ break; ++ } ++ err = au_fsctx_parse_xino_itrunc_path(fc, &opt->xino_itrunc, ++ param->string); ++ break; ++#endif ++ case Opt_itrunc_xino: ++ if (!a->sb) { ++ errorfc(fc, "out of bounds %s", param->string); ++ break; ++ } ++ err = au_fsctx_parse_xino_itrunc(fc, &opt->xino_itrunc, ++ result.int_32); ++ break; ++ ++ case Opt_dirwh: ++ err = 0; ++ opt->dirwh = result.int_32; ++ break; ++ ++ case Opt_rdcache: ++ if (unlikely(result.int_32 > AUFS_RDCACHE_MAX)) { ++ errorfc(fc, "rdcache must be smaller than %d", ++ AUFS_RDCACHE_MAX); ++ break; ++ } ++ err = 0; ++ opt->rdcache = result.int_32; ++ break; ++ ++ case Opt_rdblk: ++ err = 0; ++ opt->rdblk = AUFS_RDBLK_DEF; ++ if (!strcmp(param->string, "def")) ++ break; ++ ++ err = kstrtoint(param->string, 0, &result.int_32); ++ if (unlikely(err)) { ++ errorfc(fc, "bad value in %s", param->key); ++ break; ++ } ++ err = -EINVAL; ++ if (unlikely(result.int_32 < 0 ++ || result.int_32 > KMALLOC_MAX_SIZE)) { ++ errorfc(fc, "bad value in %s", param->key); ++ break; ++ } ++ if (unlikely(result.int_32 && result.int_32 < NAME_MAX)) { ++ errorfc(fc, "rdblk must be larger than %d", NAME_MAX); ++ break; ++ } ++ err = 0; ++ opt->rdblk = result.int_32; ++ break; ++ ++ case Opt_rdhash: ++ err = 0; ++ opt->rdhash = AUFS_RDHASH_DEF; ++ if (!strcmp(param->string, "def")) ++ break; ++ ++ err = kstrtoint(param->string, 0, &result.int_32); ++ if (unlikely(err)) { ++ errorfc(fc, "bad value in %s", param->key); ++ break; ++ } ++ /* how about zero? */ ++ if (result.int_32 < 0 ++ || result.int_32 * sizeof(struct hlist_head) ++ > KMALLOC_MAX_SIZE) { ++ err = -EINVAL; ++ errorfc(fc, "bad integer in %s", param->key); ++ break; ++ } ++ opt->rdhash = result.int_32; ++ break; ++ ++ case Opt_diropq: ++ /* ++ * As other options, fs/aufs/opts.c can handle these strings by ++ * match_token(). But "diropq=" is deprecated now and will ++ * never have other value. So simple strcmp() is enough here. ++ */ ++ if (!strcmp(param->string, "a") || ++ !strcmp(param->string, "always")) { ++ err = 0; ++ opt->type = Opt_diropq_a; ++ } else if (!strcmp(param->string, "w") || ++ !strcmp(param->string, "whiteouted")) { ++ err = 0; ++ opt->type = Opt_diropq_w; ++ } else ++ errorfc(fc, "unknown value %s", param->string); ++ break; ++ ++ case Opt_udba: ++ opt->udba = au_udba_val(param->string); ++ if (opt->udba >= 0) ++ err = 0; ++ else ++ errorf(fc, "wrong value, %s", param->string); ++ break; ++ ++ case Opt_wbr_create: ++ opt->wbr_create.wbr_create ++ = au_wbr_create_val(param->string, &opt->wbr_create); ++ if (opt->wbr_create.wbr_create >= 0) ++ err = 0; ++ else ++ errorf(fc, "wrong value, %s", param->key); ++ break; ++ ++ case Opt_wbr_copyup: ++ opt->wbr_copyup = au_wbr_copyup_val(param->string); ++ if (opt->wbr_copyup >= 0) ++ err = 0; ++ else ++ errorfc(fc, "wrong value, %s", param->key); ++ break; ++ ++ case Opt_fhsm_sec: ++ if (unlikely(result.int_32 < 0)) { ++ errorfc(fc, "bad integer in %s\n", param->key); ++ break; ++ } ++ err = 0; ++ if (sysaufs_brs) ++ opt->fhsm_second = result.int_32; ++ else ++ warnfc(fc, "ignored %s %s", param->key, param->string); ++ break; ++ ++ /* simple true/false flag */ ++#define au_fsctx_TF(name) \ ++ case Opt_##name: \ ++ err = 0; \ ++ opt->tf = !result.negated; \ ++ break; ++ au_fsctx_TF(trunc_xino); ++ au_fsctx_TF(trunc_xib); ++ au_fsctx_TF(dirperm1); ++ au_fsctx_TF(plink); ++ au_fsctx_TF(shwh); ++ au_fsctx_TF(dio); ++ au_fsctx_TF(warn_perm); ++ au_fsctx_TF(verbose); ++ au_fsctx_TF(sum); ++ au_fsctx_TF(dirren); ++ au_fsctx_TF(acl); ++#undef au_fsctx_TF ++ ++ case Opt_noverbose: ++ err = 0; ++ opt->type = Opt_verbose; ++ opt->tf = false; ++ break; ++ ++ case Opt_noxino: ++ fallthrough; ++ case Opt_list_plink: ++ fallthrough; ++ case Opt_wsum: ++ err = 0; ++ break; ++ ++ case Opt_ignore: ++ warnfc(fc, "ignored %s", param->key); ++ fallthrough; ++ case Opt_ignore_silent: ++ a->skipped = 1; ++ err = 0; ++ break; ++ default: ++ a->skipped = 1; ++ err = -ENOPARAM; ++ break; ++ } ++ if (unlikely(err)) ++ goto out; ++ if (a->skipped) ++ goto out; ++ ++ switch (token) { ++ case Opt_br: ++ fallthrough; ++ case Opt_noverbose: ++ fallthrough; ++ case Opt_diropq: ++ break; ++ default: ++ opt->type = token; ++ break; ++ } ++ opt++; ++ if (unlikely(opt > a->opt_tail)) { ++ err = -E2BIG; ++ opt--; ++ } ++ opt->type = Opt_tail; ++ a->opt = opt; ++ ++out: ++ return err; ++} ++ ++/* ++ * these options accept both 'name=val' and 'name:val' form. ++ * some accept optional '=' in its value. ++ * eg. br:/br1=rw:/br2=ro and br=/br1=rw:/br2=ro ++ */ ++static inline unsigned int is_colonopt(char *str) ++{ ++#define do_test(name) \ ++ if (!strncmp(str, name ":", sizeof(name))) \ ++ return sizeof(name) - 1; ++ do_test("br"); ++ do_test("add"); ++ do_test("ins"); ++ do_test("append"); ++ do_test("prepend"); ++ do_test("del"); ++ /* do_test("idel"); */ ++ do_test("mod"); ++ /* do_test("imod"); */ ++#undef do_test ++ ++ return 0; ++} ++ ++static int au_fsctx_parse_monolithic(struct fs_context *fc, void *data) ++{ ++ int err; ++ unsigned int u; ++ char *str; ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ str = data; ++ AuDbg("str %s\n", str); ++ while (str) { ++ u = is_colonopt(str); ++ if (u) ++ str[u] = '='; ++ str = strchr(str, ','); ++ if (!str) ++ break; ++ str++; ++ } ++ str = data; ++ AuDbg("str %s\n", str); ++ ++ err = generic_parse_monolithic(fc, str); ++ AuTraceErr(err); ++ au_fsctx_dump(&a->opts); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_fsctx_opts_free(struct au_opts *opts) ++{ ++ struct au_opt *opt; ++ ++ opt = opts->opt; ++ while (opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ fallthrough; ++ case Opt_append: ++ fallthrough; ++ case Opt_prepend: ++ kfree(opt->add.pathname); ++ path_put(&opt->add.path); ++ break; ++ case Opt_del: ++ kfree(opt->del.pathname); ++ fallthrough; ++ case Opt_idel: ++ path_put(&opt->del.h_path); ++ break; ++ case Opt_mod: ++ kfree(opt->mod.path); ++ fallthrough; ++ case Opt_imod: ++ dput(opt->mod.h_root); ++ break; ++ case Opt_xino: ++ kfree(opt->xino.path); ++ fput(opt->xino.file); ++ break; ++ } ++ opt++; ++ } ++} ++ ++static void au_fsctx_free(struct fs_context *fc) ++{ ++ struct au_fsctx_opts *a = fc->fs_private; ++ ++ /* fs_type=%p, root=%pD */ ++ AuDbg("fc %p{sb_flags 0x%x, sb_flags_mask 0x%x, purpose %u\n", ++ fc, fc->sb_flags, fc->sb_flags_mask, fc->purpose); ++ ++ kobject_put(&a->sbinfo->si_kobj); ++ au_fsctx_opts_free(&a->opts); ++ free_page((unsigned long)a->opts.opt); ++ au_kfree_rcu(a); ++} ++ ++static const struct fs_context_operations au_fsctx_ops = { ++ .free = au_fsctx_free, ++ .parse_param = au_fsctx_parse_param, ++ .parse_monolithic = au_fsctx_parse_monolithic, ++ .get_tree = au_fsctx_get_tree, ++ .reconfigure = au_fsctx_reconfigure ++ /* ++ * nfs4 requires ->dup()? No. ++ * I don't know what is this ->dup() for. ++ */ ++}; ++ ++int aufs_fsctx_init(struct fs_context *fc) ++{ ++ int err; ++ struct au_fsctx_opts *a; ++ ++ /* fs_type=%p, root=%pD */ ++ AuDbg("fc %p{sb_flags 0x%x, sb_flags_mask 0x%x, purpose %u\n", ++ fc, fc->sb_flags, fc->sb_flags_mask, fc->purpose); ++ ++ /* they will be freed by au_fsctx_free() */ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ a->bindex = 0; ++ a->opts.opt = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!a->opts.opt)) ++ goto out_a; ++ a->opt = a->opts.opt; ++ a->opt->type = Opt_tail; ++ a->opts.max_opt = PAGE_SIZE / sizeof(*a->opts.opt); ++ a->opt_tail = a->opt + a->opts.max_opt - 1; ++ a->opts.sb_flags = fc->sb_flags; ++ ++ a->sb = NULL; ++ if (fc->root) { ++ AuDebugOn(fc->purpose != FS_CONTEXT_FOR_RECONFIGURE); ++ a->opts.flags = AuOpts_REMOUNT; ++ a->sb = fc->root->d_sb; ++ a->sbinfo = au_sbi(a->sb); ++ kobject_get(&a->sbinfo->si_kobj); ++ } else { ++ a->sbinfo = au_si_alloc(a->sb); ++ AuDebugOn(!a->sbinfo); ++ err = PTR_ERR(a->sbinfo); ++ if (IS_ERR(a->sbinfo)) ++ goto out_opt; ++ au_rw_write_unlock(&a->sbinfo->si_rwsem); ++ } ++ ++ err = 0; ++ fc->fs_private = a; ++ fc->ops = &au_fsctx_ops; ++ goto out; /* success */ ++ ++out_opt: ++ free_page((unsigned long)a->opts.opt); ++out_a: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff -Naur null/fs/aufs/fstype.h linux-5.15.36/fs/aufs/fstype.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/fstype.h 2022-05-10 16:51:39.871744219 +0300 +@@ -0,0 +1,401 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * judging filesystem type ++ */ ++ ++#ifndef __AUFS_FSTYPE_H__ ++#define __AUFS_FSTYPE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++ ++static inline int au_test_aufs(struct super_block *sb) ++{ ++ return sb->s_magic == AUFS_SUPER_MAGIC; ++} ++ ++static inline const char *au_sbtype(struct super_block *sb) ++{ ++ return sb->s_type->name; ++} ++ ++static inline int au_test_iso9660(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_ISO9660_FS) ++ return sb->s_magic == ISOFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_romfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_ROMFS_FS) ++ return sb->s_magic == ROMFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_cramfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_CRAMFS) ++ return sb->s_magic == CRAMFS_MAGIC; ++#endif ++ return 0; ++} ++ ++static inline int au_test_nfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_NFS_FS) ++ return sb->s_magic == NFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_fuse(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_FUSE_FS) ++ return sb->s_magic == FUSE_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_xfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_XFS_FS) ++ return sb->s_magic == XFS_SB_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_tmpfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_TMPFS ++ return sb->s_magic == TMPFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_ecryptfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_ECRYPT_FS) ++ return !strcmp(au_sbtype(sb), "ecryptfs"); ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_ramfs(struct super_block *sb) ++{ ++ return sb->s_magic == RAMFS_MAGIC; ++} ++ ++static inline int au_test_ubifs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_UBIFS_FS) ++ return sb->s_magic == UBIFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_procfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_PROC_FS ++ return sb->s_magic == PROC_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_sysfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_SYSFS ++ return sb->s_magic == SYSFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_configfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_CONFIGFS_FS) ++ return sb->s_magic == CONFIGFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_minix(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_MINIX_FS) ++ return sb->s_magic == MINIX3_SUPER_MAGIC ++ || sb->s_magic == MINIX2_SUPER_MAGIC ++ || sb->s_magic == MINIX2_SUPER_MAGIC2 ++ || sb->s_magic == MINIX_SUPER_MAGIC ++ || sb->s_magic == MINIX_SUPER_MAGIC2; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_fat(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_FAT_FS) ++ return sb->s_magic == MSDOS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_msdos(struct super_block *sb) ++{ ++ return au_test_fat(sb); ++} ++ ++static inline int au_test_vfat(struct super_block *sb) ++{ ++ return au_test_fat(sb); ++} ++ ++static inline int au_test_securityfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_SECURITYFS ++ return sb->s_magic == SECURITYFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_squashfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_SQUASHFS) ++ return sb->s_magic == SQUASHFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_btrfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_BTRFS_FS) ++ return sb->s_magic == BTRFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_xenfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_XENFS) ++ return sb->s_magic == XENFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_debugfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_DEBUG_FS ++ return sb->s_magic == DEBUGFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_nilfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_NILFS) ++ return sb->s_magic == NILFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_hfsplus(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_HFSPLUS_FS) ++ return sb->s_magic == HFSPLUS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * they can't be an aufs branch. ++ */ ++static inline int au_test_fs_unsuppoted(struct super_block *sb) ++{ ++ return ++#ifndef CONFIG_AUFS_BR_RAMFS ++ au_test_ramfs(sb) || ++#endif ++ au_test_procfs(sb) ++ || au_test_sysfs(sb) ++ || au_test_configfs(sb) ++ || au_test_debugfs(sb) ++ || au_test_securityfs(sb) ++ || au_test_xenfs(sb) ++ || au_test_ecryptfs(sb) ++ /* || !strcmp(au_sbtype(sb), "unionfs") */ ++ || au_test_aufs(sb); /* will be supported in next version */ ++} ++ ++static inline int au_test_fs_remote(struct super_block *sb) ++{ ++ return !au_test_tmpfs(sb) ++#ifdef CONFIG_AUFS_BR_RAMFS ++ && !au_test_ramfs(sb) ++#endif ++ && !(sb->s_type->fs_flags & FS_REQUIRES_DEV); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * Note: these functions (below) are created after reading ->getattr() in all ++ * filesystems under linux/fs. it means we have to do so in every update... ++ */ ++ ++/* ++ * some filesystems require getattr to refresh the inode attributes before ++ * referencing. ++ * in most cases, we can rely on the inode attribute in NFS (or every remote fs) ++ * and leave the work for d_revalidate() ++ */ ++static inline int au_test_fs_refresh_iattr(struct super_block *sb) ++{ ++ return au_test_nfs(sb) ++ || au_test_fuse(sb) ++ /* || au_test_btrfs(sb) */ /* untested */ ++ ; ++} ++ ++/* ++ * filesystems which don't maintain i_size or i_blocks. ++ */ ++static inline int au_test_fs_bad_iattr_size(struct super_block *sb) ++{ ++ return au_test_xfs(sb) ++ || au_test_btrfs(sb) ++ || au_test_ubifs(sb) ++ || au_test_hfsplus(sb) /* maintained, but incorrect */ ++ /* || au_test_minix(sb) */ /* untested */ ++ ; ++} ++ ++/* ++ * filesystems which don't store the correct value in some of their inode ++ * attributes. ++ */ ++static inline int au_test_fs_bad_iattr(struct super_block *sb) ++{ ++ return au_test_fs_bad_iattr_size(sb) ++ || au_test_fat(sb) ++ || au_test_msdos(sb) ++ || au_test_vfat(sb); ++} ++ ++/* they don't check i_nlink in link(2) */ ++static inline int au_test_fs_no_limit_nlink(struct super_block *sb) ++{ ++ return au_test_tmpfs(sb) ++#ifdef CONFIG_AUFS_BR_RAMFS ++ || au_test_ramfs(sb) ++#endif ++ || au_test_ubifs(sb) ++ || au_test_hfsplus(sb); ++} ++ ++/* ++ * filesystems which sets S_NOATIME and S_NOCMTIME. ++ */ ++static inline int au_test_fs_notime(struct super_block *sb) ++{ ++ return au_test_nfs(sb) ++ || au_test_fuse(sb) ++ || au_test_ubifs(sb) ++ ; ++} ++ ++/* temporary support for i#1 in cramfs */ ++static inline int au_test_fs_unique_ino(struct inode *inode) ++{ ++ if (au_test_cramfs(inode->i_sb)) ++ return inode->i_ino != 1; ++ return 1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * the filesystem where the xino files placed must support i/o after unlink and ++ * maintain i_size and i_blocks. ++ */ ++static inline int au_test_fs_bad_xino(struct super_block *sb) ++{ ++ return au_test_fs_remote(sb) ++ || au_test_fs_bad_iattr_size(sb) ++ /* don't want unnecessary work for xino */ ++ || au_test_aufs(sb) ++ || au_test_ecryptfs(sb) ++ || au_test_nilfs(sb); ++} ++ ++static inline int au_test_fs_trunc_xino(struct super_block *sb) ++{ ++ return au_test_tmpfs(sb) ++ || au_test_ramfs(sb); ++} ++ ++/* ++ * test if the @sb is real-readonly. ++ */ ++static inline int au_test_fs_rr(struct super_block *sb) ++{ ++ return au_test_squashfs(sb) ++ || au_test_iso9660(sb) ++ || au_test_cramfs(sb) ++ || au_test_romfs(sb); ++} ++ ++/* ++ * test if the @inode is nfs with 'noacl' option ++ * NFS always sets SB_POSIXACL regardless its mount option 'noacl.' ++ */ ++static inline int au_test_nfs_noacl(struct inode *inode) ++{ ++ return au_test_nfs(inode->i_sb) ++ /* && IS_POSIXACL(inode) */ ++ && !nfs_server_capable(inode, NFS_CAP_ACLS); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_FSTYPE_H__ */ +diff -Naur null/fs/aufs/hbl.h linux-5.15.36/fs/aufs/hbl.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/hbl.h 2022-05-10 16:51:39.871744219 +0300 +@@ -0,0 +1,65 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2017-2021 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 . ++ */ ++ ++/* ++ * helpers for hlist_bl.h ++ */ ++ ++#ifndef __AUFS_HBL_H__ ++#define __AUFS_HBL_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++static inline void au_hbl_add(struct hlist_bl_node *node, ++ struct hlist_bl_head *hbl) ++{ ++ hlist_bl_lock(hbl); ++ hlist_bl_add_head(node, hbl); ++ hlist_bl_unlock(hbl); ++} ++ ++static inline void au_hbl_del(struct hlist_bl_node *node, ++ struct hlist_bl_head *hbl) ++{ ++ hlist_bl_lock(hbl); ++ hlist_bl_del(node); ++ hlist_bl_unlock(hbl); ++} ++ ++#define au_hbl_for_each(pos, head) \ ++ for (pos = hlist_bl_first(head); \ ++ pos; \ ++ pos = pos->next) ++ ++static inline unsigned long au_hbl_count(struct hlist_bl_head *hbl) ++{ ++ unsigned long cnt; ++ struct hlist_bl_node *pos; ++ ++ cnt = 0; ++ hlist_bl_lock(hbl); ++ au_hbl_for_each(pos, hbl) ++ cnt++; ++ hlist_bl_unlock(hbl); ++ return cnt; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_HBL_H__ */ +diff -Naur null/fs/aufs/hfsnotify.c linux-5.15.36/fs/aufs/hfsnotify.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/hfsnotify.c 2022-05-10 16:51:39.871744219 +0300 +@@ -0,0 +1,288 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * fsnotify for the lower directories ++ */ ++ ++#include "aufs.h" ++ ++/* FS_IN_IGNORED is unnecessary */ ++static const __u32 AuHfsnMask = (FS_MOVED_TO | FS_MOVED_FROM | FS_DELETE ++ | FS_CREATE | FS_EVENT_ON_CHILD); ++static DECLARE_WAIT_QUEUE_HEAD(au_hfsn_wq); ++static __cacheline_aligned_in_smp atomic64_t au_hfsn_ifree = ATOMIC64_INIT(0); ++ ++static void au_hfsn_free_mark(struct fsnotify_mark *mark) ++{ ++ struct au_hnotify *hn = container_of(mark, struct au_hnotify, ++ hn_mark); ++ /* AuDbg("here\n"); */ ++ au_cache_free_hnotify(hn); ++ smp_mb__before_atomic(); /* for atomic64_dec */ ++ if (atomic64_dec_and_test(&au_hfsn_ifree)) ++ wake_up(&au_hfsn_wq); ++} ++ ++static int au_hfsn_alloc(struct au_hinode *hinode) ++{ ++ int err; ++ struct au_hnotify *hn; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct fsnotify_mark *mark; ++ aufs_bindex_t bindex; ++ ++ hn = hinode->hi_notify; ++ sb = hn->hn_aufs_inode->i_sb; ++ bindex = au_br_index(sb, hinode->hi_id); ++ br = au_sbr(sb, bindex); ++ AuDebugOn(!br->br_hfsn); ++ ++ mark = &hn->hn_mark; ++ fsnotify_init_mark(mark, br->br_hfsn->hfsn_group); ++ mark->mask = AuHfsnMask; ++ /* ++ * by udba rename or rmdir, aufs assign a new inode to the known ++ * h_inode, so specify 1 to allow dups. ++ */ ++ lockdep_off(); ++ err = fsnotify_add_inode_mark(mark, hinode->hi_inode, /*allow_dups*/1); ++ lockdep_on(); ++ ++ return err; ++} ++ ++static int au_hfsn_free(struct au_hinode *hinode, struct au_hnotify *hn) ++{ ++ struct fsnotify_mark *mark; ++ unsigned long long ull; ++ struct fsnotify_group *group; ++ ++ ull = atomic64_inc_return(&au_hfsn_ifree); ++ BUG_ON(!ull); ++ ++ mark = &hn->hn_mark; ++ spin_lock(&mark->lock); ++ group = mark->group; ++ fsnotify_get_group(group); ++ spin_unlock(&mark->lock); ++ lockdep_off(); ++ fsnotify_destroy_mark(mark, group); ++ fsnotify_put_mark(mark); ++ fsnotify_put_group(group); ++ lockdep_on(); ++ ++ /* free hn by myself */ ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_ctl(struct au_hinode *hinode, int do_set) ++{ ++ struct fsnotify_mark *mark; ++ ++ mark = &hinode->hi_notify->hn_mark; ++ spin_lock(&mark->lock); ++ if (do_set) { ++ AuDebugOn(mark->mask & AuHfsnMask); ++ mark->mask |= AuHfsnMask; ++ } else { ++ AuDebugOn(!(mark->mask & AuHfsnMask)); ++ mark->mask &= ~AuHfsnMask; ++ } ++ spin_unlock(&mark->lock); ++ /* fsnotify_recalc_inode_mask(hinode->hi_inode); */ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* #define AuDbgHnotify */ ++#ifdef AuDbgHnotify ++static char *au_hfsn_name(u32 mask) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++#define test_ret(flag) \ ++ do { \ ++ if (mask & flag) \ ++ return #flag; \ ++ } while (0) ++ test_ret(FS_ACCESS); ++ test_ret(FS_MODIFY); ++ test_ret(FS_ATTRIB); ++ test_ret(FS_CLOSE_WRITE); ++ test_ret(FS_CLOSE_NOWRITE); ++ test_ret(FS_OPEN); ++ test_ret(FS_MOVED_FROM); ++ test_ret(FS_MOVED_TO); ++ test_ret(FS_CREATE); ++ test_ret(FS_DELETE); ++ test_ret(FS_DELETE_SELF); ++ test_ret(FS_MOVE_SELF); ++ test_ret(FS_UNMOUNT); ++ test_ret(FS_Q_OVERFLOW); ++ test_ret(FS_IN_IGNORED); ++ test_ret(FS_ISDIR); ++ test_ret(FS_IN_ONESHOT); ++ test_ret(FS_EVENT_ON_CHILD); ++ return ""; ++#undef test_ret ++#else ++ return "??"; ++#endif ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_free_group(struct fsnotify_group *group) ++{ ++ struct au_br_hfsnotify *hfsn = group->private; ++ ++ /* AuDbg("here\n"); */ ++ au_kfree_try_rcu(hfsn); ++} ++ ++static int au_hfsn_handle_event(struct fsnotify_group *group, ++ u32 mask, const void *data, int data_type, ++ struct inode *dir, ++ const struct qstr *file_name, u32 cookie, ++ struct fsnotify_iter_info *iter_info) ++{ ++ int err; ++ struct au_hnotify *hnotify; ++ struct inode *h_dir, *h_inode; ++ struct fsnotify_mark *inode_mark; ++ ++ AuDebugOn(data_type != FSNOTIFY_EVENT_INODE); ++ ++ err = 0; ++ /* if FS_UNMOUNT happens, there must be another bug */ ++ AuDebugOn(mask & FS_UNMOUNT); ++ if (mask & (FS_IN_IGNORED | FS_UNMOUNT)) ++ goto out; ++ ++ h_dir = dir; ++ h_inode = NULL; ++#ifdef AuDbgHnotify ++ au_debug_on(); ++ if (1 || h_child_qstr.len != sizeof(AUFS_XINO_FNAME) - 1 ++ || strncmp(h_child_qstr.name, AUFS_XINO_FNAME, h_child_qstr.len)) { ++ AuDbg("i%lu, mask 0x%x %s, hcname %.*s, hi%lu\n", ++ h_dir->i_ino, mask, au_hfsn_name(mask), ++ AuLNPair(&h_child_qstr), h_inode ? h_inode->i_ino : 0); ++ /* WARN_ON(1); */ ++ } ++ 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, file_name, h_inode); ++ ++out: ++ return err; ++} ++ ++static struct fsnotify_ops au_hfsn_ops = { ++ .handle_event = au_hfsn_handle_event, ++ .free_group_priv = au_hfsn_free_group, ++ .free_mark = au_hfsn_free_mark ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_fin_br(struct au_branch *br) ++{ ++ struct au_br_hfsnotify *hfsn; ++ ++ hfsn = br->br_hfsn; ++ if (hfsn) { ++ lockdep_off(); ++ fsnotify_put_group(hfsn->hfsn_group); ++ lockdep_on(); ++ } ++} ++ ++static int au_hfsn_init_br(struct au_branch *br, int perm) ++{ ++ int err; ++ struct fsnotify_group *group; ++ struct au_br_hfsnotify *hfsn; ++ ++ err = 0; ++ br->br_hfsn = NULL; ++ if (!au_br_hnotifyable(perm)) ++ goto out; ++ ++ err = -ENOMEM; ++ hfsn = kmalloc(sizeof(*hfsn), GFP_NOFS); ++ if (unlikely(!hfsn)) ++ goto out; ++ ++ err = 0; ++ group = fsnotify_alloc_group(&au_hfsn_ops); ++ if (IS_ERR(group)) { ++ err = PTR_ERR(group); ++ pr_err("fsnotify_alloc_group() failed, %d\n", err); ++ goto out_hfsn; ++ } ++ ++ group->private = hfsn; ++ hfsn->hfsn_group = group; ++ br->br_hfsn = hfsn; ++ goto out; /* success */ ++ ++out_hfsn: ++ au_kfree_try_rcu(hfsn); ++out: ++ return err; ++} ++ ++static int au_hfsn_reset_br(unsigned int udba, struct au_branch *br, int perm) ++{ ++ int err; ++ ++ err = 0; ++ if (!br->br_hfsn) ++ err = au_hfsn_init_br(br, perm); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_fin(void) ++{ ++ AuDbg("au_hfsn_ifree %lld\n", (long long)atomic64_read(&au_hfsn_ifree)); ++ wait_event(au_hfsn_wq, !atomic64_read(&au_hfsn_ifree)); ++} ++ ++const struct au_hnotify_op au_hnotify_op = { ++ .ctl = au_hfsn_ctl, ++ .alloc = au_hfsn_alloc, ++ .free = au_hfsn_free, ++ ++ .fin = au_hfsn_fin, ++ ++ .reset_br = au_hfsn_reset_br, ++ .fin_br = au_hfsn_fin_br, ++ .init_br = au_hfsn_init_br ++}; +diff -Naur null/fs/aufs/hfsplus.c linux-5.15.36/fs/aufs/hfsplus.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/hfsplus.c 2022-05-10 16:51:39.872744219 +0300 +@@ -0,0 +1,60 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2021 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 . ++ */ ++ ++/* ++ * 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 ++ * 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. ++ */ ++ ++#include "aufs.h" ++ ++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, ++ int force_wr) ++{ ++ struct file *h_file; ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ AuDebugOn(!h_dentry); ++ AuDebugOn(d_is_negative(h_dentry)); ++ ++ h_file = NULL; ++ if (au_test_hfsplus(h_dentry->d_sb) ++ && d_is_reg(h_dentry)) ++ h_file = au_h_open(dentry, bindex, ++ O_RDONLY | O_NOATIME | O_LARGEFILE, ++ /*file*/NULL, force_wr); ++ return h_file; ++} ++ ++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); ++ br = au_sbr(dentry->d_sb, bindex); ++ au_lcnt_dec(&br->br_nfiles); ++ } ++} +diff -Naur null/fs/aufs/hnotify.c linux-5.15.36/fs/aufs/hnotify.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/hnotify.c 2022-05-10 16:51:39.872744219 +0300 +@@ -0,0 +1,715 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * abstraction to notify the direct changes on lower directories ++ */ ++ ++/* #include */ ++#include "aufs.h" ++ ++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode) ++{ ++ int err; ++ struct au_hnotify *hn; ++ ++ err = -ENOMEM; ++ hn = au_cache_alloc_hnotify(); ++ if (hn) { ++ hn->hn_aufs_inode = inode; ++ hinode->hi_notify = hn; ++ err = au_hnotify_op.alloc(hinode); ++ AuTraceErr(err); ++ if (unlikely(err)) { ++ hinode->hi_notify = NULL; ++ au_cache_free_hnotify(hn); ++ /* ++ * The upper dir was removed by udba, but the same named ++ * dir left. In this case, aufs assigns a new inode ++ * number and set the monitor again. ++ * For the lower dir, the old monitor is still left. ++ */ ++ if (err == -EEXIST) ++ err = 0; ++ } ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_hn_free(struct au_hinode *hinode) ++{ ++ struct au_hnotify *hn; ++ ++ hn = hinode->hi_notify; ++ if (hn) { ++ hinode->hi_notify = NULL; ++ if (au_hnotify_op.free(hinode, hn)) ++ au_cache_free_hnotify(hn); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_hn_ctl(struct au_hinode *hinode, int do_set) ++{ ++ if (hinode->hi_notify) ++ au_hnotify_op.ctl(hinode, do_set); ++} ++ ++void au_hn_reset(struct inode *inode, unsigned int flags) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct inode *hi; ++ struct dentry *iwhdentry; ++ ++ bbot = au_ibbot(inode); ++ for (bindex = au_ibtop(inode); bindex <= bbot; bindex++) { ++ hi = au_h_iptr(inode, bindex); ++ if (!hi) ++ continue; ++ ++ /* inode_lock_nested(hi, AuLsc_I_CHILD); */ ++ iwhdentry = au_hi_wh(inode, bindex); ++ if (iwhdentry) ++ dget(iwhdentry); ++ au_igrab(hi); ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ au_set_h_iptr(inode, bindex, au_igrab(hi), ++ flags & ~AuHi_XINO); ++ iput(hi); ++ dput(iwhdentry); ++ /* inode_unlock(hi); */ ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int hn_xino(struct inode *inode, struct inode *h_inode) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot, bfound, btop; ++ struct inode *h_i; ++ ++ err = 0; ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("branch root dir was changed\n"); ++ goto out; ++ } ++ ++ bfound = -1; ++ bbot = au_ibbot(inode); ++ btop = au_ibtop(inode); ++#if 0 /* reserved for future use */ ++ if (bindex == bbot) { ++ /* keep this ino in rename case */ ++ goto out; ++ } ++#endif ++ for (bindex = btop; bindex <= bbot; bindex++) ++ if (au_h_iptr(inode, bindex) == h_inode) { ++ bfound = bindex; ++ break; ++ } ++ if (bfound < 0) ++ goto out; ++ ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ h_i = au_h_iptr(inode, bindex); ++ if (!h_i) ++ continue; ++ ++ err = au_xino_write(inode->i_sb, bindex, h_i->i_ino, /*ino*/0); ++ /* ignore this error */ ++ /* bad action? */ ++ } ++ ++ /* children inode number will be broken */ ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int hn_gen_tree(struct dentry *dentry) ++{ ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, dentry, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ struct dentry *d; ++ ++ d = dentries[j]; ++ if (IS_ROOT(d)) ++ continue; ++ ++ au_digen_dec(d); ++ if (d_really_is_positive(d)) ++ /* todo: reset children xino? ++ cached children only? */ ++ au_iigen_dec(d_inode(d)); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++/* ++ * return 0 if processed. ++ */ ++static int hn_gen_by_inode(char *name, unsigned int nlen, struct inode *inode, ++ const unsigned int isdir) ++{ ++ int err; ++ struct dentry *d; ++ struct qstr *dname; ++ ++ err = 1; ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("branch root dir was changed\n"); ++ err = 0; ++ goto out; ++ } ++ ++ if (!isdir) { ++ AuDebugOn(!name); ++ au_iigen_dec(inode); ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) { ++ spin_lock(&d->d_lock); ++ dname = &d->d_name; ++ if (dname->len != nlen ++ && memcmp(dname->name, name, nlen)) { ++ spin_unlock(&d->d_lock); ++ continue; ++ } ++ err = 0; ++ au_digen_dec(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ spin_unlock(&inode->i_lock); ++ } else { ++ au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIR); ++ d = d_find_any_alias(inode); ++ if (!d) { ++ au_iigen_dec(inode); ++ goto out; ++ } ++ ++ spin_lock(&d->d_lock); ++ dname = &d->d_name; ++ if (dname->len == nlen && !memcmp(dname->name, name, nlen)) { ++ spin_unlock(&d->d_lock); ++ err = hn_gen_tree(d); ++ spin_lock(&d->d_lock); ++ } ++ spin_unlock(&d->d_lock); ++ dput(d); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int hn_gen_by_name(struct dentry *dentry, const unsigned int isdir) ++{ ++ int err; ++ ++ if (IS_ROOT(dentry)) { ++ pr_warn("branch root dir was changed\n"); ++ return 0; ++ } ++ ++ err = 0; ++ if (!isdir) { ++ au_digen_dec(dentry); ++ if (d_really_is_positive(dentry)) ++ au_iigen_dec(d_inode(dentry)); ++ } else { ++ au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR); ++ if (d_really_is_positive(dentry)) ++ err = hn_gen_tree(dentry); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* hnotify job flags */ ++#define AuHnJob_XINO0 1 ++#define AuHnJob_GEN (1 << 1) ++#define AuHnJob_DIRENT (1 << 2) ++#define AuHnJob_ISDIR (1 << 3) ++#define AuHnJob_TRYXINO0 (1 << 4) ++#define AuHnJob_MNTPNT (1 << 5) ++#define au_ftest_hnjob(flags, name) ((flags) & AuHnJob_##name) ++#define au_fset_hnjob(flags, name) \ ++ do { (flags) |= AuHnJob_##name; } while (0) ++#define au_fclr_hnjob(flags, name) \ ++ do { (flags) &= ~AuHnJob_##name; } while (0) ++ ++enum { ++ AuHn_CHILD, ++ AuHn_PARENT, ++ AuHnLast ++}; ++ ++struct au_hnotify_args { ++ struct inode *h_dir, *dir, *h_child_inode; ++ u32 mask; ++ unsigned int flags[AuHnLast]; ++ unsigned int h_child_nlen; ++ char h_child_name[]; ++}; ++ ++struct hn_job_args { ++ unsigned int flags; ++ struct inode *inode, *h_inode, *dir, *h_dir; ++ struct dentry *dentry; ++ char *h_name; ++ int h_nlen; ++}; ++ ++static int hn_job(struct hn_job_args *a) ++{ ++ const unsigned int isdir = au_ftest_hnjob(a->flags, ISDIR); ++ int e; ++ ++ /* reset xino */ ++ if (au_ftest_hnjob(a->flags, XINO0) && a->inode) ++ hn_xino(a->inode, a->h_inode); /* ignore this error */ ++ ++ if (au_ftest_hnjob(a->flags, TRYXINO0) ++ && a->inode ++ && a->h_inode) { ++ inode_lock_shared_nested(a->h_inode, AuLsc_I_CHILD); ++ if (!a->h_inode->i_nlink ++ && !(a->h_inode->i_state & I_LINKABLE)) ++ hn_xino(a->inode, a->h_inode); /* ignore this error */ ++ inode_unlock_shared(a->h_inode); ++ } ++ ++ /* make the generation obsolete */ ++ if (au_ftest_hnjob(a->flags, GEN)) { ++ e = -1; ++ if (a->inode) ++ e = hn_gen_by_inode(a->h_name, a->h_nlen, a->inode, ++ isdir); ++ if (e && a->dentry) ++ hn_gen_by_name(a->dentry, isdir); ++ /* ignore this error */ ++ } ++ ++ /* make dir entries obsolete */ ++ if (au_ftest_hnjob(a->flags, DIRENT) && a->inode) { ++ struct au_vdir *vdir; ++ ++ vdir = au_ivdir(a->inode); ++ if (vdir) ++ vdir->vd_jiffy = 0; ++ /* IMustLock(a->inode); */ ++ /* inode_inc_iversion(a->inode); */ ++ } ++ ++ /* can do nothing but warn */ ++ if (au_ftest_hnjob(a->flags, MNTPNT) ++ && a->dentry ++ && d_mountpoint(a->dentry)) ++ pr_warn("mount-point %pd is removed or renamed\n", a->dentry); ++ ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen, ++ struct inode *dir) ++{ ++ struct dentry *dentry, *d, *parent; ++ struct qstr *dname; ++ ++ parent = d_find_any_alias(dir); ++ if (!parent) ++ return NULL; ++ ++ dentry = NULL; ++ spin_lock(&parent->d_lock); ++ list_for_each_entry(d, &parent->d_subdirs, d_child) { ++ /* AuDbg("%pd\n", d); */ ++ spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); ++ dname = &d->d_name; ++ if (dname->len != nlen || memcmp(dname->name, name, nlen)) ++ goto cont_unlock; ++ if (au_di(d)) ++ au_digen_dec(d); ++ else ++ goto cont_unlock; ++ if (au_dcount(d) > 0) { ++ dentry = dget_dlock(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ ++cont_unlock: ++ spin_unlock(&d->d_lock); ++ } ++ spin_unlock(&parent->d_lock); ++ dput(parent); ++ ++ if (dentry) ++ di_write_lock_child(dentry); ++ ++ return dentry; ++} ++ ++static struct inode *lookup_wlock_by_ino(struct super_block *sb, ++ aufs_bindex_t bindex, ino_t h_ino) ++{ ++ struct inode *inode; ++ ino_t ino; ++ int err; ++ ++ inode = NULL; ++ err = au_xino_read(sb, bindex, h_ino, &ino); ++ if (!err && ino) ++ inode = ilookup(sb, ino); ++ if (!inode) ++ goto out; ++ ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("wrong root branch\n"); ++ iput(inode); ++ inode = NULL; ++ goto out; ++ } ++ ++ ii_write_lock_child(inode); ++ ++out: ++ return inode; ++} ++ ++static void au_hn_bh(void *_args) ++{ ++ struct au_hnotify_args *a = _args; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot, bfound; ++ unsigned char xino, try_iput; ++ int err; ++ struct inode *inode; ++ ino_t h_ino; ++ struct hn_job_args args; ++ struct dentry *dentry; ++ struct au_sbinfo *sbinfo; ++ ++ AuDebugOn(!_args); ++ AuDebugOn(!a->h_dir); ++ AuDebugOn(!a->dir); ++ AuDebugOn(!a->mask); ++ AuDbg("mask 0x%x, i%lu, hi%lu, hci%lu\n", ++ a->mask, a->dir->i_ino, a->h_dir->i_ino, ++ a->h_child_inode ? a->h_child_inode->i_ino : 0); ++ ++ inode = NULL; ++ dentry = NULL; ++ /* ++ * do not lock a->dir->i_mutex here ++ * because of d_revalidate() may cause a deadlock. ++ */ ++ sb = a->dir->i_sb; ++ AuDebugOn(!sb); ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!sbinfo); ++ si_write_lock(sb, AuLock_NOPLMW); ++ ++ if (au_opt_test(sbinfo->si_mntflags, DIRREN)) ++ switch (a->mask & FS_EVENTS_POSS_ON_CHILD) { ++ case FS_MOVED_FROM: ++ case FS_MOVED_TO: ++ AuWarn1("DIRREN with UDBA may not work correctly " ++ "for the direct rename(2)\n"); ++ } ++ ++ ii_read_lock_parent(a->dir); ++ bfound = -1; ++ bbot = au_ibbot(a->dir); ++ for (bindex = au_ibtop(a->dir); bindex <= bbot; bindex++) ++ if (au_h_iptr(a->dir, bindex) == a->h_dir) { ++ bfound = bindex; ++ break; ++ } ++ ii_read_unlock(a->dir); ++ if (unlikely(bfound < 0)) ++ goto out; ++ ++ xino = !!au_opt_test(au_mntflags(sb), XINO); ++ h_ino = 0; ++ if (a->h_child_inode) ++ h_ino = a->h_child_inode->i_ino; ++ ++ if (a->h_child_nlen ++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], GEN) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], MNTPNT))) ++ dentry = lookup_wlock_by_name(a->h_child_name, a->h_child_nlen, ++ a->dir); ++ try_iput = 0; ++ if (dentry && d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (xino && !inode && h_ino ++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], XINO0) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], TRYXINO0) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], GEN))) { ++ inode = lookup_wlock_by_ino(sb, bfound, h_ino); ++ try_iput = 1; ++ } ++ ++ args.flags = a->flags[AuHn_CHILD]; ++ args.dentry = dentry; ++ args.inode = inode; ++ args.h_inode = a->h_child_inode; ++ args.dir = a->dir; ++ args.h_dir = a->h_dir; ++ args.h_name = a->h_child_name; ++ args.h_nlen = a->h_child_nlen; ++ err = hn_job(&args); ++ if (dentry) { ++ if (au_di(dentry)) ++ di_write_unlock(dentry); ++ dput(dentry); ++ } ++ if (inode && try_iput) { ++ ii_write_unlock(inode); ++ iput(inode); ++ } ++ ++ ii_write_lock_parent(a->dir); ++ args.flags = a->flags[AuHn_PARENT]; ++ args.dentry = NULL; ++ args.inode = a->dir; ++ args.h_inode = a->h_dir; ++ args.dir = NULL; ++ args.h_dir = NULL; ++ args.h_name = NULL; ++ args.h_nlen = 0; ++ err = hn_job(&args); ++ ii_write_unlock(a->dir); ++ ++out: ++ iput(a->h_child_inode); ++ iput(a->h_dir); ++ iput(a->dir); ++ si_write_unlock(sb); ++ au_nwt_done(&sbinfo->si_nowait); ++ au_kfree_rcu(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, ++ const struct qstr *h_child_qstr, struct inode *h_child_inode) ++{ ++ int err, len; ++ unsigned int flags[AuHnLast], f; ++ unsigned char isdir, isroot, wh; ++ struct inode *dir; ++ struct au_hnotify_args *args; ++ char *p, *h_child_name; ++ ++ err = 0; ++ AuDebugOn(!hnotify || !hnotify->hn_aufs_inode); ++ dir = igrab(hnotify->hn_aufs_inode); ++ if (!dir) ++ goto out; ++ ++ isroot = (dir->i_ino == AUFS_ROOT_INO); ++ wh = 0; ++ h_child_name = (void *)h_child_qstr->name; ++ len = h_child_qstr->len; ++ if (h_child_name) { ++ if (len > AUFS_WH_PFX_LEN ++ && !memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ h_child_name += AUFS_WH_PFX_LEN; ++ len -= AUFS_WH_PFX_LEN; ++ wh = 1; ++ } ++ } ++ ++ isdir = 0; ++ if (h_child_inode) ++ isdir = !!S_ISDIR(h_child_inode->i_mode); ++ flags[AuHn_PARENT] = AuHnJob_ISDIR; ++ flags[AuHn_CHILD] = 0; ++ if (isdir) ++ flags[AuHn_CHILD] = AuHnJob_ISDIR; ++ au_fset_hnjob(flags[AuHn_PARENT], DIRENT); ++ au_fset_hnjob(flags[AuHn_CHILD], GEN); ++ switch (mask & ALL_FSNOTIFY_DIRENT_EVENTS) { ++ case FS_MOVED_FROM: ++ case FS_MOVED_TO: ++ au_fset_hnjob(flags[AuHn_CHILD], XINO0); ++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); ++ fallthrough; ++ case FS_CREATE: ++ AuDebugOn(!h_child_name); ++ break; ++ ++ case FS_DELETE: ++ /* ++ * aufs never be able to get this child inode. ++ * revalidation should be in d_revalidate() ++ * by checking i_nlink, i_generation or d_unhashed(). ++ */ ++ AuDebugOn(!h_child_name); ++ au_fset_hnjob(flags[AuHn_CHILD], TRYXINO0); ++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); ++ break; ++ ++ default: ++ AuDebugOn(1); ++ } ++ ++ if (wh) ++ h_child_inode = NULL; ++ ++ err = -ENOMEM; ++ /* iput() and kfree() will be called in au_hnotify() */ ++ args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS); ++ if (unlikely(!args)) { ++ AuErr1("no memory\n"); ++ iput(dir); ++ goto out; ++ } ++ args->flags[AuHn_PARENT] = flags[AuHn_PARENT]; ++ args->flags[AuHn_CHILD] = flags[AuHn_CHILD]; ++ args->mask = mask; ++ args->dir = dir; ++ args->h_dir = igrab(h_dir); ++ if (h_child_inode) ++ h_child_inode = igrab(h_child_inode); /* can be NULL */ ++ args->h_child_inode = h_child_inode; ++ args->h_child_nlen = len; ++ if (len) { ++ p = (void *)args; ++ p += sizeof(*args); ++ memcpy(p, h_child_name, len); ++ p[len] = 0; ++ } ++ ++ /* NFS fires the event for silly-renamed one from kworker */ ++ f = 0; ++ if (!dir->i_nlink ++ || (au_test_nfs(h_dir->i_sb) && (mask & FS_DELETE))) ++ f = AuWkq_NEST; ++ err = au_wkq_nowait(au_hn_bh, args, dir->i_sb, f); ++ if (unlikely(err)) { ++ pr_err("wkq %d\n", err); ++ iput(args->h_child_inode); ++ iput(args->h_dir); ++ iput(args->dir); ++ au_kfree_rcu(args); ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm) ++{ ++ int err; ++ ++ AuDebugOn(!(udba & AuOptMask_UDBA)); ++ ++ err = 0; ++ if (au_hnotify_op.reset_br) ++ err = au_hnotify_op.reset_br(udba, br, perm); ++ ++ return err; ++} ++ ++int au_hnotify_init_br(struct au_branch *br, int perm) ++{ ++ int err; ++ ++ err = 0; ++ if (au_hnotify_op.init_br) ++ err = au_hnotify_op.init_br(br, perm); ++ ++ return err; ++} ++ ++void au_hnotify_fin_br(struct au_branch *br) ++{ ++ if (au_hnotify_op.fin_br) ++ au_hnotify_op.fin_br(br); ++} ++ ++static void au_hn_destroy_cache(void) ++{ ++ kmem_cache_destroy(au_cache[AuCache_HNOTIFY]); ++ au_cache[AuCache_HNOTIFY] = NULL; ++} ++ ++int __init au_hnotify_init(void) ++{ ++ int err; ++ ++ err = -ENOMEM; ++ au_cache[AuCache_HNOTIFY] = AuCache(au_hnotify); ++ if (au_cache[AuCache_HNOTIFY]) { ++ err = 0; ++ if (au_hnotify_op.init) ++ err = au_hnotify_op.init(); ++ if (unlikely(err)) ++ au_hn_destroy_cache(); ++ } ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_hnotify_fin(void) ++{ ++ if (au_hnotify_op.fin) ++ au_hnotify_op.fin(); ++ ++ /* cf. au_cache_fin() */ ++ if (au_cache[AuCache_HNOTIFY]) ++ au_hn_destroy_cache(); ++} +diff -Naur null/fs/aufs/iinfo.c linux-5.15.36/fs/aufs/iinfo.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/iinfo.c 2022-05-10 16:51:39.873744219 +0300 +@@ -0,0 +1,286 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * inode private data ++ */ ++ ++#include "aufs.h" ++ ++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct inode *h_inode; ++ struct au_hinode *hinode; ++ ++ IiMustAnyLock(inode); ++ ++ hinode = au_hinode(au_ii(inode), bindex); ++ h_inode = hinode->hi_inode; ++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); ++ return h_inode; ++} ++ ++/* todo: hard/soft set? */ ++void au_hiput(struct au_hinode *hinode) ++{ ++ au_hn_free(hinode); ++ dput(hinode->hi_whdentry); ++ iput(hinode->hi_inode); ++} ++ ++unsigned int au_hi_flags(struct inode *inode, int isdir) ++{ ++ unsigned int flags; ++ const unsigned int mnt_flags = au_mntflags(inode->i_sb); ++ ++ flags = 0; ++ if (au_opt_test(mnt_flags, XINO)) ++ au_fset_hi(flags, XINO); ++ if (isdir && au_opt_test(mnt_flags, UDBA_HNOTIFY)) ++ au_fset_hi(flags, HNOTIFY); ++ return flags; ++} ++ ++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode, unsigned int flags) ++{ ++ struct au_hinode *hinode; ++ struct inode *hi; ++ struct au_iinfo *iinfo = au_ii(inode); ++ ++ IiMustWriteLock(inode); ++ ++ hinode = au_hinode(iinfo, bindex); ++ hi = hinode->hi_inode; ++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); ++ ++ if (hi) ++ au_hiput(hinode); ++ hinode->hi_inode = h_inode; ++ if (h_inode) { ++ int err; ++ struct super_block *sb = inode->i_sb; ++ struct au_branch *br; ++ ++ AuDebugOn(inode->i_mode ++ && (h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT)); ++ if (bindex == iinfo->ii_btop) ++ au_cpup_igen(inode, h_inode); ++ br = au_sbr(sb, bindex); ++ hinode->hi_id = br->br_id; ++ if (au_ftest_hi(flags, XINO)) { ++ err = au_xino_write(sb, bindex, h_inode->i_ino, ++ inode->i_ino); ++ if (unlikely(err)) ++ AuIOErr1("failed au_xino_write() %d\n", err); ++ } ++ ++ if (au_ftest_hi(flags, HNOTIFY) ++ && au_br_hnotifyable(br->br_perm)) { ++ err = au_hn_alloc(hinode, inode); ++ if (unlikely(err)) ++ AuIOErr1("au_hn_alloc() %d\n", err); ++ } ++ } ++} ++ ++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_wh) ++{ ++ struct au_hinode *hinode; ++ ++ IiMustWriteLock(inode); ++ ++ hinode = au_hinode(au_ii(inode), bindex); ++ AuDebugOn(hinode->hi_whdentry); ++ hinode->hi_whdentry = h_wh; ++} ++ ++void au_update_iigen(struct inode *inode, int half) ++{ ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ unsigned int sigen; ++ ++ sigen = au_sigen(inode->i_sb); ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ iigen->ig_generation = sigen; ++ if (half) ++ au_ig_fset(iigen->ig_flags, HALF_REFRESHED); ++ else ++ au_ig_fclr(iigen->ig_flags, HALF_REFRESHED); ++ spin_unlock(&iigen->ig_spin); ++} ++ ++/* it may be called at remount time, too */ ++void au_update_ibrange(struct inode *inode, int do_put_zero) ++{ ++ struct au_iinfo *iinfo; ++ aufs_bindex_t bindex, bbot; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ IiMustWriteLock(inode); ++ ++ iinfo = au_ii(inode); ++ if (do_put_zero && iinfo->ii_btop >= 0) { ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; ++ bindex++) { ++ struct inode *h_i; ++ ++ h_i = au_hinode(iinfo, bindex)->hi_inode; ++ if (h_i ++ && !h_i->i_nlink ++ && !(h_i->i_state & I_LINKABLE)) ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ } ++ } ++ ++ iinfo->ii_btop = -1; ++ iinfo->ii_bbot = -1; ++ bbot = au_sbbot(inode->i_sb); ++ for (bindex = 0; bindex <= bbot; bindex++) ++ if (au_hinode(iinfo, bindex)->hi_inode) { ++ iinfo->ii_btop = bindex; ++ break; ++ } ++ if (iinfo->ii_btop >= 0) ++ for (bindex = bbot; bindex >= iinfo->ii_btop; bindex--) ++ if (au_hinode(iinfo, bindex)->hi_inode) { ++ iinfo->ii_bbot = bindex; ++ break; ++ } ++ AuDebugOn(iinfo->ii_btop > iinfo->ii_bbot); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_icntnr_init_once(void *_c) ++{ ++ struct au_icntnr *c = _c; ++ struct au_iinfo *iinfo = &c->iinfo; ++ ++ spin_lock_init(&iinfo->ii_generation.ig_spin); ++ au_rw_init(&iinfo->ii_rwsem); ++ inode_init_once(&c->vfs_inode); ++} ++ ++void au_hinode_init(struct au_hinode *hinode) ++{ ++ hinode->hi_inode = NULL; ++ hinode->hi_id = -1; ++ au_hn_init(hinode); ++ hinode->hi_whdentry = NULL; ++} ++ ++int au_iinfo_init(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct super_block *sb; ++ struct au_hinode *hi; ++ int nbr, i; ++ ++ sb = inode->i_sb; ++ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++ nbr = au_sbbot(sb) + 1; ++ if (unlikely(nbr <= 0)) ++ nbr = 1; ++ hi = kmalloc_array(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS); ++ if (hi) { ++ au_lcnt_inc(&au_sbi(sb)->si_ninodes); ++ ++ iinfo->ii_hinode = hi; ++ for (i = 0; i < nbr; i++, hi++) ++ au_hinode_init(hi); ++ ++ iinfo->ii_generation.ig_generation = au_sigen(sb); ++ iinfo->ii_btop = -1; ++ iinfo->ii_bbot = -1; ++ iinfo->ii_vdir = NULL; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++int au_hinode_realloc(struct au_iinfo *iinfo, int nbr, int may_shrink) ++{ ++ int err, i; ++ struct au_hinode *hip; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ err = -ENOMEM; ++ hip = au_krealloc(iinfo->ii_hinode, sizeof(*hip) * nbr, GFP_NOFS, ++ may_shrink); ++ if (hip) { ++ iinfo->ii_hinode = hip; ++ i = iinfo->ii_bbot + 1; ++ hip += i; ++ for (; i < nbr; i++, hip++) ++ au_hinode_init(hip); ++ err = 0; ++ } ++ ++ return err; ++} ++ ++void au_iinfo_fin(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot; ++ const unsigned char unlinked = !inode->i_nlink; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ ++ sb = inode->i_sb; ++ au_lcnt_dec(&au_sbi(sb)->si_ninodes); ++ if (si_pid_test(sb)) ++ au_xino_delete_inode(inode, unlinked); ++ else { ++ /* ++ * it is safe to hide the dependency between sbinfo and ++ * sb->s_umount. ++ */ ++ lockdep_off(); ++ si_noflush_read_lock(sb); ++ au_xino_delete_inode(inode, unlinked); ++ si_read_unlock(sb); ++ lockdep_on(); ++ } ++ ++ iinfo = au_ii(inode); ++ if (iinfo->ii_vdir) ++ au_vdir_free(iinfo->ii_vdir); ++ ++ bindex = iinfo->ii_btop; ++ if (bindex >= 0) { ++ hi = au_hinode(iinfo, bindex); ++ bbot = iinfo->ii_bbot; ++ while (bindex++ <= bbot) { ++ if (hi->hi_inode) ++ au_hiput(hi); ++ hi++; ++ } ++ } ++ au_kfree_rcu(iinfo->ii_hinode); ++ AuRwDestroy(&iinfo->ii_rwsem); ++} +diff -Naur null/fs/aufs/inode.c linux-5.15.36/fs/aufs/inode.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/inode.c 2022-05-10 16:51:39.873744219 +0300 +@@ -0,0 +1,531 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * inode functions ++ */ ++ ++#include ++#include "aufs.h" ++ ++struct inode *au_igrab(struct inode *inode) ++{ ++ if (inode) { ++ AuDebugOn(!atomic_read(&inode->i_count)); ++ ihold(inode); ++ } ++ return inode; ++} ++ ++static void au_refresh_hinode_attr(struct inode *inode, int do_version) ++{ ++ au_cpup_attr_all(inode, /*force*/0); ++ au_update_iigen(inode, /*half*/1); ++ if (do_version) ++ inode_inc_iversion(inode); ++} ++ ++static int au_ii_refresh(struct inode *inode, int *update) ++{ ++ int err, e, nbr; ++ umode_t type; ++ aufs_bindex_t bindex, new_bindex; ++ struct super_block *sb; ++ struct au_iinfo *iinfo; ++ struct au_hinode *p, *q, tmp; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ IiMustWriteLock(inode); ++ ++ *update = 0; ++ sb = inode->i_sb; ++ nbr = au_sbbot(sb) + 1; ++ type = inode->i_mode & S_IFMT; ++ iinfo = au_ii(inode); ++ err = au_hinode_realloc(iinfo, nbr, /*may_shrink*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ AuDebugOn(iinfo->ii_btop < 0); ++ p = au_hinode(iinfo, iinfo->ii_btop); ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; ++ bindex++, p++) { ++ if (!p->hi_inode) ++ continue; ++ ++ AuDebugOn(type != (p->hi_inode->i_mode & S_IFMT)); ++ new_bindex = au_br_index(sb, p->hi_id); ++ if (new_bindex == bindex) ++ continue; ++ ++ if (new_bindex < 0) { ++ *update = 1; ++ au_hiput(p); ++ p->hi_inode = NULL; ++ continue; ++ } ++ ++ if (new_bindex < iinfo->ii_btop) ++ iinfo->ii_btop = new_bindex; ++ if (iinfo->ii_bbot < new_bindex) ++ iinfo->ii_bbot = new_bindex; ++ /* swap two lower inode, and loop again */ ++ q = au_hinode(iinfo, new_bindex); ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hi_inode) { ++ bindex--; ++ p--; ++ } ++ } ++ au_update_ibrange(inode, /*do_put_zero*/0); ++ au_hinode_realloc(iinfo, nbr, /*may_shrink*/1); /* harmless if err */ ++ e = au_dy_irefresh(inode); ++ if (unlikely(e && !err)) ++ err = e; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_refresh_iop(struct inode *inode, int force_getattr) ++{ ++ int type; ++ struct au_sbinfo *sbi = au_sbi(inode->i_sb); ++ const struct inode_operations *iop ++ = force_getattr ? aufs_iop : sbi->si_iop_array; ++ ++ if (inode->i_op == iop) ++ return; ++ ++ switch (inode->i_mode & S_IFMT) { ++ case S_IFDIR: ++ type = AuIop_DIR; ++ break; ++ case S_IFLNK: ++ type = AuIop_SYMLINK; ++ break; ++ default: ++ type = AuIop_OTHER; ++ break; ++ } ++ ++ inode->i_op = iop + type; ++ /* unnecessary smp_wmb() */ ++} ++ ++int au_refresh_hinode_self(struct inode *inode) ++{ ++ int err, update; ++ ++ err = au_ii_refresh(inode, &update); ++ if (!err) ++ au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode)); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry) ++{ ++ int err, e, update; ++ unsigned int flags; ++ umode_t mode; ++ aufs_bindex_t bindex, bbot; ++ unsigned char isdir; ++ struct au_hinode *p; ++ struct au_iinfo *iinfo; ++ ++ err = au_ii_refresh(inode, &update); ++ if (unlikely(err)) ++ goto out; ++ ++ update = 0; ++ iinfo = au_ii(inode); ++ p = au_hinode(iinfo, iinfo->ii_btop); ++ mode = (inode->i_mode & S_IFMT); ++ isdir = S_ISDIR(mode); ++ flags = au_hi_flags(inode, isdir); ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) { ++ struct inode *h_i, *h_inode; ++ struct dentry *h_d; ++ ++ h_d = au_h_dptr(dentry, bindex); ++ if (!h_d || d_is_negative(h_d)) ++ continue; ++ ++ h_inode = d_inode(h_d); ++ AuDebugOn(mode != (h_inode->i_mode & S_IFMT)); ++ if (iinfo->ii_btop <= bindex && bindex <= iinfo->ii_bbot) { ++ h_i = au_h_iptr(inode, bindex); ++ if (h_i) { ++ if (h_i == h_inode) ++ continue; ++ err = -EIO; ++ break; ++ } ++ } ++ if (bindex < iinfo->ii_btop) ++ iinfo->ii_btop = bindex; ++ if (iinfo->ii_bbot < bindex) ++ iinfo->ii_bbot = bindex; ++ au_set_h_iptr(inode, bindex, au_igrab(h_inode), flags); ++ update = 1; ++ } ++ au_update_ibrange(inode, /*do_put_zero*/0); ++ e = au_dy_irefresh(inode); ++ if (unlikely(e && !err)) ++ err = e; ++ if (!err) ++ au_refresh_hinode_attr(inode, update && isdir); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int set_inode(struct inode *inode, struct dentry *dentry) ++{ ++ int err; ++ unsigned int flags; ++ umode_t mode; ++ aufs_bindex_t bindex, btop, btail; ++ unsigned char isdir; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_iinfo *iinfo; ++ const struct inode_operations *iop; ++ ++ IiMustWriteLock(inode); ++ ++ err = 0; ++ isdir = 0; ++ iop = au_sbi(inode->i_sb)->si_iop_array; ++ btop = au_dbtop(dentry); ++ h_dentry = au_h_dptr(dentry, btop); ++ h_inode = d_inode(h_dentry); ++ mode = h_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_OTHER; ++ inode->i_fop = &aufs_file_fop; ++ err = au_dy_iaop(inode, btop, h_inode); ++ if (unlikely(err)) ++ goto out; ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ btail = au_dbtaildir(dentry); ++ inode->i_op = iop + AuIop_DIR; ++ inode->i_fop = &aufs_dir_fop; ++ break; ++ case S_IFLNK: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_SYMLINK; ++ break; ++ case S_IFBLK: ++ case S_IFCHR: ++ case S_IFIFO: ++ case S_IFSOCK: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_OTHER; ++ init_special_inode(inode, mode, h_inode->i_rdev); ++ break; ++ default: ++ AuIOErr("Unknown file type 0%o\n", mode); ++ err = -EIO; ++ goto out; ++ } ++ ++ /* do not set hnotify for whiteouted dirs (SHWH mode) */ ++ flags = au_hi_flags(inode, isdir); ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH) ++ && au_ftest_hi(flags, HNOTIFY) ++ && dentry->d_name.len > AUFS_WH_PFX_LEN ++ && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) ++ au_fclr_hi(flags, HNOTIFY); ++ iinfo = au_ii(inode); ++ iinfo->ii_btop = btop; ++ iinfo->ii_bbot = btail; ++ for (bindex = btop; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) ++ au_set_h_iptr(inode, bindex, ++ au_igrab(d_inode(h_dentry)), flags); ++ } ++ au_cpup_attr_all(inode, /*force*/1); ++ /* ++ * to force calling aufs_get_acl() every time, ++ * do not call cache_no_acl() for aufs inode. ++ */ ++ ++out: ++ return err; ++} ++ ++/* ++ * successful returns with iinfo write_locked ++ * minus: errno ++ * zero: success, matched ++ * plus: no error, but unmatched ++ */ ++static int reval_inode(struct inode *inode, struct dentry *dentry) ++{ ++ int err; ++ unsigned int gen, igflags; ++ aufs_bindex_t bindex, bbot; ++ struct inode *h_inode, *h_dinode; ++ struct dentry *h_dentry; ++ ++ /* ++ * before this function, if aufs got any iinfo lock, it must be only ++ * one, the parent dir. ++ * it can happen by UDBA and the obsoleted inode number. ++ */ ++ err = -EIO; ++ if (unlikely(inode->i_ino == parent_ino(dentry))) ++ goto out; ++ ++ err = 1; ++ ii_write_lock_new_child(inode); ++ h_dentry = au_h_dptr(dentry, au_dbtop(dentry)); ++ h_dinode = d_inode(h_dentry); ++ bbot = au_ibbot(inode); ++ for (bindex = au_ibtop(inode); bindex <= bbot; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (!h_inode || h_inode != h_dinode) ++ continue; ++ ++ err = 0; ++ gen = au_iigen(inode, &igflags); ++ if (gen == au_digen(dentry) ++ && !au_ig_ftest(igflags, HALF_REFRESHED)) ++ break; ++ ++ /* fully refresh inode using dentry */ ++ err = au_refresh_hinode(inode, dentry); ++ if (!err) ++ au_update_iigen(inode, /*half*/0); ++ break; ++ } ++ ++ if (unlikely(err)) ++ ii_write_unlock(inode); ++out: ++ return err; ++} ++ ++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ unsigned int d_type, ino_t *ino) ++{ ++ int err, idx; ++ const int isnondir = d_type != DT_DIR; ++ ++ /* prevent hardlinked inode number from race condition */ ++ if (isnondir) { ++ err = au_xinondir_enter(sb, bindex, h_ino, &idx); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ err = au_xino_read(sb, bindex, h_ino, ino); ++ if (unlikely(err)) ++ goto out_xinondir; ++ ++ if (!*ino) { ++ err = -EIO; ++ *ino = au_xino_new_ino(sb); ++ if (unlikely(!*ino)) ++ goto out_xinondir; ++ err = au_xino_write(sb, bindex, h_ino, *ino); ++ if (unlikely(err)) ++ goto out_xinondir; ++ } ++ ++out_xinondir: ++ if (isnondir && idx >= 0) ++ au_xinondir_leave(sb, bindex, h_ino, idx); ++out: ++ return err; ++} ++ ++/* successful returns with iinfo write_locked */ ++/* todo: return with unlocked? */ ++struct inode *au_new_inode(struct dentry *dentry, int must_new) ++{ ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry; ++ struct super_block *sb; ++ ino_t h_ino, ino; ++ int err, idx, hlinked; ++ aufs_bindex_t btop; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ h_dentry = au_h_dptr(dentry, btop); ++ h_inode = d_inode(h_dentry); ++ h_ino = h_inode->i_ino; ++ hlinked = !d_is_dir(h_dentry) && h_inode->i_nlink > 1; ++ ++new_ino: ++ /* ++ * stop 'race'-ing between hardlinks under different ++ * parents. ++ */ ++ if (hlinked) { ++ err = au_xinondir_enter(sb, btop, h_ino, &idx); ++ inode = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ err = au_xino_read(sb, btop, h_ino, &ino); ++ inode = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_xinondir; ++ ++ if (!ino) { ++ ino = au_xino_new_ino(sb); ++ if (unlikely(!ino)) { ++ inode = ERR_PTR(-EIO); ++ goto out_xinondir; ++ } ++ } ++ ++ AuDbg("i%lu\n", (unsigned long)ino); ++ inode = au_iget_locked(sb, ino); ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out_xinondir; ++ ++ AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW)); ++ if (inode->i_state & I_NEW) { ++ ii_write_lock_new_child(inode); ++ err = set_inode(inode, dentry); ++ if (!err) { ++ unlock_new_inode(inode); ++ goto out_xinondir; /* success */ ++ } ++ ++ /* ++ * iget_failed() calls iput(), but we need to call ++ * ii_write_unlock() after iget_failed(). so dirty hack for ++ * i_count. ++ */ ++ atomic_inc(&inode->i_count); ++ iget_failed(inode); ++ ii_write_unlock(inode); ++ au_xino_write(sb, btop, h_ino, /*ino*/0); ++ /* ignore this error */ ++ goto out_iput; ++ } else if (!must_new && !IS_DEADDIR(inode) && inode->i_nlink) { ++ /* ++ * horrible race condition between lookup, readdir and copyup ++ * (or something). ++ */ ++ if (hlinked && idx >= 0) ++ au_xinondir_leave(sb, btop, h_ino, idx); ++ err = reval_inode(inode, dentry); ++ if (unlikely(err < 0)) { ++ hlinked = 0; ++ goto out_iput; ++ } ++ if (!err) ++ goto out; /* success */ ++ else if (hlinked && idx >= 0) { ++ err = au_xinondir_enter(sb, btop, h_ino, &idx); ++ if (unlikely(err)) { ++ iput(inode); ++ inode = ERR_PTR(err); ++ goto out; ++ } ++ } ++ } ++ ++ if (unlikely(au_test_fs_unique_ino(h_inode))) ++ AuWarn1("Warning: Un-notified UDBA or repeatedly renamed dir," ++ " b%d, %s, %pd, hi%lu, i%lu.\n", ++ btop, au_sbtype(h_dentry->d_sb), dentry, ++ (unsigned long)h_ino, (unsigned long)ino); ++ ino = 0; ++ err = au_xino_write(sb, btop, h_ino, /*ino*/0); ++ if (!err) { ++ iput(inode); ++ if (hlinked && idx >= 0) ++ au_xinondir_leave(sb, btop, h_ino, idx); ++ goto new_ino; ++ } ++ ++out_iput: ++ iput(inode); ++ inode = ERR_PTR(err); ++out_xinondir: ++ if (hlinked && idx >= 0) ++ au_xinondir_leave(sb, btop, h_ino, idx); ++out: ++ return inode; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode) ++{ ++ int err; ++ struct inode *hi; ++ ++ err = au_br_rdonly(au_sbr(sb, bindex)); ++ ++ /* pseudo-link after flushed may happen out of bounds */ ++ if (!err ++ && inode ++ && au_ibtop(inode) <= bindex ++ && bindex <= au_ibbot(inode)) { ++ /* ++ * permission check is unnecessary since vfsub routine ++ * will be called later ++ */ ++ hi = au_h_iptr(inode, bindex); ++ if (hi) ++ err = IS_IMMUTABLE(hi) ? -EROFS : 0; ++ } ++ ++ return err; ++} ++ ++int au_test_h_perm(struct user_namespace *h_userns, struct inode *h_inode, ++ int mask) ++{ ++ if (uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) ++ return 0; ++ return inode_permission(h_userns, h_inode, mask); ++} ++ ++int au_test_h_perm_sio(struct user_namespace *h_userns, struct inode *h_inode, ++ int mask) ++{ ++ if (au_test_nfs(h_inode->i_sb) ++ && (mask & MAY_WRITE) ++ && S_ISDIR(h_inode->i_mode)) ++ mask |= MAY_READ; /* force permission check */ ++ return au_test_h_perm(h_userns, h_inode, mask); ++} +diff -Naur null/fs/aufs/inode.h linux-5.15.36/fs/aufs/inode.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/inode.h 2022-05-10 16:51:39.873744219 +0300 +@@ -0,0 +1,705 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * inode operations ++ */ ++ ++#ifndef __AUFS_INODE_H__ ++#define __AUFS_INODE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "rwsem.h" ++ ++struct vfsmount; ++ ++struct au_hnotify { ++#ifdef CONFIG_AUFS_HNOTIFY ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ /* never use fsnotify_add_vfsmount_mark() */ ++ struct fsnotify_mark hn_mark; ++#endif ++ struct inode *hn_aufs_inode; /* no get/put */ ++ struct rcu_head rcu; ++#endif ++} ____cacheline_aligned_in_smp; ++ ++struct au_hinode { ++ struct inode *hi_inode; ++ aufs_bindex_t hi_id; ++#ifdef CONFIG_AUFS_HNOTIFY ++ struct au_hnotify *hi_notify; ++#endif ++ ++ /* reference to the copied-up whiteout with get/put */ ++ struct dentry *hi_whdentry; ++}; ++ ++/* ig_flags */ ++#define AuIG_HALF_REFRESHED 1 ++#define au_ig_ftest(flags, name) ((flags) & AuIG_##name) ++#define au_ig_fset(flags, name) \ ++ do { (flags) |= AuIG_##name; } while (0) ++#define au_ig_fclr(flags, name) \ ++ do { (flags) &= ~AuIG_##name; } while (0) ++ ++struct au_iigen { ++ spinlock_t ig_spin; ++ __u32 ig_generation, ig_flags; ++}; ++ ++struct au_vdir; ++struct au_iinfo { ++ struct au_iigen ii_generation; ++ struct super_block *ii_hsb1; /* no get/put */ ++ ++ struct au_rwsem ii_rwsem; ++ aufs_bindex_t ii_btop, ii_bbot; ++ __u32 ii_higen; ++ struct au_hinode *ii_hinode; ++ struct au_vdir *ii_vdir; ++}; ++ ++struct au_icntnr { ++ struct au_iinfo iinfo; ++ struct inode vfs_inode; ++ struct hlist_bl_node plink; ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* au_pin flags */ ++#define AuPin_DI_LOCKED 1 ++#define AuPin_MNT_WRITE (1 << 1) ++#define au_ftest_pin(flags, name) ((flags) & AuPin_##name) ++#define au_fset_pin(flags, name) \ ++ do { (flags) |= AuPin_##name; } while (0) ++#define au_fclr_pin(flags, name) \ ++ do { (flags) &= ~AuPin_##name; } while (0) ++ ++struct au_pin { ++ /* input */ ++ struct dentry *dentry; ++ unsigned int udba; ++ unsigned char lsc_di, lsc_hi, flags; ++ aufs_bindex_t bindex; ++ ++ /* output */ ++ struct dentry *parent; ++ struct au_hinode *hdir; ++ struct vfsmount *h_mnt; ++ ++ /* temporary unlock/relock for copyup */ ++ struct dentry *h_dentry, *h_parent; ++ struct au_branch *br; ++ struct task_struct *task; ++}; ++ ++void au_pin_hdir_unlock(struct au_pin *p); ++int au_pin_hdir_lock(struct au_pin *p); ++int au_pin_hdir_relock(struct au_pin *p); ++void au_pin_hdir_acquire_nest(struct au_pin *p); ++void au_pin_hdir_release(struct au_pin *p); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_iinfo *au_ii(struct inode *inode) ++{ ++ BUG_ON(is_bad_inode(inode)); ++ return &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* inode.c */ ++struct inode *au_igrab(struct inode *inode); ++void au_refresh_iop(struct inode *inode, int force_getattr); ++int au_refresh_hinode_self(struct inode *inode); ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry); ++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ unsigned int d_type, ino_t *ino); ++struct inode *au_new_inode(struct dentry *dentry, int must_new); ++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode); ++int au_test_h_perm(struct user_namespace *h_userns, struct inode *h_inode, ++ int mask); ++int au_test_h_perm_sio(struct user_namespace *h_userns, struct inode *h_inode, ++ int mask); ++ ++static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex, ++ ino_t h_ino, unsigned int d_type, ino_t *ino) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ return au_ino(sb, bindex, h_ino, d_type, ino); ++#else ++ return 0; ++#endif ++} ++ ++/* i_op.c */ ++enum { ++ AuIop_SYMLINK, ++ AuIop_DIR, ++ AuIop_OTHER, ++ AuIop_Last ++}; ++extern struct inode_operations aufs_iop[AuIop_Last], /* not const */ ++ aufs_iop_nogetattr[AuIop_Last]; ++ ++/* au_wr_dir flags */ ++#define AuWrDir_ADD_ENTRY 1 ++#define AuWrDir_ISDIR (1 << 1) ++#define AuWrDir_TMPFILE (1 << 2) ++#define au_ftest_wrdir(flags, name) ((flags) & AuWrDir_##name) ++#define au_fset_wrdir(flags, name) \ ++ do { (flags) |= AuWrDir_##name; } while (0) ++#define au_fclr_wrdir(flags, name) \ ++ do { (flags) &= ~AuWrDir_##name; } while (0) ++ ++struct au_wr_dir_args { ++ aufs_bindex_t force_btgt; ++ unsigned char flags; ++}; ++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, ++ struct au_wr_dir_args *args); ++ ++struct dentry *au_pinned_h_parent(struct au_pin *pin); ++void au_pin_init(struct au_pin *pin, struct dentry *dentry, ++ aufs_bindex_t bindex, int lsc_di, int lsc_hi, ++ unsigned int udba, unsigned char flags); ++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int udba, unsigned char flags) __must_check; ++int au_do_pin(struct au_pin *pin) __must_check; ++void au_unpin(struct au_pin *pin); ++int au_reval_for_attr(struct dentry *dentry, unsigned int sigen); ++ ++#define AuIcpup_DID_CPUP 1 ++#define au_ftest_icpup(flags, name) ((flags) & AuIcpup_##name) ++#define au_fset_icpup(flags, name) \ ++ do { (flags) |= AuIcpup_##name; } while (0) ++#define au_fclr_icpup(flags, name) \ ++ do { (flags) &= ~AuIcpup_##name; } while (0) ++ ++struct au_icpup_args { ++ unsigned char flags; ++ unsigned char pin_flags; ++ aufs_bindex_t btgt; ++ unsigned int udba; ++ struct au_pin pin; ++ struct path h_path; ++ struct inode *h_inode; ++}; ++ ++int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia, ++ struct au_icpup_args *a); ++ ++int au_h_path_getattr(struct dentry *dentry, struct inode *inode, int force, ++ struct path *h_path, int locked); ++ ++/* i_op_add.c */ ++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir); ++int aufs_mknod(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode, dev_t dev); ++int aufs_symlink(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, const char *symname); ++int aufs_create(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode, bool want_excl); ++struct vfsub_aopen_args; ++int au_aopen_or_create(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args); ++int aufs_tmpfile(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode); ++int aufs_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry); ++int aufs_mkdir(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode); ++ ++/* i_op_del.c */ ++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup); ++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir); ++int aufs_unlink(struct inode *dir, struct dentry *dentry); ++int aufs_rmdir(struct inode *dir, struct dentry *dentry); ++ ++/* i_op_ren.c */ ++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt); ++int aufs_rename(struct user_namespace *userns, ++ struct inode *_src_dir, struct dentry *_src_dentry, ++ struct inode *_dst_dir, struct dentry *_dst_dentry, ++ unsigned int _flags); ++ ++/* iinfo.c */ ++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex); ++void au_hiput(struct au_hinode *hinode); ++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_wh); ++unsigned int au_hi_flags(struct inode *inode, int isdir); ++ ++/* hinode flags */ ++#define AuHi_XINO 1 ++#define AuHi_HNOTIFY (1 << 1) ++#define au_ftest_hi(flags, name) ((flags) & AuHi_##name) ++#define au_fset_hi(flags, name) \ ++ do { (flags) |= AuHi_##name; } while (0) ++#define au_fclr_hi(flags, name) \ ++ do { (flags) &= ~AuHi_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_HNOTIFY ++#undef AuHi_HNOTIFY ++#define AuHi_HNOTIFY 0 ++#endif ++ ++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode, unsigned int flags); ++ ++void au_update_iigen(struct inode *inode, int half); ++void au_update_ibrange(struct inode *inode, int do_put_zero); ++ ++void au_icntnr_init_once(void *_c); ++void au_hinode_init(struct au_hinode *hinode); ++int au_iinfo_init(struct inode *inode); ++void au_iinfo_fin(struct inode *inode); ++int au_hinode_realloc(struct au_iinfo *iinfo, int nbr, int may_shrink); ++ ++#ifdef CONFIG_PROC_FS ++/* plink.c */ ++int au_plink_maint(struct super_block *sb, int flags); ++struct au_sbinfo; ++void au_plink_maint_leave(struct au_sbinfo *sbinfo); ++int au_plink_maint_enter(struct super_block *sb); ++#ifdef CONFIG_AUFS_DEBUG ++void au_plink_list(struct super_block *sb); ++#else ++AuStubVoid(au_plink_list, struct super_block *sb) ++#endif ++int au_plink_test(struct inode *inode); ++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex); ++void au_plink_append(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++void au_plink_put(struct super_block *sb, int verbose); ++void au_plink_clean(struct super_block *sb, int verbose); ++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id); ++#else ++AuStubInt0(au_plink_maint, struct super_block *sb, int flags); ++AuStubVoid(au_plink_maint_leave, struct au_sbinfo *sbinfo); ++AuStubInt0(au_plink_maint_enter, struct super_block *sb); ++AuStubVoid(au_plink_list, struct super_block *sb); ++AuStubInt0(au_plink_test, struct inode *inode); ++AuStub(struct dentry *, au_plink_lkup, return NULL, ++ struct inode *inode, aufs_bindex_t bindex); ++AuStubVoid(au_plink_append, struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++AuStubVoid(au_plink_put, struct super_block *sb, int verbose); ++AuStubVoid(au_plink_clean, struct super_block *sb, int verbose); ++AuStubVoid(au_plink_half_refresh, struct super_block *sb, aufs_bindex_t br_id); ++#endif /* CONFIG_PROC_FS */ ++ ++#ifdef CONFIG_AUFS_XATTR ++/* xattr.c */ ++int au_cpup_xattr(struct path *h_dst, struct path *h_src, int ignore_flags, ++ unsigned int verbose); ++ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size); ++void au_xattr_init(struct super_block *sb); ++#else ++AuStubInt0(au_cpup_xattr, struct path *h_dst, struct path *h_src, ++ int ignore_flags, unsigned int verbose); ++AuStubVoid(au_xattr_init, struct super_block *sb); ++#endif ++ ++#ifdef CONFIG_FS_POSIX_ACL ++struct posix_acl *aufs_get_acl(struct inode *inode, int type, bool rcu); ++int aufs_set_acl(struct user_namespace *userns, struct inode *inode, ++ struct posix_acl *acl, int type); ++#endif ++ ++#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL) ++enum { ++ AU_XATTR_SET, ++ AU_ACL_SET ++}; ++ ++struct au_sxattr { ++ int type; ++ union { ++ struct { ++ const char *name; ++ const void *value; ++ size_t size; ++ int flags; ++ } set; ++ struct { ++ struct posix_acl *acl; ++ int type; ++ } acl_set; ++ } u; ++}; ++ssize_t au_sxattr(struct dentry *dentry, struct inode *inode, ++ struct au_sxattr *arg); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for iinfo */ ++enum { ++ AuLsc_II_CHILD, /* child first */ ++ AuLsc_II_CHILD2, /* rename(2), link(2), and cpup at hnotify */ ++ AuLsc_II_CHILD3, /* copyup dirs */ ++ AuLsc_II_PARENT, /* see AuLsc_I_PARENT in vfsub.h */ ++ AuLsc_II_PARENT2, ++ AuLsc_II_PARENT3, /* copyup dirs */ ++ AuLsc_II_NEW_CHILD ++}; ++ ++/* ++ * ii_read_lock_child, ii_write_lock_child, ++ * ii_read_lock_child2, ii_write_lock_child2, ++ * ii_read_lock_child3, ii_write_lock_child3, ++ * ii_read_lock_parent, ii_write_lock_parent, ++ * ii_read_lock_parent2, ii_write_lock_parent2, ++ * ii_read_lock_parent3, ii_write_lock_parent3, ++ * ii_read_lock_new_child, ii_write_lock_new_child, ++ */ ++#define AuReadLockFunc(name, lsc) \ ++static inline void ii_read_lock_##name(struct inode *i) \ ++{ \ ++ au_rw_read_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ ++} ++ ++#define AuWriteLockFunc(name, lsc) \ ++static inline void ii_write_lock_##name(struct inode *i) \ ++{ \ ++ au_rw_write_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ ++} ++ ++#define AuRWLockFuncs(name, lsc) \ ++ AuReadLockFunc(name, lsc) \ ++ AuWriteLockFunc(name, lsc) ++ ++AuRWLockFuncs(child, CHILD); ++AuRWLockFuncs(child2, CHILD2); ++AuRWLockFuncs(child3, CHILD3); ++AuRWLockFuncs(parent, PARENT); ++AuRWLockFuncs(parent2, PARENT2); ++AuRWLockFuncs(parent3, PARENT3); ++AuRWLockFuncs(new_child, NEW_CHILD); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++#define ii_read_unlock(i) au_rw_read_unlock(&au_ii(i)->ii_rwsem) ++#define ii_write_unlock(i) au_rw_write_unlock(&au_ii(i)->ii_rwsem) ++#define ii_downgrade_lock(i) au_rw_dgrade_lock(&au_ii(i)->ii_rwsem) ++ ++#define IiMustNoWaiters(i) AuRwMustNoWaiters(&au_ii(i)->ii_rwsem) ++#define IiMustAnyLock(i) AuRwMustAnyLock(&au_ii(i)->ii_rwsem) ++#define IiMustWriteLock(i) AuRwMustWriteLock(&au_ii(i)->ii_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void au_icntnr_init(struct au_icntnr *c) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++ c->vfs_inode.i_mode = 0; ++#endif ++} ++ ++static inline unsigned int au_iigen(struct inode *inode, unsigned int *igflags) ++{ ++ unsigned int gen; ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ if (igflags) ++ *igflags = iigen->ig_flags; ++ gen = iigen->ig_generation; ++ spin_unlock(&iigen->ig_spin); ++ ++ return gen; ++} ++ ++/* tiny test for inode number */ ++/* tmpfs generation is too rough */ ++static inline int au_test_higen(struct inode *inode, struct inode *h_inode) ++{ ++ struct au_iinfo *iinfo; ++ ++ iinfo = au_ii(inode); ++ AuRwMustAnyLock(&iinfo->ii_rwsem); ++ return !(iinfo->ii_hsb1 == h_inode->i_sb ++ && iinfo->ii_higen == h_inode->i_generation); ++} ++ ++static inline void au_iigen_dec(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ iigen->ig_generation--; ++ spin_unlock(&iigen->ig_spin); ++} ++ ++static inline int au_iigen_test(struct inode *inode, unsigned int sigen) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(inode && au_iigen(inode, NULL) != sigen)) ++ err = -EIO; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_hinode *au_hinode(struct au_iinfo *iinfo, ++ aufs_bindex_t bindex) ++{ ++ return iinfo->ii_hinode + bindex; ++} ++ ++static inline int au_is_bad_inode(struct inode *inode) ++{ ++ return !!(is_bad_inode(inode) || !au_hinode(au_ii(inode), 0)); ++} ++ ++static inline aufs_bindex_t au_ii_br_id(struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_hinode(au_ii(inode), bindex)->hi_id; ++} ++ ++static inline aufs_bindex_t au_ibtop(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_btop; ++} ++ ++static inline aufs_bindex_t au_ibbot(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_bbot; ++} ++ ++static inline struct au_vdir *au_ivdir(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_vdir; ++} ++ ++static inline struct dentry *au_hi_wh(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_hinode(au_ii(inode), bindex)->hi_whdentry; ++} ++ ++static inline void au_set_ibtop(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_btop = bindex; ++} ++ ++static inline void au_set_ibbot(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_bbot = bindex; ++} ++ ++static inline void au_set_ivdir(struct inode *inode, struct au_vdir *vdir) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_vdir = vdir; ++} ++ ++static inline struct au_hinode *au_hi(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_hinode(au_ii(inode), bindex); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct dentry *au_pinned_parent(struct au_pin *pin) ++{ ++ if (pin) ++ return pin->parent; ++ return NULL; ++} ++ ++static inline struct inode *au_pinned_h_dir(struct au_pin *pin) ++{ ++ if (pin && pin->hdir) ++ return pin->hdir->hi_inode; ++ return NULL; ++} ++ ++static inline struct au_hinode *au_pinned_hdir(struct au_pin *pin) ++{ ++ if (pin) ++ return pin->hdir; ++ return NULL; ++} ++ ++static inline void au_pin_set_dentry(struct au_pin *pin, struct dentry *dentry) ++{ ++ if (pin) ++ pin->dentry = dentry; ++} ++ ++static inline void au_pin_set_parent_lflag(struct au_pin *pin, ++ unsigned char lflag) ++{ ++ if (pin) { ++ if (lflag) ++ au_fset_pin(pin->flags, DI_LOCKED); ++ else ++ au_fclr_pin(pin->flags, DI_LOCKED); ++ } ++} ++ ++#if 0 /* reserved */ ++static inline void au_pin_set_parent(struct au_pin *pin, struct dentry *parent) ++{ ++ if (pin) { ++ dput(pin->parent); ++ pin->parent = dget(parent); ++ } ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_branch; ++#ifdef CONFIG_AUFS_HNOTIFY ++struct au_hnotify_op { ++ void (*ctl)(struct au_hinode *hinode, int do_set); ++ int (*alloc)(struct au_hinode *hinode); ++ ++ /* ++ * if it returns true, the caller should free hinode->hi_notify, ++ * otherwise ->free() frees it. ++ */ ++ int (*free)(struct au_hinode *hinode, ++ struct au_hnotify *hn) __must_check; ++ ++ void (*fin)(void); ++ int (*init)(void); ++ ++ int (*reset_br)(unsigned int udba, struct au_branch *br, int perm); ++ void (*fin_br)(struct au_branch *br); ++ int (*init_br)(struct au_branch *br, int perm); ++}; ++ ++/* hnotify.c */ ++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode); ++void au_hn_free(struct au_hinode *hinode); ++void au_hn_ctl(struct au_hinode *hinode, int do_set); ++void au_hn_reset(struct inode *inode, unsigned int flags); ++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, ++ const struct qstr *h_child_qstr, struct inode *h_child_inode); ++int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm); ++int au_hnotify_init_br(struct au_branch *br, int perm); ++void au_hnotify_fin_br(struct au_branch *br); ++int __init au_hnotify_init(void); ++void au_hnotify_fin(void); ++ ++/* hfsnotify.c */ ++extern const struct au_hnotify_op au_hnotify_op; ++ ++static inline ++void au_hn_init(struct au_hinode *hinode) ++{ ++ hinode->hi_notify = NULL; ++} ++ ++static inline struct au_hnotify *au_hn(struct au_hinode *hinode) ++{ ++ return hinode->hi_notify; ++} ++ ++#else ++AuStub(int, au_hn_alloc, return -EOPNOTSUPP, ++ struct au_hinode *hinode __maybe_unused, ++ struct inode *inode __maybe_unused) ++AuStub(struct au_hnotify *, au_hn, return NULL, struct au_hinode *hinode) ++AuStubVoid(au_hn_free, struct au_hinode *hinode __maybe_unused) ++AuStubVoid(au_hn_ctl, struct au_hinode *hinode __maybe_unused, ++ int do_set __maybe_unused) ++AuStubVoid(au_hn_reset, struct inode *inode __maybe_unused, ++ unsigned int flags __maybe_unused) ++AuStubInt0(au_hnotify_reset_br, unsigned int udba __maybe_unused, ++ struct au_branch *br __maybe_unused, ++ int perm __maybe_unused) ++AuStubInt0(au_hnotify_init_br, struct au_branch *br __maybe_unused, ++ int perm __maybe_unused) ++AuStubVoid(au_hnotify_fin_br, struct au_branch *br __maybe_unused) ++AuStubInt0(__init au_hnotify_init, void) ++AuStubVoid(au_hnotify_fin, void) ++AuStubVoid(au_hn_init, struct au_hinode *hinode __maybe_unused) ++#endif /* CONFIG_AUFS_HNOTIFY */ ++ ++static inline void au_hn_suspend(struct au_hinode *hdir) ++{ ++ au_hn_ctl(hdir, /*do_set*/0); ++} ++ ++static inline void au_hn_resume(struct au_hinode *hdir) ++{ ++ au_hn_ctl(hdir, /*do_set*/1); ++} ++ ++static inline void au_hn_inode_lock(struct au_hinode *hdir) ++{ ++ inode_lock(hdir->hi_inode); ++ au_hn_suspend(hdir); ++} ++ ++static inline void au_hn_inode_lock_nested(struct au_hinode *hdir, ++ unsigned int sc __maybe_unused) ++{ ++ inode_lock_nested(hdir->hi_inode, sc); ++ au_hn_suspend(hdir); ++} ++ ++#if 0 /* unused */ ++#include "vfsub.h" ++static inline void au_hn_inode_lock_shared_nested(struct au_hinode *hdir, ++ unsigned int sc) ++{ ++ inode_lock_shared_nested(hdir->hi_inode, sc); ++ au_hn_suspend(hdir); ++} ++#endif ++ ++static inline void au_hn_inode_unlock(struct au_hinode *hdir) ++{ ++ au_hn_resume(hdir); ++ inode_unlock(hdir->hi_inode); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_INODE_H__ */ +diff -Naur null/fs/aufs/ioctl.c linux-5.15.36/fs/aufs/ioctl.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/ioctl.c 2022-05-10 16:51:39.874744219 +0300 +@@ -0,0 +1,220 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * ioctl ++ * plink-management and readdir in userspace. ++ * assist the pathconf(3) wrapper library. ++ * move-down ++ * File-based Hierarchical Storage Management. ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++static int au_wbr_fd(struct path *path, struct aufs_wbr_fd __user *arg) ++{ ++ int err, fd; ++ aufs_bindex_t wbi, bindex, bbot; ++ struct file *h_file; ++ struct super_block *sb; ++ struct dentry *root; ++ struct au_branch *br; ++ struct aufs_wbr_fd wbrfd = { ++ .oflags = au_dir_roflags, ++ .brid = -1 ++ }; ++ const int valid = O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_DIRECTORY ++ | O_NOATIME | O_CLOEXEC; ++ ++ AuDebugOn(wbrfd.oflags & ~valid); ++ ++ if (arg) { ++ err = copy_from_user(&wbrfd, arg, sizeof(wbrfd)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ goto out; ++ } ++ ++ err = -EINVAL; ++ AuDbg("wbrfd{0%o, %d}\n", wbrfd.oflags, wbrfd.brid); ++ wbrfd.oflags |= au_dir_roflags; ++ AuDbg("0%o\n", wbrfd.oflags); ++ if (unlikely(wbrfd.oflags & ~valid)) ++ goto out; ++ } ++ ++ fd = get_unused_fd_flags(0); ++ err = fd; ++ if (unlikely(fd < 0)) ++ goto out; ++ ++ h_file = ERR_PTR(-EINVAL); ++ wbi = 0; ++ br = NULL; ++ sb = path->dentry->d_sb; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_IR); ++ bbot = au_sbbot(sb); ++ if (wbrfd.brid >= 0) { ++ wbi = au_br_index(sb, wbrfd.brid); ++ if (unlikely(wbi < 0 || wbi > bbot)) ++ goto out_unlock; ++ } ++ ++ h_file = ERR_PTR(-ENOENT); ++ br = au_sbr(sb, wbi); ++ if (!au_br_writable(br->br_perm)) { ++ if (arg) ++ goto out_unlock; ++ ++ bindex = wbi + 1; ++ wbi = -1; ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm)) { ++ wbi = bindex; ++ br = au_sbr(sb, wbi); ++ break; ++ } ++ } ++ } ++ AuDbg("wbi %d\n", wbi); ++ if (wbi >= 0) ++ h_file = au_h_open(root, wbi, wbrfd.oflags, NULL, ++ /*force_wr*/0); ++ ++out_unlock: ++ aufs_read_unlock(root, AuLock_IR); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out_fd; ++ ++ au_lcnt_dec(&br->br_nfiles); /* cf. au_h_open() */ ++ fd_install(fd, h_file); ++ err = fd; ++ goto out; /* success */ ++ ++out_fd: ++ put_unused_fd(fd); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err; ++ struct dentry *dentry; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ioctl(file, cmd, arg); ++ break; ++ ++ case AUFS_CTL_WBR_FD: ++ err = au_wbr_fd(&file->f_path, (void __user *)arg); ++ break; ++ ++ case AUFS_CTL_IBUSY: ++ err = au_ibusy_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_BRINFO: ++ err = au_brinfo_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_FHSM_FD: ++ dentry = file->f_path.dentry; ++ if (IS_ROOT(dentry)) ++ err = au_fhsm_fd(dentry->d_sb, arg); ++ else ++ err = -ENOTTY; ++ break; ++ ++ default: ++ /* do not call the lower */ ++ AuDbg("0x%x\n", cmd); ++ err = -ENOTTY; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err; ++ ++ switch (cmd) { ++ case AUFS_CTL_MVDOWN: ++ err = au_mvdown(file->f_path.dentry, (void __user *)arg); ++ break; ++ ++ case AUFS_CTL_WBR_FD: ++ err = au_wbr_fd(&file->f_path, (void __user *)arg); ++ break; ++ ++ default: ++ /* do not call the lower */ ++ AuDbg("0x%x\n", cmd); ++ err = -ENOTTY; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++#ifdef CONFIG_COMPAT ++long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ long err; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_compat_ioctl(file, cmd, arg); ++ break; ++ ++ case AUFS_CTL_IBUSY: ++ err = au_ibusy_compat_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_BRINFO: ++ err = au_brinfo_compat_ioctl(file, arg); ++ break; ++ ++ default: ++ err = aufs_ioctl_dir(file, cmd, arg); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ return aufs_ioctl_nondir(file, cmd, (unsigned long)compat_ptr(arg)); ++} ++#endif +diff -Naur null/fs/aufs/i_op_add.c linux-5.15.36/fs/aufs/i_op_add.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/i_op_add.c 2022-05-10 16:51:39.872744219 +0300 +@@ -0,0 +1,941 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * inode operations (add entry) ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * final procedure of adding a new entry, except link(2). ++ * remove whiteout, instantiate, copyup the parent dir's times and size ++ * and update version. ++ * if it failed, re-create the removed whiteout. ++ */ ++static int epilog(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct dentry *dentry) ++{ ++ int err, rerr; ++ aufs_bindex_t bwh; ++ struct path h_path; ++ struct super_block *sb; ++ struct inode *inode, *h_dir; ++ struct dentry *wh; ++ ++ bwh = -1; ++ sb = dir->i_sb; ++ if (wh_dentry) { ++ h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */ ++ IMustLock(h_dir); ++ AuDebugOn(au_h_iptr(dir, bindex) != h_dir); ++ bwh = au_dbwh(dentry); ++ h_path.dentry = wh_dentry; ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, ++ dentry); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ inode = au_new_inode(dentry, /*must_new*/1); ++ if (!IS_ERR(inode)) { ++ d_instantiate(dentry, inode); ++ dir = d_inode(dentry->d_parent); /* dir inode is locked */ ++ IMustLock(dir); ++ au_dir_ts(dir, bindex); ++ inode_inc_iversion(dir); ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ return 0; /* success */ ++ } ++ ++ err = PTR_ERR(inode); ++ if (!wh_dentry) ++ goto out; ++ ++ /* revert */ ++ /* dir inode is locked */ ++ wh = au_wh_create(dentry, bwh, wh_dentry->d_parent); ++ rerr = PTR_ERR(wh); ++ if (IS_ERR(wh)) { ++ AuIOErr("%pd reverting whiteout failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } else ++ dput(wh); ++ ++out: ++ return err; ++} ++ ++static int au_d_may_add(struct dentry *dentry) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(d_unhashed(dentry))) ++ err = -ENOENT; ++ if (unlikely(d_really_is_positive(dentry))) ++ err = -EEXIST; ++ return err; ++} ++ ++/* ++ * simple tests for the adding inode operations. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir) ++{ ++ int err; ++ umode_t h_mode; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ err = -ENAMETOOLONG; ++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ goto out; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (d_really_is_negative(dentry)) { ++ err = -EEXIST; ++ if (unlikely(d_is_positive(h_dentry))) ++ goto out; ++ } else { ++ /* rename(2) case */ ++ err = -EIO; ++ if (unlikely(d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ if (unlikely(!h_inode->i_nlink)) ++ goto out; ++ ++ h_mode = h_inode->i_mode; ++ if (!isdir) { ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(h_mode))) ++ goto out; ++ } else if (unlikely(!S_ISDIR(h_mode))) { ++ err = -ENOTDIR; ++ goto out; ++ } ++ } ++ ++ err = 0; ++ /* expected parent dir is locked */ ++ if (unlikely(h_parent != h_dentry->d_parent)) ++ err = -EIO; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * initial procedure of adding a new entry. ++ * prepare writable branch and the parent dir, lock it, ++ * and lookup whiteout for the new entry. ++ */ ++static struct dentry* ++lock_hdir_lkup_wh(struct dentry *dentry, struct au_dtime *dt, ++ struct dentry *src_dentry, struct au_pin *pin, ++ struct au_wr_dir_args *wr_dir_args) ++{ ++ struct dentry *wh_dentry, *h_parent; ++ struct super_block *sb; ++ struct au_branch *br; ++ int err; ++ unsigned int udba; ++ aufs_bindex_t bcpup; ++ ++ AuDbg("%pd\n", dentry); ++ ++ err = au_wr_dir(dentry, src_dentry, wr_dir_args); ++ bcpup = err; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ udba = au_opt_udba(sb); ++ err = au_pin(pin, dentry, bcpup, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ h_parent = au_pinned_h_parent(pin); ++ if (udba != AuOpt_UDBA_NONE ++ && au_dbtop(dentry) == bcpup) ++ err = au_may_add(dentry, bcpup, h_parent, ++ au_ftest_wrdir(wr_dir_args->flags, ISDIR)); ++ else if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ err = -ENAMETOOLONG; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ br = au_sbr(sb, bcpup); ++ if (dt) { ++ struct path tmp = { ++ .dentry = h_parent, ++ .mnt = au_br_mnt(br) ++ }; ++ au_dtime_store(dt, au_pinned_parent(pin), &tmp); ++ } ++ ++ wh_dentry = NULL; ++ if (bcpup != au_dbwh(dentry)) ++ goto out; /* success */ ++ ++ /* ++ * ENAMETOOLONG here means that if we allowed create such name, then it ++ * would not be able to removed in the future. So we don't allow such ++ * name here and we don't handle ENAMETOOLONG differently here. ++ */ ++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, br); ++ ++out_unpin: ++ if (IS_ERR(wh_dentry)) ++ au_unpin(pin); ++out: ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++enum { Mknod, Symlink, Creat }; ++struct simple_arg { ++ int type; ++ union { ++ struct { ++ umode_t mode; ++ bool want_excl; ++ bool try_aopen; ++ struct vfsub_aopen_args *aopen; ++ } c; ++ struct { ++ const char *symname; ++ } s; ++ struct { ++ umode_t mode; ++ dev_t dev; ++ } m; ++ } u; ++}; ++ ++static int add_simple(struct inode *dir, struct dentry *dentry, ++ struct simple_arg *arg) ++{ ++ int err, rerr; ++ aufs_bindex_t btop; ++ 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 reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ struct path h_path; ++ struct au_wr_dir_args wr_dir_args; ++ } *a; ++ ++ AuDbg("%pd\n", dentry); ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ a->wr_dir_args.force_btgt = -1; ++ a->wr_dir_args.flags = AuWrDir_ADD_ENTRY; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ if (!try_aopen) { ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ } ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ if (!try_aopen) ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, ++ &a->pin, &a->wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ btop = au_dbtop(dentry); ++ sb = dentry->d_sb; ++ br = au_sbr(sb, btop); ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ a->h_path.mnt = au_br_mnt(br); ++ h_dir = au_pinned_h_dir(&a->pin); ++ switch (arg->type) { ++ case Creat: ++ 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); ++ 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(); ++ } ++ if (unlikely(err < 0)) ++ goto out_unpin; ++ ++ err = epilog(dir, btop, wh_dentry, dentry); ++ if (!err) ++ goto out_unpin; /* success */ ++ ++ /* revert */ ++ if (created /* && d_is_positive(a->h_path.dentry) */) { ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(h_dir, &a->h_path, /*delegated*/NULL, ++ /*force*/0); ++ if (rerr) { ++ AuIOErr("%pd revert failure(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ 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); ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++out_parent: ++ if (!try_aopen) ++ di_write_unlock(parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbtop(dentry); ++ d_drop(dentry); ++ } ++ if (!try_aopen) ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ return err; ++} ++ ++int aufs_mknod(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode, dev_t dev) ++{ ++ struct simple_arg arg = { ++ .type = Mknod, ++ .u.m = { ++ .mode = mode, ++ .dev = dev ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_symlink(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, const char *symname) ++{ ++ struct simple_arg arg = { ++ .type = Symlink, ++ .u.s.symname = symname ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_create(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode, bool want_excl) ++{ ++ struct simple_arg arg = { ++ .type = Creat, ++ .u.c = { ++ .mode = mode, ++ .want_excl = want_excl ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int au_aopen_or_create(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *aopen_args) ++{ ++ struct simple_arg arg = { ++ .type = Creat, ++ .u.c = { ++ .mode = aopen_args->create_mode, ++ .want_excl = aopen_args->open_flag & O_EXCL, ++ .try_aopen = true, ++ .aopen = aopen_args ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_tmpfile(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent, *h_dentry; ++ struct inode *h_dir, *inode; ++ struct vfsmount *h_mnt; ++ struct user_namespace *h_userns; ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = AuWrDir_TMPFILE ++ }; ++ ++ /* copy-up may happen */ ++ inode_lock(dir); ++ ++ sb = dir->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_di_init(dentry); ++ if (unlikely(err)) ++ goto out_si; ++ ++ err = -EBUSY; ++ parent = d_find_any_alias(dir); ++ AuDebugOn(!parent); ++ di_write_lock_parent(parent); ++ if (unlikely(d_inode(parent) != dir)) ++ goto out_parent; ++ ++ err = au_digen_test(parent, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ bindex = au_dbtop(parent); ++ au_set_dbtop(dentry, bindex); ++ au_set_dbbot(dentry, bindex); ++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); ++ bindex = err; ++ if (unlikely(err < 0)) ++ goto out_parent; ++ ++ err = -EOPNOTSUPP; ++ h_dir = au_h_iptr(dir, bindex); ++ if (unlikely(!h_dir->i_op->tmpfile)) ++ goto out_parent; ++ ++ h_mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mnt_want_write(h_mnt); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ h_userns = mnt_user_ns(h_mnt); ++ h_parent = au_h_dptr(parent, bindex); ++ h_dentry = vfs_tmpfile(h_userns, h_parent, mode, /*open_flag*/0); ++ if (IS_ERR(h_dentry)) { ++ err = PTR_ERR(h_dentry); ++ goto out_mnt; ++ } ++ ++ au_set_dbtop(dentry, bindex); ++ au_set_dbbot(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, dget(h_dentry)); ++ inode = au_new_inode(dentry, /*must_new*/1); ++ if (IS_ERR(inode)) { ++ err = PTR_ERR(inode); ++ au_set_h_dptr(dentry, bindex, NULL); ++ au_set_dbtop(dentry, -1); ++ au_set_dbbot(dentry, -1); ++ } else { ++ if (!inode->i_nlink) ++ set_nlink(inode, 1); ++ d_tmpfile(dentry, inode); ++ au_di(dentry)->di_tmpfile = 1; ++ ++ /* update without i_mutex */ ++ if (au_ibtop(dir) == au_dbtop(dentry)) ++ au_cpup_attr_timesizes(dir); ++ } ++ dput(h_dentry); ++ ++out_mnt: ++ vfsub_mnt_drop_write(h_mnt); ++out_parent: ++ di_write_unlock(parent); ++ dput(parent); ++ di_write_unlock(dentry); ++ if (unlikely(err)) { ++ au_di_fin(dentry); ++ dentry->d_fsdata = NULL; ++ } ++out_si: ++ si_read_unlock(sb); ++out: ++ inode_unlock(dir); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_link_args { ++ aufs_bindex_t bdst, bsrc; ++ struct au_pin pin; ++ struct path h_path; ++ struct dentry *src_parent, *parent; ++}; ++ ++static int au_cpup_before_link(struct dentry *src_dentry, ++ struct au_link_args *a) ++{ ++ int err; ++ struct dentry *h_src_dentry; ++ struct au_cp_generic cpg = { ++ .dentry = src_dentry, ++ .bdst = a->bdst, ++ .bsrc = a->bsrc, ++ .len = -1, ++ .pin = &a->pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN /* | AuCpup_KEEPLINO */ ++ }; ++ ++ di_read_lock_parent(a->src_parent, AuLock_IR); ++ err = au_test_and_cpup_dirs(src_dentry, a->bdst); ++ if (unlikely(err)) ++ goto out; ++ ++ h_src_dentry = au_h_dptr(src_dentry, a->bsrc); ++ err = au_pin(&a->pin, src_dentry, a->bdst, ++ au_opt_udba(src_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&a->pin); ++ ++out: ++ di_read_unlock(a->src_parent, AuLock_IR); ++ return err; ++} ++ ++static int au_cpup_or_link(struct dentry *src_dentry, struct dentry *dentry, ++ struct au_link_args *a) ++{ ++ int err; ++ unsigned char plink; ++ aufs_bindex_t bbot; ++ struct dentry *h_src_dentry; ++ struct inode *h_inode, *inode, *delegated; ++ struct super_block *sb; ++ struct file *h_file; ++ ++ plink = 0; ++ h_inode = NULL; ++ sb = src_dentry->d_sb; ++ inode = d_inode(src_dentry); ++ if (au_ibtop(inode) <= a->bdst) ++ h_inode = au_h_iptr(inode, a->bdst); ++ if (!h_inode || !h_inode->i_nlink) { ++ /* copyup src_dentry as the name of dentry. */ ++ bbot = au_dbbot(dentry); ++ if (bbot < a->bsrc) ++ au_set_dbbot(dentry, a->bsrc); ++ au_set_h_dptr(dentry, a->bsrc, ++ dget(au_h_dptr(src_dentry, a->bsrc))); ++ dget(a->h_path.dentry); ++ au_set_h_dptr(dentry, a->bdst, NULL); ++ AuDbg("temporary d_inode...\n"); ++ spin_lock(&dentry->d_lock); ++ dentry->d_inode = d_inode(src_dentry); /* tmp */ ++ spin_unlock(&dentry->d_lock); ++ h_file = au_h_open_pre(dentry, a->bsrc, /*force_wr*/0); ++ if (IS_ERR(h_file)) ++ err = PTR_ERR(h_file); ++ else { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->bdst, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &a->pin, ++ .flags = AuCpup_KEEPLINO ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ au_h_open_post(dentry, a->bsrc, h_file); ++ if (!err) { ++ dput(a->h_path.dentry); ++ a->h_path.dentry = au_h_dptr(dentry, a->bdst); ++ } else ++ au_set_h_dptr(dentry, a->bdst, ++ a->h_path.dentry); ++ } ++ spin_lock(&dentry->d_lock); ++ dentry->d_inode = NULL; /* restore */ ++ spin_unlock(&dentry->d_lock); ++ AuDbg("temporary d_inode...done\n"); ++ au_set_h_dptr(dentry, a->bsrc, NULL); ++ au_set_dbbot(dentry, bbot); ++ } else { ++ /* the inode of src_dentry already exists on a.bdst branch */ ++ h_src_dentry = d_find_alias(h_inode); ++ if (!h_src_dentry && au_plink_test(inode)) { ++ plink = 1; ++ h_src_dentry = au_plink_lkup(inode, a->bdst); ++ err = PTR_ERR(h_src_dentry); ++ if (IS_ERR(h_src_dentry)) ++ goto out; ++ ++ if (unlikely(d_is_negative(h_src_dentry))) { ++ dput(h_src_dentry); ++ h_src_dentry = NULL; ++ } ++ ++ } ++ if (h_src_dentry) { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ dput(h_src_dentry); ++ } else { ++ AuIOErr("no dentry found for hi%lu on b%d\n", ++ h_inode->i_ino, a->bdst); ++ err = -EIO; ++ } ++ } ++ ++ if (!err && !plink) ++ au_plink_append(inode, a->bdst, a->h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int aufs_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry) ++{ ++ int err, rerr; ++ struct au_dtime dt; ++ struct au_link_args *a; ++ struct dentry *wh_dentry, *h_src_dentry; ++ struct inode *inode, *delegated; ++ struct super_block *sb; ++ struct au_wr_dir_args wr_dir_args = { ++ /* .force_btgt = -1, */ ++ .flags = AuWrDir_ADD_ENTRY ++ }; ++ ++ IMustLock(dir); ++ inode = d_inode(src_dentry); ++ IMustLock(inode); ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ a->parent = dentry->d_parent; /* dir inode is locked */ ++ err = aufs_read_and_write_lock2(dentry, src_dentry, ++ AuLock_NOPLM | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_kfree; ++ err = au_d_linkable(src_dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ a->src_parent = dget_parent(src_dentry); ++ wr_dir_args.force_btgt = au_ibtop(inode); ++ ++ di_write_lock_parent(a->parent); ++ wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, &a->pin, ++ &wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ a->bdst = au_dbtop(dentry); ++ a->h_path.dentry = au_h_dptr(dentry, a->bdst); ++ a->h_path.mnt = au_sbr_mnt(sb, a->bdst); ++ a->bsrc = au_ibtop(inode); ++ h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); ++ if (!h_src_dentry && au_di(src_dentry)->di_tmpfile) ++ h_src_dentry = dget(au_hi_wh(inode, a->bsrc)); ++ if (!h_src_dentry) { ++ a->bsrc = au_dbtop(src_dentry); ++ h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); ++ AuDebugOn(!h_src_dentry); ++ } else if (IS_ERR(h_src_dentry)) { ++ err = PTR_ERR(h_src_dentry); ++ goto out_parent; ++ } ++ ++ /* ++ * aufs doesn't touch the credential so ++ * security_dentry_create_files_as() is unnecessary. ++ */ ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ if (a->bdst < a->bsrc ++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) ++ err = au_cpup_or_link(src_dentry, dentry, a); ++ else { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ dput(h_src_dentry); ++ } else { ++ /* ++ * copyup src_dentry to the branch we process, ++ * and then link(2) to it. ++ */ ++ dput(h_src_dentry); ++ if (a->bdst < a->bsrc ++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) { ++ au_unpin(&a->pin); ++ di_write_unlock(a->parent); ++ err = au_cpup_before_link(src_dentry, a); ++ di_write_lock_parent(a->parent); ++ if (!err) ++ err = au_pin(&a->pin, dentry, a->bdst, ++ au_opt_udba(sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_wh; ++ } ++ if (!err) { ++ h_src_dentry = au_h_dptr(src_dentry, a->bdst); ++ err = -ENOENT; ++ if (h_src_dentry && d_is_positive(h_src_dentry)) { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, ++ au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry" ++ " for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ } ++ } ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ if (wh_dentry) { ++ a->h_path.dentry = wh_dentry; ++ err = au_wh_unlink_dentry(au_pinned_h_dir(&a->pin), &a->h_path, ++ dentry); ++ if (unlikely(err)) ++ goto out_revert; ++ } ++ ++ au_dir_ts(dir, a->bdst); ++ inode_inc_iversion(dir); ++ inc_nlink(inode); ++ inode->i_ctime = dir->i_ctime; ++ d_instantiate(dentry, au_igrab(inode)); ++ if (d_unhashed(a->h_path.dentry)) ++ /* some filesystem calls d_drop() */ ++ d_drop(dentry); ++ /* some filesystems consume an inode even hardlink */ ++ au_fhsm_wrote(sb, a->bdst, /*force*/0); ++ goto out_unpin; /* success */ ++ ++out_revert: ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, ++ /*delegated*/NULL, /*force*/0); ++ if (unlikely(rerr)) { ++ AuIOErr("%pd reverting failed(%d, %d)\n", dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&dt); ++out_unpin: ++ au_unpin(&a->pin); ++out_wh: ++ dput(wh_dentry); ++out_parent: ++ di_write_unlock(a->parent); ++ dput(a->src_parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbtop(dentry); ++ d_drop(dentry); ++ } ++ aufs_read_and_write_unlock2(dentry, src_dentry); ++out_kfree: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int aufs_mkdir(struct user_namespace *userns, struct inode *dir, ++ struct dentry *dentry, umode_t mode) ++{ ++ int err, rerr; ++ aufs_bindex_t bindex; ++ unsigned char diropq; ++ struct path h_path; ++ struct dentry *wh_dentry, *parent, *opq_dentry; ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct { ++ struct au_pin pin; ++ struct au_dtime dt; ++ } *a; /* reduce the stack usage */ ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = AuWrDir_ADD_ENTRY | AuWrDir_ISDIR ++ }; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, ++ &a->pin, &wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ sb = dentry->d_sb; ++ bindex = au_dbtop(dentry); ++ h_path.dentry = au_h_dptr(dentry, bindex); ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode); ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ /* make the dir opaque */ ++ diropq = 0; ++ h_inode = d_inode(h_path.dentry); ++ if (wh_dentry ++ || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) { ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ opq_dentry = au_diropq_create(dentry, bindex); ++ inode_unlock(h_inode); ++ err = PTR_ERR(opq_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out_dir; ++ dput(opq_dentry); ++ diropq = 1; ++ } ++ ++ err = epilog(dir, bindex, wh_dentry, dentry); ++ if (!err) { ++ inc_nlink(dir); ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ if (diropq) { ++ AuLabel(revert opq); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(dentry, bindex); ++ inode_unlock(h_inode); ++ if (rerr) { ++ AuIOErr("%pd reverting diropq failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ } ++ ++out_dir: ++ AuLabel(revert dir); ++ rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path); ++ if (rerr) { ++ AuIOErr("%pd reverting dir failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&a->dt); ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++out_parent: ++ di_write_unlock(parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbtop(dentry); ++ d_drop(dentry); ++ } ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ return err; ++} +diff -Naur null/fs/aufs/i_op.c linux-5.15.36/fs/aufs/i_op.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/i_op.c 2022-05-10 16:51:39.872744219 +0300 +@@ -0,0 +1,1512 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * inode operations (except add/del/rename) ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++static int h_permission(struct inode *h_inode, int mask, ++ struct path *h_path, int brperm) ++{ ++ int err; ++ const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); ++ struct user_namespace *h_userns; ++ ++ err = -EPERM; ++ if (write_mask && IS_IMMUTABLE(h_inode)) ++ goto out; ++ ++ err = -EACCES; ++ if (((mask & MAY_EXEC) ++ && S_ISREG(h_inode->i_mode) ++ && (path_noexec(h_path) ++ || !(h_inode->i_mode & 0111)))) ++ goto out; ++ ++ /* ++ * - skip the lower fs test in the case of write to ro branch. ++ * - nfs dir permission write check is optimized, but a policy for ++ * link/rename requires a real check. ++ * - nfs always sets SB_POSIXACL regardless its mount option 'noacl.' ++ * in this case, generic_permission() returns -EOPNOTSUPP. ++ */ ++ h_userns = mnt_user_ns(h_path->mnt); ++ if ((write_mask && !au_br_writable(brperm)) ++ || (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode) ++ && write_mask && !(mask & MAY_READ)) ++ || !h_inode->i_op->permission) { ++ /* AuLabel(generic_permission); */ ++ /* AuDbg("get_acl %ps\n", h_inode->i_op->get_acl); */ ++ err = generic_permission(h_userns, h_inode, mask); ++ if (err == -EOPNOTSUPP && au_test_nfs_noacl(h_inode)) ++ err = h_inode->i_op->permission(h_userns, h_inode, ++ mask); ++ AuTraceErr(err); ++ } else { ++ /* AuLabel(h_inode->permission); */ ++ err = h_inode->i_op->permission(h_userns, h_inode, mask); ++ AuTraceErr(err); ++ } ++ ++ if (!err) ++ err = devcgroup_inode_permission(h_inode, mask); ++ if (!err) ++ err = security_inode_permission(h_inode, mask); ++ ++out: ++ return err; ++} ++ ++static int aufs_permission(struct user_namespace *userns, struct inode *inode, ++ int mask) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ const unsigned char isdir = !!S_ISDIR(inode->i_mode), ++ write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ ++ /* todo: support rcu-walk? */ ++ if (mask & MAY_NOT_BLOCK) ++ return -ECHILD; ++ ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_read_lock_child(inode); ++#if 0 /* reserved for future use */ ++ /* ++ * This test may be rather 'too much' since the test is essentially done ++ * in the aufs_lookup(). Theoretically it is possible that the inode ++ * generation doesn't match to the superblock's here. But it isn't a ++ * big deal I suppose. ++ */ ++ err = au_iigen_test(inode, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out; ++#endif ++ ++ if (!isdir ++ || write_mask ++ || au_opt_test(au_mntflags(sb), DIRPERM1)) { ++ err = au_busy_or_stale(); ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ if (unlikely(!h_inode ++ || (h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT))) ++ goto out; ++ ++ err = 0; ++ bindex = au_ibtop(inode); ++ br = au_sbr(sb, bindex); ++ err = h_permission(h_inode, mask, &br->br_path, br->br_perm); ++ if (write_mask ++ && !err ++ && !special_file(h_inode->i_mode)) { ++ /* test whether the upper writable branch exists */ ++ err = -EROFS; ++ for (; bindex >= 0; bindex--) ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = 0; ++ break; ++ } ++ } ++ goto out; ++ } ++ ++ /* non-write to dir */ ++ err = 0; ++ bbot = au_ibbot(inode); ++ for (bindex = au_ibtop(inode); !err && bindex <= bbot; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (h_inode) { ++ err = au_busy_or_stale(); ++ if (unlikely(!S_ISDIR(h_inode->i_mode))) ++ break; ++ ++ br = au_sbr(sb, bindex); ++ err = h_permission(h_inode, mask, &br->br_path, ++ br->br_perm); ++ } ++ } ++ ++out: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry, ++ unsigned int flags) ++{ ++ struct dentry *ret, *parent; ++ struct inode *inode; ++ struct super_block *sb; ++ int err, npositive; ++ ++ IMustLock(dir); ++ ++ /* todo: support rcu-walk? */ ++ ret = ERR_PTR(-ECHILD); ++ if (flags & LOOKUP_RCU) ++ goto out; ++ ++ ret = ERR_PTR(-ENAMETOOLONG); ++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ goto out; ++ ++ sb = dir->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ ret = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_di_init(dentry); ++ ret = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_si; ++ ++ inode = NULL; ++ npositive = 0; /* suppress a warning */ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_alive_dir(parent); ++ if (!err) ++ err = au_digen_test(parent, au_sigen(sb)); ++ if (!err) { ++ /* regardless LOOKUP_CREATE, always ALLOW_NEG */ ++ npositive = au_lkup_dentry(dentry, au_dbtop(parent), ++ AuLkup_ALLOW_NEG); ++ err = npositive; ++ } ++ di_read_unlock(parent, AuLock_IR); ++ ret = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out_unlock; ++ ++ if (npositive) { ++ inode = au_new_inode(dentry, /*must_new*/0); ++ if (IS_ERR(inode)) { ++ ret = (void *)inode; ++ inode = NULL; ++ goto out_unlock; ++ } ++ } ++ ++ if (inode) ++ atomic_inc(&inode->i_count); ++ ret = d_splice_alias(inode, dentry); ++#if 0 /* reserved for future use */ ++ if (unlikely(d_need_lookup(dentry))) { ++ spin_lock(&dentry->d_lock); ++ dentry->d_flags &= ~DCACHE_NEED_LOOKUP; ++ spin_unlock(&dentry->d_lock); ++ } else ++#endif ++ if (inode) { ++ if (!IS_ERR(ret)) { ++ iput(inode); ++ if (ret && ret != dentry) ++ ii_write_unlock(inode); ++ } else { ++ ii_write_unlock(inode); ++ iput(inode); ++ inode = NULL; ++ } ++ } ++ ++out_unlock: ++ di_write_unlock(dentry); ++out_si: ++ si_read_unlock(sb); ++out: ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * 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; ++}; ++ ++static int au_do_aopen(struct inode *inode, struct file *file) ++{ ++ struct hlist_bl_head *aopen; ++ struct hlist_bl_node *pos; ++ struct aopen_node *node; ++ struct au_do_open_args args = { ++ .aopen = 1, ++ .open = au_do_open_nondir ++ }; ++ ++ aopen = &au_sbi(inode->i_sb)->si_aopen; ++ hlist_bl_lock(aopen); ++ hlist_bl_for_each_entry(node, pos, aopen, hblist) ++ if (node->file == file) { ++ args.h_file = node->h_file; ++ break; ++ } ++ hlist_bl_unlock(aopen); ++ /* AuDebugOn(!args.h_file); */ ++ ++ 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 err, did_open; ++ unsigned int lkup_flags; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct dentry *parent, *d; ++ struct vfsub_aopen_args args = { ++ .open_flag = open_flag, ++ .create_mode = create_mode ++ }; ++ struct aopen_node aopen_node = { ++ .file = file ++ }; ++ ++ IMustLock(dir); ++ AuDbg("open_flag 0%o\n", open_flag); ++ AuDbgDentry(dentry); ++ ++ err = 0; ++ if (!au_di(dentry)) { ++ lkup_flags = LOOKUP_OPEN; ++ if (open_flag & O_CREAT) ++ lkup_flags |= LOOKUP_CREATE; ++ d = aufs_lookup(dir, dentry, lkup_flags); ++ if (IS_ERR(d)) { ++ err = PTR_ERR(d); ++ AuTraceErr(err); ++ goto out; ++ } else if (d) { ++ /* ++ * obsoleted dentry found. ++ * another error will be returned later. ++ */ ++ d_drop(d); ++ AuDbgDentry(d); ++ dput(d); ++ } ++ AuDbgDentry(dentry); ++ } ++ ++ if (d_is_positive(dentry) ++ || d_unhashed(dentry) ++ || d_unlinked(dentry) ++ || !(open_flag & O_CREAT)) { ++ err = au_aopen_no_open(file, dentry); ++ goto out; /* success */ ++ } ++ ++ 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 < 0)) ++ goto out_parent; ++ ++ AuDbgDentry(dentry); ++ if (d_is_positive(dentry)) { ++ err = au_aopen_no_open(file, dentry); ++ goto out_parent; /* success */ ++ } ++ ++ args.file = alloc_empty_file(file->f_flags, current_cred()); ++ err = PTR_ERR(args.file); ++ if (IS_ERR(args.file)) ++ goto out_parent; ++ ++ bindex = au_dbtop(dentry); ++ err = au_aopen_or_create(dir, dentry, &args); ++ AuTraceErr(err); ++ AuDbgFile(args.file); ++ 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); ++ if (unlikely(err < 0)) { ++ if (args.file) ++ fput(args.file); ++ goto out_sb; ++ } ++ ++ if (!did_open) ++ err = au_aopen_no_open(file, dentry); ++ else { ++ aopen_node.h_file = args.file; ++ err = au_aopen_do_open(file, dentry, &aopen_node); ++ } ++ 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: ++ AuTraceErr(err); ++ AuDbgFile(file); ++ return err; ++} ++ ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent, ++ const unsigned char add_entry, aufs_bindex_t bcpup, ++ aufs_bindex_t btop) ++{ ++ int err; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ ++ if (add_entry) ++ IMustLock(d_inode(parent)); ++ else ++ di_write_lock_parent(parent); ++ ++ err = 0; ++ if (!au_h_dptr(parent, bcpup)) { ++ if (btop > bcpup) ++ err = au_cpup_dirs(dentry, bcpup); ++ else if (btop < bcpup) ++ err = au_cpdown_dirs(dentry, bcpup); ++ else ++ BUG(); ++ } ++ if (!err && add_entry && !au_ftest_wrdir(add_entry, TMPFILE)) { ++ h_parent = au_h_dptr(parent, bcpup); ++ h_dir = d_inode(h_parent); ++ inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); ++ err = au_lkup_neg(dentry, bcpup, /*wh*/0); ++ /* todo: no unlock here */ ++ inode_unlock_shared(h_dir); ++ ++ AuDbg("bcpup %d\n", bcpup); ++ if (!err) { ++ if (d_really_is_negative(dentry)) ++ au_set_h_dptr(dentry, btop, NULL); ++ au_update_dbrange(dentry, /*do_put_zero*/0); ++ } ++ } ++ ++ if (!add_entry) ++ di_write_unlock(parent); ++ if (!err) ++ err = bcpup; /* success */ ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * decide the branch and the parent dir where we will create a new entry. ++ * returns new bindex or an error. ++ * copyup the parent dir if needed. ++ */ ++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, ++ struct au_wr_dir_args *args) ++{ ++ int err; ++ unsigned int flags; ++ aufs_bindex_t bcpup, btop, src_btop; ++ const unsigned char add_entry ++ = au_ftest_wrdir(args->flags, ADD_ENTRY) ++ | au_ftest_wrdir(args->flags, TMPFILE); ++ struct super_block *sb; ++ struct dentry *parent; ++ struct au_sbinfo *sbinfo; ++ ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ parent = dget_parent(dentry); ++ btop = au_dbtop(dentry); ++ bcpup = btop; ++ if (args->force_btgt < 0) { ++ if (src_dentry) { ++ src_btop = au_dbtop(src_dentry); ++ if (src_btop < btop) ++ bcpup = src_btop; ++ } else if (add_entry) { ++ flags = 0; ++ if (au_ftest_wrdir(args->flags, ISDIR)) ++ au_fset_wbr(flags, DIR); ++ err = AuWbrCreate(sbinfo, dentry, flags); ++ bcpup = err; ++ } ++ ++ if (bcpup < 0 || au_test_ro(sb, bcpup, d_inode(dentry))) { ++ if (add_entry) ++ err = AuWbrCopyup(sbinfo, dentry); ++ else { ++ if (!IS_ROOT(dentry)) { ++ di_read_lock_parent(parent, !AuLock_IR); ++ err = AuWbrCopyup(sbinfo, dentry); ++ di_read_unlock(parent, !AuLock_IR); ++ } else ++ err = AuWbrCopyup(sbinfo, dentry); ++ } ++ bcpup = err; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else { ++ bcpup = args->force_btgt; ++ AuDebugOn(au_test_ro(sb, bcpup, d_inode(dentry))); ++ } ++ ++ AuDbg("btop %d, bcpup %d\n", btop, bcpup); ++ err = bcpup; ++ if (bcpup == btop) ++ goto out; /* success */ ++ ++ /* copyup the new parent into the branch we process */ ++ err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, btop); ++ if (err >= 0) { ++ if (d_really_is_negative(dentry)) { ++ au_set_h_dptr(dentry, btop, NULL); ++ au_set_dbtop(dentry, bcpup); ++ au_set_dbbot(dentry, bcpup); ++ } ++ AuDebugOn(add_entry ++ && !au_ftest_wrdir(args->flags, TMPFILE) ++ && !au_h_dptr(dentry, bcpup)); ++ } ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_pin_hdir_unlock(struct au_pin *p) ++{ ++ if (p->hdir) ++ au_hn_inode_unlock(p->hdir); ++} ++ ++int au_pin_hdir_lock(struct au_pin *p) ++{ ++ int err; ++ ++ err = 0; ++ if (!p->hdir) ++ goto out; ++ ++ /* even if an error happens later, keep this lock */ ++ au_hn_inode_lock_nested(p->hdir, p->lsc_hi); ++ ++ err = -EBUSY; ++ if (unlikely(p->hdir->hi_inode != d_inode(p->h_parent))) ++ goto out; ++ ++ err = 0; ++ if (p->h_dentry) ++ err = au_h_verify(p->h_dentry, p->udba, p->hdir->hi_inode, ++ p->h_parent, p->br); ++ ++out: ++ return err; ++} ++ ++int au_pin_hdir_relock(struct au_pin *p) ++{ ++ int err, i; ++ struct inode *h_i; ++ struct dentry *h_d[] = { ++ p->h_dentry, ++ p->h_parent ++ }; ++ ++ err = au_pin_hdir_lock(p); ++ if (unlikely(err)) ++ goto out; ++ ++ for (i = 0; !err && i < sizeof(h_d)/sizeof(*h_d); i++) { ++ if (!h_d[i]) ++ continue; ++ if (d_is_positive(h_d[i])) { ++ h_i = d_inode(h_d[i]); ++ err = !h_i->i_nlink; ++ } ++ } ++ ++out: ++ return err; ++} ++ ++static void au_pin_hdir_set_owner(struct au_pin *p, struct task_struct *task) ++{ ++ atomic_long_set(&p->hdir->hi_inode->i_rwsem.owner, (long)task); ++} ++ ++void au_pin_hdir_acquire_nest(struct au_pin *p) ++{ ++ if (p->hdir) { ++ rwsem_acquire_nest(&p->hdir->hi_inode->i_rwsem.dep_map, ++ p->lsc_hi, 0, NULL, _RET_IP_); ++ au_pin_hdir_set_owner(p, current); ++ } ++} ++ ++void au_pin_hdir_release(struct au_pin *p) ++{ ++ if (p->hdir) { ++ au_pin_hdir_set_owner(p, p->task); ++ rwsem_release(&p->hdir->hi_inode->i_rwsem.dep_map, _RET_IP_); ++ } ++} ++ ++struct dentry *au_pinned_h_parent(struct au_pin *pin) ++{ ++ if (pin && pin->parent) ++ return au_h_dptr(pin->parent, pin->bindex); ++ return NULL; ++} ++ ++void au_unpin(struct au_pin *p) ++{ ++ if (p->hdir) ++ au_pin_hdir_unlock(p); ++ if (p->h_mnt && au_ftest_pin(p->flags, MNT_WRITE)) ++ vfsub_mnt_drop_write(p->h_mnt); ++ if (!p->hdir) ++ return; ++ ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ iput(p->hdir->hi_inode); ++ dput(p->parent); ++ p->parent = NULL; ++ p->hdir = NULL; ++ p->h_mnt = NULL; ++ /* do not clear p->task */ ++} ++ ++int au_do_pin(struct au_pin *p) ++{ ++ int err; ++ struct super_block *sb; ++ struct inode *h_dir; ++ ++ err = 0; ++ sb = p->dentry->d_sb; ++ p->br = au_sbr(sb, p->bindex); ++ if (IS_ROOT(p->dentry)) { ++ if (au_ftest_pin(p->flags, MNT_WRITE)) { ++ p->h_mnt = au_br_mnt(p->br); ++ err = vfsub_mnt_want_write(p->h_mnt); ++ if (unlikely(err)) { ++ au_fclr_pin(p->flags, MNT_WRITE); ++ goto out_err; ++ } ++ } ++ goto out; ++ } ++ ++ p->h_dentry = NULL; ++ if (p->bindex <= au_dbbot(p->dentry)) ++ p->h_dentry = au_h_dptr(p->dentry, p->bindex); ++ ++ p->parent = dget_parent(p->dentry); ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_lock(p->parent, AuLock_IR, p->lsc_di); ++ ++ h_dir = NULL; ++ p->h_parent = au_h_dptr(p->parent, p->bindex); ++ p->hdir = au_hi(d_inode(p->parent), p->bindex); ++ if (p->hdir) ++ h_dir = p->hdir->hi_inode; ++ ++ /* ++ * udba case, or ++ * if DI_LOCKED is not set, then p->parent may be different ++ * and h_parent can be NULL. ++ */ ++ if (unlikely(!p->hdir || !h_dir || !p->h_parent)) { ++ err = -EBUSY; ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ dput(p->parent); ++ p->parent = NULL; ++ goto out_err; ++ } ++ ++ if (au_ftest_pin(p->flags, MNT_WRITE)) { ++ p->h_mnt = au_br_mnt(p->br); ++ err = vfsub_mnt_want_write(p->h_mnt); ++ if (unlikely(err)) { ++ au_fclr_pin(p->flags, MNT_WRITE); ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ dput(p->parent); ++ p->parent = NULL; ++ goto out_err; ++ } ++ } ++ ++ au_igrab(h_dir); ++ err = au_pin_hdir_lock(p); ++ if (!err) ++ goto out; /* success */ ++ ++ au_unpin(p); ++ ++out_err: ++ pr_err("err %d\n", err); ++ err = au_busy_or_stale(); ++out: ++ return err; ++} ++ ++void au_pin_init(struct au_pin *p, struct dentry *dentry, ++ aufs_bindex_t bindex, int lsc_di, int lsc_hi, ++ unsigned int udba, unsigned char flags) ++{ ++ p->dentry = dentry; ++ p->udba = udba; ++ p->lsc_di = lsc_di; ++ p->lsc_hi = lsc_hi; ++ p->flags = flags; ++ p->bindex = bindex; ++ ++ p->parent = NULL; ++ p->hdir = NULL; ++ p->h_mnt = NULL; ++ ++ p->h_dentry = NULL; ++ p->h_parent = NULL; ++ p->br = NULL; ++ p->task = current; ++} ++ ++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int udba, unsigned char flags) ++{ ++ au_pin_init(pin, dentry, bindex, AuLsc_DI_PARENT, AuLsc_I_PARENT2, ++ udba, flags); ++ return au_do_pin(pin); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * ->setattr() and ->getattr() are called in various cases. ++ * chmod, stat: dentry is revalidated. ++ * fchmod, fstat: file and dentry are not revalidated, additionally they may be ++ * unhashed. ++ * for ->setattr(), ia->ia_file is passed from ftruncate only. ++ */ ++/* todo: consolidate with do_refresh() and simple_reval_dpath() */ ++int au_reval_for_attr(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *parent; ++ ++ err = 0; ++ if (au_digen_test(dentry, sigen)) { ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(dentry, parent); ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia, ++ struct au_icpup_args *a) ++{ ++ int err; ++ loff_t sz; ++ aufs_bindex_t btop, ibtop; ++ struct dentry *hi_wh, *parent; ++ struct inode *inode; ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = 0 ++ }; ++ ++ if (d_is_dir(dentry)) ++ au_fset_wrdir(wr_dir_args.flags, ISDIR); ++ /* plink or hi_wh() case */ ++ btop = au_dbtop(dentry); ++ inode = d_inode(dentry); ++ ibtop = au_ibtop(inode); ++ if (btop != ibtop && !au_test_ro(inode->i_sb, ibtop, inode)) ++ wr_dir_args.force_btgt = ibtop; ++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); ++ if (unlikely(err < 0)) ++ goto out; ++ a->btgt = err; ++ if (err != btop) ++ au_fset_icpup(a->flags, DID_CPUP); ++ ++ err = 0; ++ a->pin_flags = AuPin_MNT_WRITE; ++ parent = NULL; ++ if (!IS_ROOT(dentry)) { ++ au_fset_pin(a->pin_flags, DI_LOCKED); ++ parent = dget_parent(dentry); ++ di_write_lock_parent(parent); ++ } ++ ++ err = au_pin(&a->pin, dentry, a->btgt, a->udba, a->pin_flags); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ sz = -1; ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ a->h_inode = d_inode(a->h_path.dentry); ++ if (ia && (ia->ia_valid & ATTR_SIZE)) { ++ inode_lock_shared_nested(a->h_inode, AuLsc_I_CHILD); ++ if (ia->ia_size < i_size_read(a->h_inode)) ++ sz = ia->ia_size; ++ inode_unlock_shared(a->h_inode); ++ } ++ ++ hi_wh = NULL; ++ if (au_ftest_icpup(a->flags, DID_CPUP) && d_unlinked(dentry)) { ++ hi_wh = au_hi_wh(inode, a->btgt); ++ if (!hi_wh) { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->btgt, ++ .bsrc = -1, ++ .len = sz, ++ .pin = &a->pin ++ }; ++ err = au_sio_cpup_wh(&cpg, /*file*/NULL); ++ if (unlikely(err)) ++ goto out_unlock; ++ hi_wh = au_hi_wh(inode, a->btgt); ++ /* todo: revalidate hi_wh? */ ++ } ++ } ++ ++ if (parent) { ++ au_pin_set_parent_lflag(&a->pin, /*lflag*/0); ++ di_downgrade_lock(parent, AuLock_IR); ++ dput(parent); ++ parent = NULL; ++ } ++ if (!au_ftest_icpup(a->flags, DID_CPUP)) ++ goto out; /* success */ ++ ++ if (!d_unhashed(dentry)) { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->btgt, ++ .bsrc = btop, ++ .len = sz, ++ .pin = &a->pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ if (!err) ++ a->h_path.dentry = au_h_dptr(dentry, a->btgt); ++ } else if (!hi_wh) ++ a->h_path.dentry = au_h_dptr(dentry, a->btgt); ++ else ++ a->h_path.dentry = hi_wh; /* do not dget here */ ++ ++out_unlock: ++ a->h_inode = d_inode(a->h_path.dentry); ++ if (!err) ++ goto out; /* success */ ++ au_unpin(&a->pin); ++out_parent: ++ if (parent) { ++ di_write_unlock(parent); ++ dput(parent); ++ } ++out: ++ if (!err) ++ inode_lock_nested(a->h_inode, AuLsc_I_CHILD); ++ return err; ++} ++ ++static int aufs_setattr(struct user_namespace *userns, struct dentry *dentry, ++ struct iattr *ia) ++{ ++ int err; ++ struct inode *inode, *delegated; ++ struct super_block *sb; ++ struct file *file; ++ struct au_icpup_args *a; ++ struct user_namespace *h_userns; ++ ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ ++ err = setattr_prepare(userns, dentry, ia); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) ++ ia->ia_valid &= ~ATTR_MODE; ++ ++ file = NULL; ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_kfree; ++ ++ if (ia->ia_valid & ATTR_FILE) { ++ /* currently ftruncate(2) only */ ++ AuDebugOn(!d_is_reg(dentry)); ++ file = ia->ia_file; ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1, ++ /*fi_lsc*/0); ++ if (unlikely(err)) ++ goto out_si; ++ ia->ia_file = au_hf_top(file); ++ a->udba = AuOpt_UDBA_NONE; ++ } else { ++ /* fchmod() doesn't pass ia_file */ ++ a->udba = au_opt_udba(sb); ++ di_write_lock_child(dentry); ++ /* no d_unlinked(), to set UDBA_NONE for root */ ++ if (d_unhashed(dentry)) ++ a->udba = AuOpt_UDBA_NONE; ++ if (a->udba != AuOpt_UDBA_NONE) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_for_attr(dentry, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out_dentry; ++ } ++ } ++ ++ err = au_pin_and_icpup(dentry, ia, a); ++ if (unlikely(err < 0)) ++ goto out_dentry; ++ if (au_ftest_icpup(a->flags, DID_CPUP)) { ++ ia->ia_file = NULL; ++ ia->ia_valid &= ~ATTR_FILE; ++ } ++ ++ a->h_path.mnt = au_sbr_mnt(sb, a->btgt); ++ if ((ia->ia_valid & (ATTR_MODE | ATTR_CTIME)) ++ == (ATTR_MODE | ATTR_CTIME)) { ++ err = security_path_chmod(&a->h_path, ia->ia_mode); ++ if (unlikely(err)) ++ goto out_unlock; ++ } else if ((ia->ia_valid & (ATTR_UID | ATTR_GID)) ++ && (ia->ia_valid & ATTR_CTIME)) { ++ err = security_path_chown(&a->h_path, ia->ia_uid, ia->ia_gid); ++ if (unlikely(err)) ++ goto out_unlock; ++ } ++ ++ if (ia->ia_valid & ATTR_SIZE) { ++ struct file *f; ++ ++ if (ia->ia_size < i_size_read(inode)) ++ /* unmap only */ ++ truncate_setsize(inode, ia->ia_size); ++ ++ f = NULL; ++ if (ia->ia_valid & ATTR_FILE) ++ f = ia->ia_file; ++ inode_unlock(a->h_inode); ++ err = vfsub_trunc(&a->h_path, ia->ia_size, ia->ia_valid, f); ++ inode_lock_nested(a->h_inode, AuLsc_I_CHILD); ++ } else { ++ delegated = NULL; ++ while (1) { ++ err = vfsub_notify_change(&a->h_path, ia, &delegated); ++ if (delegated) { ++ err = break_deleg_wait(&delegated); ++ if (!err) ++ continue; ++ } ++ break; ++ } ++ } ++ /* ++ * regardless aufs 'acl' option setting. ++ * why don't all acl-aware fs call this func from their ->setattr()? ++ */ ++ if (!err && (ia->ia_valid & ATTR_MODE)) { ++ h_userns = mnt_user_ns(a->h_path.mnt); ++ err = vfsub_acl_chmod(h_userns, a->h_inode, ia->ia_mode); ++ } ++ if (!err) ++ au_cpup_attr_changeable(inode); ++ ++out_unlock: ++ inode_unlock(a->h_inode); ++ au_unpin(&a->pin); ++ if (unlikely(err)) ++ au_update_dbtop(dentry); ++out_dentry: ++ di_write_unlock(dentry); ++ if (file) { ++ fi_write_unlock(file); ++ ia->ia_file = file; ++ ia->ia_valid |= ATTR_FILE; ++ } ++out_si: ++ si_read_unlock(sb); ++out_kfree: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL) ++static int au_h_path_to_set_attr(struct dentry *dentry, ++ struct au_icpup_args *a, struct path *h_path) ++{ ++ int err; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ a->udba = au_opt_udba(sb); ++ /* no d_unlinked(), to set UDBA_NONE for root */ ++ if (d_unhashed(dentry)) ++ a->udba = AuOpt_UDBA_NONE; ++ if (a->udba != AuOpt_UDBA_NONE) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_for_attr(dentry, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out; ++ } ++ err = au_pin_and_icpup(dentry, /*ia*/NULL, a); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ h_path->dentry = a->h_path.dentry; ++ h_path->mnt = au_sbr_mnt(sb, a->btgt); ++ ++out: ++ return err; ++} ++ ++ssize_t au_sxattr(struct dentry *dentry, struct inode *inode, ++ struct au_sxattr *arg) ++{ ++ int err; ++ struct path h_path; ++ struct super_block *sb; ++ struct au_icpup_args *a; ++ struct inode *h_inode; ++ struct user_namespace *h_userns; ++ ++ IMustLock(inode); ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_kfree; ++ ++ h_path.dentry = NULL; /* silence gcc */ ++ di_write_lock_child(dentry); ++ err = au_h_path_to_set_attr(dentry, a, &h_path); ++ if (unlikely(err)) ++ goto out_di; ++ h_userns = mnt_user_ns(h_path.mnt); ++ ++ inode_unlock(a->h_inode); ++ switch (arg->type) { ++ case AU_XATTR_SET: ++ AuDebugOn(d_is_negative(h_path.dentry)); ++ err = vfsub_setxattr(h_userns, h_path.dentry, ++ arg->u.set.name, arg->u.set.value, ++ arg->u.set.size, arg->u.set.flags); ++ break; ++ case AU_ACL_SET: ++ err = -EOPNOTSUPP; ++ h_inode = d_inode(h_path.dentry); ++ if (h_inode->i_op->set_acl) { ++ /* this will call posix_acl_update_mode */ ++ err = h_inode->i_op->set_acl(h_userns, h_inode, ++ arg->u.acl_set.acl, ++ arg->u.acl_set.type); ++ } ++ break; ++ } ++ if (!err) ++ au_cpup_attr_timesizes(inode); ++ ++ au_unpin(&a->pin); ++ if (unlikely(err)) ++ au_update_dbtop(dentry); ++ ++out_di: ++ di_write_unlock(dentry); ++ si_read_unlock(sb); ++out_kfree: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++#endif ++ ++static void au_refresh_iattr(struct inode *inode, struct kstat *st, ++ unsigned int nlink) ++{ ++ unsigned int n; ++ ++ inode->i_mode = st->mode; ++ /* don't i_[ug]id_write() here */ ++ inode->i_uid = st->uid; ++ inode->i_gid = st->gid; ++ inode->i_atime = st->atime; ++ inode->i_mtime = st->mtime; ++ inode->i_ctime = st->ctime; ++ ++ au_cpup_attr_nlink(inode, /*force*/0); ++ if (S_ISDIR(inode->i_mode)) { ++ n = inode->i_nlink; ++ n -= nlink; ++ n += st->nlink; ++ smp_mb(); /* for i_nlink */ ++ /* 0 can happen */ ++ set_nlink(inode, n); ++ } ++ ++ spin_lock(&inode->i_lock); ++ inode->i_blocks = st->blocks; ++ i_size_write(inode, st->size); ++ spin_unlock(&inode->i_lock); ++} ++ ++/* ++ * common routine for aufs_getattr() and au_getxattr(). ++ * returns zero or negative (an error). ++ * @dentry will be read-locked in success. ++ */ ++int au_h_path_getattr(struct dentry *dentry, struct inode *inode, int force, ++ struct path *h_path, int locked) ++{ ++ int err; ++ unsigned int mnt_flags, sigen; ++ unsigned char udba_none; ++ aufs_bindex_t bindex; ++ struct super_block *sb, *h_sb; ++ ++ h_path->mnt = NULL; ++ h_path->dentry = NULL; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ mnt_flags = au_mntflags(sb); ++ udba_none = !!au_opt_test(mnt_flags, UDBA_NONE); ++ ++ if (unlikely(locked)) ++ goto body; /* skip locking dinfo */ ++ ++ /* support fstat(2) */ ++ if (!d_unlinked(dentry) && !udba_none) { ++ sigen = au_sigen(sb); ++ err = au_digen_test(dentry, sigen); ++ if (!err) { ++ di_read_lock_child(dentry, AuLock_IR); ++ err = au_dbrange_test(dentry); ++ if (unlikely(err)) { ++ di_read_unlock(dentry, AuLock_IR); ++ goto out; ++ } ++ } else { ++ AuDebugOn(IS_ROOT(dentry)); ++ di_write_lock_child(dentry); ++ err = au_dbrange_test(dentry); ++ if (!err) ++ err = au_reval_for_attr(dentry, sigen); ++ if (!err) ++ di_downgrade_lock(dentry, AuLock_IR); ++ else { ++ di_write_unlock(dentry); ++ goto out; ++ } ++ } ++ } else ++ di_read_lock_child(dentry, AuLock_IR); ++ ++body: ++ if (!inode) { ++ inode = d_inode(dentry); ++ if (unlikely(!inode)) ++ goto out; ++ } ++ bindex = au_ibtop(inode); ++ h_path->mnt = au_sbr_mnt(sb, bindex); ++ h_sb = h_path->mnt->mnt_sb; ++ if (!force ++ && !au_test_fs_bad_iattr(h_sb) ++ && udba_none) ++ goto out; /* success */ ++ ++ if (au_dbtop(dentry) == bindex) ++ h_path->dentry = au_h_dptr(dentry, bindex); ++ else if (au_opt_test(mnt_flags, PLINK) && au_plink_test(inode)) { ++ h_path->dentry = au_plink_lkup(inode, bindex); ++ if (IS_ERR(h_path->dentry)) ++ /* pretending success */ ++ h_path->dentry = NULL; ++ else ++ dput(h_path->dentry); ++ } ++ ++out: ++ return err; ++} ++ ++static int aufs_getattr(struct user_namespace *userns, const struct path *path, ++ struct kstat *st, u32 request, unsigned int query) ++{ ++ int err; ++ unsigned char positive; ++ struct path h_path; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ dentry = path->dentry; ++ inode = d_inode(dentry); ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ err = au_h_path_getattr(dentry, /*inode*/NULL, /*force*/0, &h_path, ++ /*locked*/0); ++ if (unlikely(err)) ++ goto out_si; ++ if (unlikely(!h_path.dentry)) ++ /* illegally overlapped or something */ ++ goto out_fill; /* pretending success */ ++ ++ positive = d_is_positive(h_path.dentry); ++ if (positive) ++ /* no vfsub version */ ++ err = vfs_getattr(&h_path, st, request, query); ++ if (!err) { ++ if (positive) ++ au_refresh_iattr(inode, st, ++ d_inode(h_path.dentry)->i_nlink); ++ goto out_fill; /* success */ ++ } ++ AuTraceErr(err); ++ goto out_di; ++ ++out_fill: ++ generic_fillattr(userns, inode, st); ++out_di: ++ di_read_unlock(dentry, AuLock_IR); ++out_si: ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const char *aufs_get_link(struct dentry *dentry, struct inode *inode, ++ struct delayed_call *done) ++{ ++ const char *ret; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ int err; ++ aufs_bindex_t bindex; ++ ++ ret = NULL; /* suppress a warning */ ++ err = -ECHILD; ++ if (!dentry) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_d_hashed_positive(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ err = -EINVAL; ++ inode = d_inode(dentry); ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(!h_inode->i_op->get_link)) ++ goto out_unlock; ++ ++ err = -EBUSY; ++ h_dentry = NULL; ++ if (au_dbtop(dentry) <= bindex) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) ++ dget(h_dentry); ++ } ++ if (!h_dentry) { ++ h_dentry = d_find_any_alias(h_inode); ++ if (IS_ERR(h_dentry)) { ++ err = PTR_ERR(h_dentry); ++ goto out_unlock; ++ } ++ } ++ if (unlikely(!h_dentry)) ++ goto out_unlock; ++ ++ err = 0; ++ AuDbg("%ps\n", h_inode->i_op->get_link); ++ AuDbgDentry(h_dentry); ++ ret = vfs_get_link(h_dentry, done); ++ dput(h_dentry); ++ if (IS_ERR(ret)) ++ err = PTR_ERR(ret); ++ ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_IR); ++out: ++ if (unlikely(err)) ++ ret = ERR_PTR(err); ++ AuTraceErrPtr(ret); ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_is_special(struct inode *inode) ++{ ++ return (inode->i_mode & (S_IFBLK | S_IFCHR | S_IFIFO | S_IFSOCK)); ++} ++ ++static int aufs_update_time(struct inode *inode, struct timespec64 *ts, ++ int flags) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct inode *h_inode; ++ struct vfsmount *h_mnt; ++ ++ sb = inode->i_sb; ++ WARN_ONCE((flags & S_ATIME) && !IS_NOATIME(inode), ++ "unexpected s_flags 0x%lx", sb->s_flags); ++ ++ /* mmap_sem might be acquired already, cf. aufs_mmap() */ ++ lockdep_off(); ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_write_lock_child(inode); ++ ++ err = 0; ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (!au_test_ro(sb, bindex, inode)) { ++ h_mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mnt_want_write(h_mnt); ++ if (!err) { ++ err = vfsub_update_time(h_inode, ts, flags); ++ vfsub_mnt_drop_write(h_mnt); ++ } ++ } else if (au_is_special(h_inode)) { ++ /* ++ * Never copy-up here. ++ * These special files may already be opened and used for ++ * communicating. If we copied it up, then the communication ++ * would be corrupted. ++ */ ++ AuWarn1("timestamps for i%lu are ignored " ++ "since it is on readonly branch (hi%lu).\n", ++ inode->i_ino, h_inode->i_ino); ++ } else if (flags & ~S_ATIME) { ++ err = -EIO; ++ AuIOErr1("unexpected flags 0x%x\n", flags); ++ AuDebugOn(1); ++ } ++ ++ if (!err) ++ au_cpup_attr_timesizes(inode); ++ ii_write_unlock(inode); ++ si_read_unlock(sb); ++ lockdep_on(); ++ ++ if (!err && (flags & S_VERSION)) ++ inode_inc_iversion(inode); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* no getattr version will be set by module.c:aufs_init() */ ++struct inode_operations aufs_iop_nogetattr[AuIop_Last], ++ aufs_iop[] = { ++ [AuIop_SYMLINK] = { ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, /* unsupport for symlink? */ ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .listxattr = aufs_listxattr, ++#endif ++ ++ .get_link = aufs_get_link, ++ ++ /* .update_time = aufs_update_time */ ++ }, ++ [AuIop_DIR] = { ++ .create = aufs_create, ++ .lookup = aufs_lookup, ++ .link = aufs_link, ++ .unlink = aufs_unlink, ++ .symlink = aufs_symlink, ++ .mkdir = aufs_mkdir, ++ .rmdir = aufs_rmdir, ++ .mknod = aufs_mknod, ++ .rename = aufs_rename, ++ ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .listxattr = aufs_listxattr, ++#endif ++ ++ .update_time = aufs_update_time, ++ .atomic_open = aufs_atomic_open, ++ .tmpfile = aufs_tmpfile ++ }, ++ [AuIop_OTHER] = { ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .listxattr = aufs_listxattr, ++#endif ++ ++ .update_time = aufs_update_time ++ } ++}; +diff -Naur null/fs/aufs/i_op_del.c linux-5.15.36/fs/aufs/i_op_del.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/i_op_del.c 2022-05-10 16:51:39.873744219 +0300 +@@ -0,0 +1,522 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * inode operations (del entry) ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * decide if a new whiteout for @dentry is necessary or not. ++ * when it is necessary, prepare the parent dir for the upper branch whose ++ * branch index is @bcpup for creation. the actual creation of the whiteout will ++ * be done by caller. ++ * return value: ++ * 0: wh is unnecessary ++ * plus: wh is necessary ++ * minus: error ++ */ ++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup) ++{ ++ int need_wh, err; ++ aufs_bindex_t btop; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ if (*bcpup < 0) { ++ *bcpup = btop; ++ if (au_test_ro(sb, btop, d_inode(dentry))) { ++ err = AuWbrCopyup(au_sbi(sb), dentry); ++ *bcpup = err; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else ++ AuDebugOn(btop < *bcpup ++ || au_test_ro(sb, *bcpup, d_inode(dentry))); ++ AuDbg("bcpup %d, btop %d\n", *bcpup, btop); ++ ++ if (*bcpup != btop) { ++ err = au_cpup_dirs(dentry, *bcpup); ++ if (unlikely(err)) ++ goto out; ++ need_wh = 1; ++ } else { ++ struct au_dinfo *dinfo, *tmp; ++ ++ need_wh = -ENOMEM; ++ dinfo = au_di(dentry); ++ tmp = au_di_alloc(sb, AuLsc_DI_TMP); ++ if (tmp) { ++ au_di_cp(tmp, dinfo); ++ au_di_swap(tmp, dinfo); ++ /* returns the number of positive dentries */ ++ need_wh = au_lkup_dentry(dentry, btop + 1, ++ /* AuLkup_IGNORE_PERM */ 0); ++ au_di_swap(tmp, dinfo); ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ } ++ } ++ AuDbg("need_wh %d\n", need_wh); ++ err = need_wh; ++ ++out: ++ return err; ++} ++ ++/* ++ * simple tests for the del-entry operations. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir) ++{ ++ int err; ++ umode_t h_mode; ++ struct dentry *h_dentry, *h_latest; ++ struct inode *h_inode; ++ struct path h_ppath; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct user_namespace *h_userns; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (d_really_is_positive(dentry)) { ++ err = -ENOENT; ++ if (unlikely(d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ if (unlikely(!h_inode->i_nlink)) ++ goto out; ++ ++ h_mode = h_inode->i_mode; ++ if (!isdir) { ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(h_mode))) ++ goto out; ++ } else if (unlikely(!S_ISDIR(h_mode))) { ++ err = -ENOTDIR; ++ goto out; ++ } ++ } else { ++ /* rename(2) case */ ++ err = -EIO; ++ if (unlikely(d_is_positive(h_dentry))) ++ goto out; ++ } ++ ++ err = -ENOENT; ++ /* expected parent dir is locked */ ++ if (unlikely(h_parent != h_dentry->d_parent)) ++ goto out; ++ err = 0; ++ ++ /* ++ * rmdir a dir may break the consistency on some filesystem. ++ * let's try heavy test. ++ */ ++ err = -EACCES; ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bindex); ++ h_userns = au_br_userns(br); ++ if (unlikely(!au_opt_test(au_mntflags(sb), DIRPERM1) ++ && au_test_h_perm(h_userns, d_inode(h_parent), ++ MAY_EXEC | MAY_WRITE))) ++ goto out; ++ ++ h_ppath.dentry = h_parent; ++ h_ppath.mnt = au_br_mnt(br); ++ h_latest = au_sio_lkup_one(h_userns, &dentry->d_name, &h_ppath); ++ err = -EIO; ++ if (IS_ERR(h_latest)) ++ goto out; ++ if (h_latest == h_dentry) ++ err = 0; ++ dput(h_latest); ++ ++out: ++ return err; ++} ++ ++/* ++ * decide the branch where we operate for @dentry. the branch index will be set ++ * @rbcpup. after deciding it, 'pin' it and store the timestamps of the parent ++ * dir for reverting. ++ * when a new whiteout is necessary, create it. ++ */ ++static struct dentry* ++lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *rbcpup, ++ struct au_dtime *dt, struct au_pin *pin) ++{ ++ struct dentry *wh_dentry; ++ struct super_block *sb; ++ struct path h_path; ++ int err, need_wh; ++ unsigned int udba; ++ aufs_bindex_t bcpup; ++ ++ need_wh = au_wr_dir_need_wh(dentry, isdir, rbcpup); ++ wh_dentry = ERR_PTR(need_wh); ++ if (unlikely(need_wh < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ udba = au_opt_udba(sb); ++ bcpup = *rbcpup; ++ err = au_pin(pin, dentry, bcpup, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ h_path.dentry = au_pinned_h_parent(pin); ++ if (udba != AuOpt_UDBA_NONE ++ && au_dbtop(dentry) == bcpup) { ++ err = au_may_del(dentry, bcpup, h_path.dentry, isdir); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_unpin; ++ } ++ ++ h_path.mnt = au_sbr_mnt(sb, bcpup); ++ au_dtime_store(dt, au_pinned_parent(pin), &h_path); ++ wh_dentry = NULL; ++ if (!need_wh) ++ goto out; /* success, no need to create whiteout */ ++ ++ wh_dentry = au_wh_create(dentry, bcpup, h_path.dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_unpin; ++ ++ /* returns with the parent is locked and wh_dentry is dget-ed */ ++ goto out; /* success */ ++ ++out_unpin: ++ au_unpin(pin); ++out: ++ return wh_dentry; ++} ++ ++/* ++ * when removing a dir, rename it to a unique temporary whiteout-ed name first ++ * in order to be revertible and save time for removing many child whiteouts ++ * under the dir. ++ * returns 1 when there are too many child whiteout and caller should remove ++ * them asynchronously. returns 0 when the number of children is enough small to ++ * remove now or the branch fs is a remote fs. ++ * otherwise return an error. ++ */ ++static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex, ++ struct au_nhash *whlist, struct inode *dir) ++{ ++ int rmdir_later, err, dirwh; ++ struct dentry *h_dentry; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ sb = dentry->d_sb; ++ SiMustAnyLock(sb); ++ h_dentry = au_h_dptr(dentry, bindex); ++ err = au_whtmp_ren(h_dentry, au_sbr(sb, bindex)); ++ if (unlikely(err)) ++ goto out; ++ ++ /* stop monitoring */ ++ inode = d_inode(dentry); ++ au_hn_free(au_hi(inode, bindex)); ++ ++ if (!au_test_fs_remote(h_dentry->d_sb)) { ++ dirwh = au_sbi(sb)->si_dirwh; ++ rmdir_later = (dirwh <= 1); ++ if (!rmdir_later) ++ rmdir_later = au_nhash_test_longer_wh(whlist, bindex, ++ dirwh); ++ if (rmdir_later) ++ return rmdir_later; ++ } ++ ++ err = au_whtmp_rmdir(dir, bindex, h_dentry, whlist); ++ if (unlikely(err)) { ++ AuIOErr("rmdir %pd, b%d failed, %d. ignored\n", ++ h_dentry, bindex, err); ++ err = 0; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * final procedure for deleting a entry. ++ * maintain dentry and iattr. ++ */ ++static void epilog(struct inode *dir, struct dentry *dentry, ++ aufs_bindex_t bindex) ++{ ++ struct inode *inode; ++ ++ inode = d_inode(dentry); ++ d_drop(dentry); ++ inode->i_ctime = dir->i_ctime; ++ ++ au_dir_ts(dir, bindex); ++ inode_inc_iversion(dir); ++} ++ ++/* ++ * when an error happened, remove the created whiteout and revert everything. ++ */ ++static int do_revert(int err, struct inode *dir, aufs_bindex_t bindex, ++ aufs_bindex_t bwh, struct dentry *wh_dentry, ++ struct dentry *dentry, struct au_dtime *dt) ++{ ++ int rerr; ++ struct path h_path = { ++ .dentry = wh_dentry, ++ .mnt = au_sbr_mnt(dir->i_sb, bindex) ++ }; ++ ++ rerr = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, dentry); ++ if (!rerr) { ++ au_set_dbwh(dentry, bwh); ++ au_dtime_revert(dt); ++ return 0; ++ } ++ ++ AuIOErr("%pd reverting whiteout failed(%d, %d)\n", dentry, err, rerr); ++ return -EIO; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_unlink(struct inode *dir, struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bwh, bindex, btop; ++ struct inode *inode, *h_dir, *delegated; ++ struct dentry *parent, *wh_dentry; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ struct path h_path; ++ } *a; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_d_hashed_positive(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ err = -EISDIR; ++ if (unlikely(d_is_dir(dentry))) ++ goto out_unlock; /* possible? */ ++ ++ btop = au_dbtop(dentry); ++ bwh = au_dbwh(dentry); ++ bindex = -1; ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &a->dt, ++ &a->pin); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ a->h_path.mnt = au_sbr_mnt(dentry->d_sb, btop); ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ dget(a->h_path.dentry); ++ if (bindex == btop) { ++ h_dir = au_pinned_h_dir(&a->pin); ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &a->h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } else { ++ /* dir inode is locked */ ++ h_dir = d_inode(wh_dentry->d_parent); ++ IMustLock(h_dir); ++ err = 0; ++ } ++ ++ if (!err) { ++ vfsub_drop_nlink(inode); ++ epilog(dir, dentry, bindex); ++ ++ /* update target timestamps */ ++ if (bindex == btop) { ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); ++ /*ignore*/ ++ inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; ++ } else ++ /* todo: this timestamp may be reverted later */ ++ inode->i_ctime = h_dir->i_ctime; ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ if (wh_dentry) { ++ int rerr; ++ ++ rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, ++ &a->dt); ++ if (rerr) ++ err = rerr; ++ } ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++ dput(a->h_path.dentry); ++out_parent: ++ di_write_unlock(parent); ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ return err; ++} ++ ++int aufs_rmdir(struct inode *dir, struct dentry *dentry) ++{ ++ int err, rmdir_later; ++ aufs_bindex_t bwh, bindex, btop; ++ struct inode *inode; ++ struct dentry *parent, *wh_dentry, *h_dentry; ++ struct au_whtmp_rmdir *args; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ } *a; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_alive_dir(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ err = -ENOTDIR; ++ if (unlikely(!d_is_dir(dentry))) ++ goto out_unlock; /* possible? */ ++ ++ err = -ENOMEM; ++ args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS); ++ if (unlikely(!args)) ++ goto out_unlock; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ err = au_test_empty(dentry, &args->whlist); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ btop = au_dbtop(dentry); ++ bwh = au_dbwh(dentry); ++ bindex = -1; ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &a->dt, ++ &a->pin); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ h_dentry = au_h_dptr(dentry, btop); ++ dget(h_dentry); ++ rmdir_later = 0; ++ if (bindex == btop) { ++ err = renwh_and_rmdir(dentry, btop, &args->whlist, dir); ++ if (err > 0) { ++ rmdir_later = err; ++ err = 0; ++ } ++ } else { ++ /* stop monitoring */ ++ au_hn_free(au_hi(inode, btop)); ++ ++ /* dir inode is locked */ ++ IMustLock(d_inode(wh_dentry->d_parent)); ++ err = 0; ++ } ++ ++ if (!err) { ++ vfsub_dead_dir(inode); ++ au_set_dbdiropq(dentry, -1); ++ epilog(dir, dentry, bindex); ++ ++ if (rmdir_later) { ++ au_whtmp_kick_rmdir(dir, btop, h_dentry, args); ++ args = NULL; ++ } ++ ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ AuLabel(revert); ++ if (wh_dentry) { ++ int rerr; ++ ++ rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, ++ &a->dt); ++ if (rerr) ++ err = rerr; ++ } ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++ dput(h_dentry); ++out_parent: ++ di_write_unlock(parent); ++ if (args) ++ au_whtmp_rmdir_free(args); ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff -Naur null/fs/aufs/i_op_ren.c linux-5.15.36/fs/aufs/i_op_ren.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/i_op_ren.c 2022-05-10 16:51:39.873744219 +0300 +@@ -0,0 +1,1257 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * inode operation (rename entry) ++ * todo: this is crazy monster ++ */ ++ ++#include ++#include "aufs.h" ++ ++enum { AuSRC, AuDST, AuSrcDst }; ++enum { AuPARENT, AuCHILD, AuParentChild }; ++ ++#define AuRen_ISDIR_SRC 1 ++#define AuRen_ISDIR_DST (1 << 1) ++#define AuRen_ISSAMEDIR (1 << 2) ++#define AuRen_WHSRC (1 << 3) ++#define AuRen_WHDST (1 << 4) ++#define AuRen_MNT_WRITE (1 << 5) ++#define AuRen_DT_DSTDIR (1 << 6) ++#define AuRen_DIROPQ_SRC (1 << 7) ++#define AuRen_DIROPQ_DST (1 << 8) ++#define AuRen_DIRREN (1 << 9) ++#define AuRen_DROPPED_SRC (1 << 10) ++#define AuRen_DROPPED_DST (1 << 11) ++#define au_ftest_ren(flags, name) ((flags) & AuRen_##name) ++#define au_fset_ren(flags, name) \ ++ do { (flags) |= AuRen_##name; } while (0) ++#define au_fclr_ren(flags, name) \ ++ do { (flags) &= ~AuRen_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuRen_DIRREN ++#define AuRen_DIRREN 0 ++#endif ++ ++struct au_ren_args { ++ struct { ++ struct dentry *dentry, *h_dentry, *parent, *h_parent, ++ *wh_dentry; ++ struct inode *dir, *inode; ++ struct au_hinode *hdir, *hinode; ++ struct au_dtime dt[AuParentChild]; ++ aufs_bindex_t btop, bdiropq; ++ } sd[AuSrcDst]; ++ ++#define src_dentry sd[AuSRC].dentry ++#define src_dir sd[AuSRC].dir ++#define src_inode sd[AuSRC].inode ++#define src_h_dentry sd[AuSRC].h_dentry ++#define src_parent sd[AuSRC].parent ++#define src_h_parent sd[AuSRC].h_parent ++#define src_wh_dentry sd[AuSRC].wh_dentry ++#define src_hdir sd[AuSRC].hdir ++#define src_hinode sd[AuSRC].hinode ++#define src_h_dir sd[AuSRC].hdir->hi_inode ++#define src_dt sd[AuSRC].dt ++#define src_btop sd[AuSRC].btop ++#define src_bdiropq sd[AuSRC].bdiropq ++ ++#define dst_dentry sd[AuDST].dentry ++#define dst_dir sd[AuDST].dir ++#define dst_inode sd[AuDST].inode ++#define dst_h_dentry sd[AuDST].h_dentry ++#define dst_parent sd[AuDST].parent ++#define dst_h_parent sd[AuDST].h_parent ++#define dst_wh_dentry sd[AuDST].wh_dentry ++#define dst_hdir sd[AuDST].hdir ++#define dst_hinode sd[AuDST].hinode ++#define dst_h_dir sd[AuDST].hdir->hi_inode ++#define dst_dt sd[AuDST].dt ++#define dst_btop sd[AuDST].btop ++#define dst_bdiropq sd[AuDST].bdiropq ++ ++ struct dentry *h_trap; ++ struct au_branch *br; ++ struct path h_path; ++ struct au_nhash whlist; ++ aufs_bindex_t btgt, src_bwh; ++ ++ struct { ++ unsigned short auren_flags; ++ unsigned char flags; /* syscall parameter */ ++ unsigned char exchange; ++ } __packed; ++ ++ struct au_whtmp_rmdir *thargs; ++ struct dentry *h_dst; ++ struct au_hinode *h_root; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * functions for reverting. ++ * when an error happened in a single rename systemcall, we should revert ++ * everything as if nothing happened. ++ * we don't need to revert the copied-up/down the parent dir since they are ++ * harmless. ++ */ ++ ++#define RevertFailure(fmt, ...) do { \ ++ AuIOErr("revert failure: " fmt " (%d, %d)\n", \ ++ ##__VA_ARGS__, err, rerr); \ ++ err = -EIO; \ ++} while (0) ++ ++static void au_ren_do_rev_diropq(int err, struct au_ren_args *a, int idx) ++{ ++ int rerr; ++ struct dentry *d; ++#define src_or_dst(member) a->sd[idx].member ++ ++ d = src_or_dst(dentry); /* {src,dst}_dentry */ ++ au_hn_inode_lock_nested(src_or_dst(hinode), AuLsc_I_CHILD); ++ rerr = au_diropq_remove(d, a->btgt); ++ au_hn_inode_unlock(src_or_dst(hinode)); ++ au_set_dbdiropq(d, src_or_dst(bdiropq)); ++ if (rerr) ++ RevertFailure("remove diropq %pd", d); ++ ++#undef src_or_dst_ ++} ++ ++static void au_ren_rev_diropq(int err, struct au_ren_args *a) ++{ ++ if (au_ftest_ren(a->auren_flags, DIROPQ_SRC)) ++ au_ren_do_rev_diropq(err, a, AuSRC); ++ if (au_ftest_ren(a->auren_flags, DIROPQ_DST)) ++ au_ren_do_rev_diropq(err, a, AuDST); ++} ++ ++static void au_ren_rev_rename(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ struct inode *delegated; ++ struct path h_ppath = { ++ .dentry = a->src_h_parent, ++ .mnt = a->h_path.mnt ++ }; ++ ++ a->h_path.dentry = vfsub_lkup_one(&a->src_dentry->d_name, &h_ppath); ++ rerr = PTR_ERR(a->h_path.dentry); ++ if (IS_ERR(a->h_path.dentry)) { ++ RevertFailure("lkup one %pd", a->src_dentry); ++ return; ++ } ++ ++ delegated = NULL; ++ rerr = vfsub_rename(a->dst_h_dir, ++ au_h_dptr(a->src_dentry, a->btgt), ++ a->src_h_dir, &a->h_path, &delegated, a->flags); ++ if (unlikely(rerr == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ /* au_set_h_dptr(a->src_dentry, a->btgt, NULL); */ ++ if (rerr) ++ RevertFailure("rename %pd", a->src_dentry); ++} ++ ++static void au_ren_rev_whtmp(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ struct inode *delegated; ++ struct path h_ppath = { ++ .dentry = a->dst_h_parent, ++ .mnt = a->h_path.mnt ++ }; ++ ++ a->h_path.dentry = vfsub_lkup_one(&a->dst_dentry->d_name, &h_ppath); ++ rerr = PTR_ERR(a->h_path.dentry); ++ if (IS_ERR(a->h_path.dentry)) { ++ RevertFailure("lkup one %pd", a->dst_dentry); ++ return; ++ } ++ if (d_is_positive(a->h_path.dentry)) { ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ return; ++ } ++ ++ delegated = NULL; ++ rerr = vfsub_rename(a->dst_h_dir, a->h_dst, a->dst_h_dir, &a->h_path, ++ &delegated, a->flags); ++ if (unlikely(rerr == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ if (!rerr) ++ au_set_h_dptr(a->dst_dentry, a->btgt, dget(a->h_dst)); ++ else ++ RevertFailure("rename %pd", a->h_dst); ++} ++ ++static void au_ren_rev_whsrc(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ ++ a->h_path.dentry = a->src_wh_dentry; ++ rerr = au_wh_unlink_dentry(a->src_h_dir, &a->h_path, a->src_dentry); ++ au_set_dbwh(a->src_dentry, a->src_bwh); ++ if (rerr) ++ RevertFailure("unlink %pd", a->src_wh_dentry); ++} ++#undef RevertFailure ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * when we have to copyup the renaming entry, do it with the rename-target name ++ * in order to minimize the cost (the later actual rename is unnecessary). ++ * otherwise rename it on the target branch. ++ */ ++static int au_ren_or_cpup(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *d; ++ struct inode *delegated; ++ ++ d = a->src_dentry; ++ if (au_dbtop(d) == a->btgt) { ++ a->h_path.dentry = a->dst_h_dentry; ++ AuDebugOn(au_dbtop(d) != a->btgt); ++ delegated = NULL; ++ err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt), ++ a->dst_h_dir, &a->h_path, &delegated, ++ a->flags); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ } else ++ BUG(); ++ ++ if (!err && a->h_dst) ++ /* it will be set to dinfo later */ ++ dget(a->h_dst); ++ ++ return err; ++} ++ ++/* cf. aufs_rmdir() */ ++static int au_ren_del_whtmp(struct au_ren_args *a) ++{ ++ int err; ++ struct inode *dir; ++ ++ dir = a->dst_dir; ++ SiMustAnyLock(dir->i_sb); ++ if (!au_nhash_test_longer_wh(&a->whlist, a->btgt, ++ au_sbi(dir->i_sb)->si_dirwh) ++ || au_test_fs_remote(a->h_dst->d_sb)) { ++ err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist); ++ if (unlikely(err)) ++ pr_warn("failed removing whtmp dir %pd (%d), " ++ "ignored.\n", a->h_dst, err); ++ } else { ++ au_nhash_wh_free(&a->thargs->whlist); ++ a->thargs->whlist = a->whlist; ++ a->whlist.nh_num = 0; ++ au_whtmp_kick_rmdir(dir, a->btgt, a->h_dst, a->thargs); ++ dput(a->h_dst); ++ a->thargs = NULL; ++ } ++ ++ return 0; ++} ++ ++/* make it 'opaque' dir. */ ++static int au_ren_do_diropq(struct au_ren_args *a, int idx) ++{ ++ int err; ++ struct dentry *d, *diropq; ++#define src_or_dst(member) a->sd[idx].member ++ ++ err = 0; ++ d = src_or_dst(dentry); /* {src,dst}_dentry */ ++ src_or_dst(bdiropq) = au_dbdiropq(d); ++ src_or_dst(hinode) = au_hi(src_or_dst(inode), a->btgt); ++ au_hn_inode_lock_nested(src_or_dst(hinode), AuLsc_I_CHILD); ++ diropq = au_diropq_create(d, a->btgt); ++ au_hn_inode_unlock(src_or_dst(hinode)); ++ if (IS_ERR(diropq)) ++ err = PTR_ERR(diropq); ++ else ++ dput(diropq); ++ ++#undef src_or_dst_ ++ return err; ++} ++ ++static int au_ren_diropq(struct au_ren_args *a) ++{ ++ int err; ++ unsigned char always; ++ struct dentry *d; ++ ++ err = 0; ++ d = a->dst_dentry; /* already renamed on the branch */ ++ always = !!au_opt_test(au_mntflags(d->d_sb), ALWAYS_DIROPQ); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC) ++ && !au_ftest_ren(a->auren_flags, DIRREN) ++ && a->btgt != au_dbdiropq(a->src_dentry) ++ && (a->dst_wh_dentry ++ || a->btgt <= au_dbdiropq(d) ++ /* hide the lower to keep xino */ ++ /* the lowers may not be a dir, but we hide them anyway */ ++ || a->btgt < au_dbbot(d) ++ || always)) { ++ AuDbg("here\n"); ++ err = au_ren_do_diropq(a, AuSRC); ++ if (unlikely(err)) ++ goto out; ++ au_fset_ren(a->auren_flags, DIROPQ_SRC); ++ } ++ if (!a->exchange) ++ goto out; /* success */ ++ ++ d = a->src_dentry; /* already renamed on the branch */ ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST) ++ && a->btgt != au_dbdiropq(a->dst_dentry) ++ && (a->btgt < au_dbdiropq(d) ++ || a->btgt < au_dbbot(d) ++ || always)) { ++ AuDbgDentry(a->src_dentry); ++ AuDbgDentry(a->dst_dentry); ++ err = au_ren_do_diropq(a, AuDST); ++ if (unlikely(err)) ++ goto out_rev_src; ++ au_fset_ren(a->auren_flags, DIROPQ_DST); ++ } ++ goto out; /* success */ ++ ++out_rev_src: ++ AuDbg("err %d, reverting src\n", err); ++ au_ren_rev_diropq(err, a); ++out: ++ return err; ++} ++ ++static int do_rename(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *d, *h_d; ++ ++ if (!a->exchange) { ++ /* prepare workqueue args for asynchronous rmdir */ ++ h_d = a->dst_h_dentry; ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST) ++ /* && !au_ftest_ren(a->auren_flags, DIRREN) */ ++ && d_is_positive(h_d)) { ++ err = -ENOMEM; ++ a->thargs = au_whtmp_rmdir_alloc(a->src_dentry->d_sb, ++ GFP_NOFS); ++ if (unlikely(!a->thargs)) ++ goto out; ++ a->h_dst = dget(h_d); ++ } ++ ++ /* create whiteout for src_dentry */ ++ if (au_ftest_ren(a->auren_flags, WHSRC)) { ++ a->src_bwh = au_dbwh(a->src_dentry); ++ AuDebugOn(a->src_bwh >= 0); ++ a->src_wh_dentry = au_wh_create(a->src_dentry, a->btgt, ++ a->src_h_parent); ++ err = PTR_ERR(a->src_wh_dentry); ++ if (IS_ERR(a->src_wh_dentry)) ++ goto out_thargs; ++ } ++ ++ /* lookup whiteout for dentry */ ++ if (au_ftest_ren(a->auren_flags, WHDST)) { ++ h_d = au_wh_lkup(a->dst_h_parent, ++ &a->dst_dentry->d_name, a->br); ++ err = PTR_ERR(h_d); ++ if (IS_ERR(h_d)) ++ goto out_whsrc; ++ if (d_is_negative(h_d)) ++ dput(h_d); ++ else ++ a->dst_wh_dentry = h_d; ++ } ++ ++ /* rename dentry to tmpwh */ ++ if (a->thargs) { ++ err = au_whtmp_ren(a->dst_h_dentry, a->br); ++ if (unlikely(err)) ++ goto out_whdst; ++ ++ d = a->dst_dentry; ++ au_set_h_dptr(d, a->btgt, NULL); ++ err = au_lkup_neg(d, a->btgt, /*wh*/0); ++ if (unlikely(err)) ++ goto out_whtmp; ++ a->dst_h_dentry = au_h_dptr(d, a->btgt); ++ } ++ } ++ ++ BUG_ON(d_is_positive(a->dst_h_dentry) && a->src_btop != a->btgt); ++#if 0 /* debugging */ ++ BUG_ON(!au_ftest_ren(a->auren_flags, DIRREN) ++ && d_is_positive(a->dst_h_dentry) ++ && a->src_btop != a->btgt); ++#endif ++ ++ /* rename by vfs_rename or cpup */ ++ err = au_ren_or_cpup(a); ++ if (unlikely(err)) ++ /* leave the copied-up one */ ++ goto out_whtmp; ++ ++ /* make dir opaque */ ++ err = au_ren_diropq(a); ++ if (unlikely(err)) ++ goto out_rename; ++ ++ /* update target timestamps */ ++ if (a->exchange) { ++ AuDebugOn(au_dbtop(a->dst_dentry) != a->btgt); ++ a->h_path.dentry = au_h_dptr(a->dst_dentry, a->btgt); ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/ ++ a->dst_inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; ++ } ++ AuDebugOn(au_dbtop(a->src_dentry) != a->btgt); ++ a->h_path.dentry = au_h_dptr(a->src_dentry, a->btgt); ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/ ++ a->src_inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; ++ ++ if (!a->exchange) { ++ /* remove whiteout for dentry */ ++ if (a->dst_wh_dentry) { ++ a->h_path.dentry = a->dst_wh_dentry; ++ err = au_wh_unlink_dentry(a->dst_h_dir, &a->h_path, ++ a->dst_dentry); ++ if (unlikely(err)) ++ goto out_diropq; ++ } ++ ++ /* remove whtmp */ ++ if (a->thargs) ++ au_ren_del_whtmp(a); /* ignore this error */ ++ ++ au_fhsm_wrote(a->src_dentry->d_sb, a->btgt, /*force*/0); ++ } ++ err = 0; ++ goto out_success; ++ ++out_diropq: ++ au_ren_rev_diropq(err, a); ++out_rename: ++ au_ren_rev_rename(err, a); ++ dput(a->h_dst); ++out_whtmp: ++ if (a->thargs) ++ au_ren_rev_whtmp(err, a); ++out_whdst: ++ dput(a->dst_wh_dentry); ++ a->dst_wh_dentry = NULL; ++out_whsrc: ++ if (a->src_wh_dentry) ++ au_ren_rev_whsrc(err, a); ++out_success: ++ dput(a->src_wh_dentry); ++ dput(a->dst_wh_dentry); ++out_thargs: ++ if (a->thargs) { ++ dput(a->h_dst); ++ au_whtmp_rmdir_free(a->thargs); ++ a->thargs = NULL; ++ } ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if @dentry dir can be rename destination or not. ++ * success means, it is a logically empty dir. ++ */ ++static int may_rename_dstdir(struct dentry *dentry, struct au_nhash *whlist) ++{ ++ return au_test_empty(dentry, whlist); ++} ++ ++/* ++ * test if @a->src_dentry dir can be rename source or not. ++ * if it can, return 0. ++ * success means, ++ * - it is a logically empty dir. ++ * - or, it exists on writable branch and has no children including whiteouts ++ * on the lower branch unless DIRREN is on. ++ */ ++static int may_rename_srcdir(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int rdhash; ++ aufs_bindex_t btop, btgt; ++ struct dentry *dentry; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ dentry = a->src_dentry; ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ if (au_opt_test(sbinfo->si_mntflags, DIRREN)) ++ au_fset_ren(a->auren_flags, DIRREN); ++ ++ btgt = a->btgt; ++ btop = au_dbtop(dentry); ++ if (btop != btgt) { ++ struct au_nhash whlist; ++ ++ SiMustAnyLock(sb); ++ rdhash = sbinfo->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, ++ dentry)); ++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_test_empty(dentry, &whlist); ++ au_nhash_wh_free(&whlist); ++ goto out; ++ } ++ ++ if (btop == au_dbtaildir(dentry)) ++ return 0; /* success */ ++ ++ err = au_test_empty_lower(dentry); ++ ++out: ++ if (err == -ENOTEMPTY) { ++ if (au_ftest_ren(a->auren_flags, DIRREN)) { ++ err = 0; ++ } else { ++ AuWarn1("renaming dir who has child(ren) on multiple " ++ "branches, is not supported\n"); ++ err = -EXDEV; ++ } ++ } ++ return err; ++} ++ ++/* side effect: sets whlist and h_dentry */ ++static int au_ren_may_dir(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int rdhash; ++ struct dentry *d; ++ ++ d = a->dst_dentry; ++ SiMustAnyLock(d->d_sb); ++ ++ err = 0; ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST) && a->dst_inode) { ++ rdhash = au_sbi(d->d_sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, d)); ++ err = au_nhash_alloc(&a->whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ ++ if (!a->exchange) { ++ au_set_dbtop(d, a->dst_btop); ++ err = may_rename_dstdir(d, &a->whlist); ++ au_set_dbtop(d, a->btgt); ++ } else ++ err = may_rename_srcdir(a); ++ } ++ a->dst_h_dentry = au_h_dptr(d, au_dbtop(d)); ++ if (unlikely(err)) ++ goto out; ++ ++ d = a->src_dentry; ++ a->src_h_dentry = au_h_dptr(d, au_dbtop(d)); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) { ++ err = may_rename_srcdir(a); ++ if (unlikely(err)) { ++ au_nhash_wh_free(&a->whlist); ++ a->whlist.nh_num = 0; ++ } ++ } ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * simple tests for rename. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++static int au_may_ren(struct au_ren_args *a) ++{ ++ int err, isdir; ++ struct inode *h_inode; ++ ++ if (a->src_btop == a->btgt) { ++ err = au_may_del(a->src_dentry, a->btgt, a->src_h_parent, ++ au_ftest_ren(a->auren_flags, ISDIR_SRC)); ++ if (unlikely(err)) ++ goto out; ++ err = -EINVAL; ++ if (unlikely(a->src_h_dentry == a->h_trap)) ++ goto out; ++ } ++ ++ err = 0; ++ if (a->dst_btop != a->btgt) ++ goto out; ++ ++ err = -ENOTEMPTY; ++ if (unlikely(a->dst_h_dentry == a->h_trap)) ++ goto out; ++ ++ err = -EIO; ++ isdir = !!au_ftest_ren(a->auren_flags, ISDIR_DST); ++ if (d_really_is_negative(a->dst_dentry)) { ++ if (d_is_negative(a->dst_h_dentry)) ++ err = au_may_add(a->dst_dentry, a->btgt, ++ a->dst_h_parent, isdir); ++ } else { ++ if (unlikely(d_is_negative(a->dst_h_dentry))) ++ goto out; ++ h_inode = d_inode(a->dst_h_dentry); ++ if (h_inode->i_nlink) ++ err = au_may_del(a->dst_dentry, a->btgt, ++ a->dst_h_parent, isdir); ++ } ++ ++out: ++ if (unlikely(err == -ENOENT || err == -EEXIST)) ++ err = -EIO; ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * locking order ++ * (VFS) ++ * - src_dir and dir by lock_rename() ++ * - inode if exists ++ * (aufs) ++ * - lock all ++ * + src_dentry and dentry by aufs_read_and_write_lock2() which calls, ++ * + si_read_lock ++ * + di_write_lock2_child() ++ * + di_write_lock_child() ++ * + ii_write_lock_child() ++ * + di_write_lock_child2() ++ * + ii_write_lock_child2() ++ * + src_parent and parent ++ * + di_write_lock_parent() ++ * + ii_write_lock_parent() ++ * + di_write_lock_parent2() ++ * + ii_write_lock_parent2() ++ * + lower src_dir and dir by vfsub_lock_rename() ++ * + verify the every relationships between child and parent. if any ++ * of them failed, unlock all and return -EBUSY. ++ */ ++static void au_ren_unlock(struct au_ren_args *a) ++{ ++ vfsub_unlock_rename(a->src_h_parent, a->src_hdir, ++ a->dst_h_parent, a->dst_hdir); ++ if (au_ftest_ren(a->auren_flags, DIRREN) ++ && a->h_root) ++ au_hn_inode_unlock(a->h_root); ++ if (au_ftest_ren(a->auren_flags, MNT_WRITE)) ++ vfsub_mnt_drop_write(au_br_mnt(a->br)); ++} ++ ++static int au_ren_lock(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int udba; ++ ++ err = 0; ++ a->src_h_parent = au_h_dptr(a->src_parent, a->btgt); ++ a->src_hdir = au_hi(a->src_dir, a->btgt); ++ a->dst_h_parent = au_h_dptr(a->dst_parent, a->btgt); ++ a->dst_hdir = au_hi(a->dst_dir, a->btgt); ++ ++ err = vfsub_mnt_want_write(au_br_mnt(a->br)); ++ if (unlikely(err)) ++ goto out; ++ au_fset_ren(a->auren_flags, MNT_WRITE); ++ if (au_ftest_ren(a->auren_flags, DIRREN)) { ++ struct dentry *root; ++ struct inode *dir; ++ ++ /* ++ * sbinfo is already locked, so this ii_read_lock is ++ * unnecessary. but our debugging feature checks it. ++ */ ++ root = a->src_inode->i_sb->s_root; ++ if (root != a->src_parent && root != a->dst_parent) { ++ dir = d_inode(root); ++ ii_read_lock_parent3(dir); ++ a->h_root = au_hi(dir, a->btgt); ++ ii_read_unlock(dir); ++ au_hn_inode_lock_nested(a->h_root, AuLsc_I_PARENT3); ++ } ++ } ++ a->h_trap = vfsub_lock_rename(a->src_h_parent, a->src_hdir, ++ a->dst_h_parent, a->dst_hdir); ++ udba = au_opt_udba(a->src_dentry->d_sb); ++ if (unlikely(a->src_hdir->hi_inode != d_inode(a->src_h_parent) ++ || a->dst_hdir->hi_inode != d_inode(a->dst_h_parent))) ++ err = au_busy_or_stale(); ++ if (!err && au_dbtop(a->src_dentry) == a->btgt) ++ err = au_h_verify(a->src_h_dentry, udba, ++ d_inode(a->src_h_parent), a->src_h_parent, ++ a->br); ++ if (!err && au_dbtop(a->dst_dentry) == a->btgt) ++ err = au_h_verify(a->dst_h_dentry, udba, ++ d_inode(a->dst_h_parent), a->dst_h_parent, ++ a->br); ++ if (!err) ++ goto out; /* success */ ++ ++ err = au_busy_or_stale(); ++ au_ren_unlock(a); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_ren_refresh_dir(struct au_ren_args *a) ++{ ++ struct inode *dir; ++ ++ dir = a->dst_dir; ++ inode_inc_iversion(dir); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) { ++ /* is this updating defined in POSIX? */ ++ au_cpup_attr_timesizes(a->src_inode); ++ au_cpup_attr_nlink(dir, /*force*/1); ++ } ++ au_dir_ts(dir, a->btgt); ++ ++ if (a->exchange) { ++ dir = a->src_dir; ++ inode_inc_iversion(dir); ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST)) { ++ /* is this updating defined in POSIX? */ ++ au_cpup_attr_timesizes(a->dst_inode); ++ au_cpup_attr_nlink(dir, /*force*/1); ++ } ++ au_dir_ts(dir, a->btgt); ++ } ++ ++ if (au_ftest_ren(a->auren_flags, ISSAMEDIR)) ++ return; ++ ++ dir = a->src_dir; ++ inode_inc_iversion(dir); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) ++ au_cpup_attr_nlink(dir, /*force*/1); ++ au_dir_ts(dir, a->btgt); ++} ++ ++static void au_ren_refresh(struct au_ren_args *a) ++{ ++ aufs_bindex_t bbot, bindex; ++ struct dentry *d, *h_d; ++ struct inode *i, *h_i; ++ struct super_block *sb; ++ ++ d = a->dst_dentry; ++ d_drop(d); ++ if (a->h_dst) ++ /* already dget-ed by au_ren_or_cpup() */ ++ au_set_h_dptr(d, a->btgt, a->h_dst); ++ ++ i = a->dst_inode; ++ if (i) { ++ if (!a->exchange) { ++ if (!au_ftest_ren(a->auren_flags, ISDIR_DST)) ++ vfsub_drop_nlink(i); ++ else { ++ vfsub_dead_dir(i); ++ au_cpup_attr_timesizes(i); ++ } ++ au_update_dbrange(d, /*do_put_zero*/1); ++ } else ++ au_cpup_attr_nlink(i, /*force*/1); ++ } else { ++ bbot = a->btgt; ++ for (bindex = au_dbtop(d); bindex < bbot; bindex++) ++ au_set_h_dptr(d, bindex, NULL); ++ bbot = au_dbbot(d); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) ++ au_set_h_dptr(d, bindex, NULL); ++ au_update_dbrange(d, /*do_put_zero*/0); ++ } ++ ++ if (a->exchange ++ || au_ftest_ren(a->auren_flags, DIRREN)) { ++ d_drop(a->src_dentry); ++ if (au_ftest_ren(a->auren_flags, DIRREN)) ++ au_set_dbwh(a->src_dentry, -1); ++ return; ++ } ++ ++ d = a->src_dentry; ++ au_set_dbwh(d, -1); ++ bbot = au_dbbot(d); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) { ++ h_d = au_h_dptr(d, bindex); ++ if (h_d) ++ au_set_h_dptr(d, bindex, NULL); ++ } ++ au_set_dbbot(d, a->btgt); ++ ++ sb = d->d_sb; ++ i = a->src_inode; ++ if (au_opt_test(au_mntflags(sb), PLINK) && au_plink_test(i)) ++ return; /* success */ ++ ++ bbot = au_ibbot(i); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) { ++ h_i = au_h_iptr(i, bindex); ++ if (h_i) { ++ au_xino_write(sb, bindex, h_i->i_ino, /*ino*/0); ++ /* ignore this error */ ++ au_set_h_iptr(i, bindex, NULL, 0); ++ } ++ } ++ au_set_ibbot(i, a->btgt); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* mainly for link(2) and rename(2) */ ++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt) ++{ ++ aufs_bindex_t bdiropq, bwh; ++ struct dentry *parent; ++ struct au_branch *br; ++ ++ parent = dentry->d_parent; ++ IMustLock(d_inode(parent)); /* dir is locked */ ++ ++ bdiropq = au_dbdiropq(parent); ++ bwh = au_dbwh(dentry); ++ br = au_sbr(dentry->d_sb, btgt); ++ if (au_br_rdonly(br) ++ || (0 <= bdiropq && bdiropq < btgt) ++ || (0 <= bwh && bwh < btgt)) ++ btgt = -1; ++ ++ AuDbg("btgt %d\n", btgt); ++ return btgt; ++} ++ ++/* sets src_btop, dst_btop and btgt */ ++static int au_ren_wbr(struct au_ren_args *a) ++{ ++ int err; ++ struct au_wr_dir_args wr_dir_args = { ++ /* .force_btgt = -1, */ ++ .flags = AuWrDir_ADD_ENTRY ++ }; ++ ++ a->src_btop = au_dbtop(a->src_dentry); ++ a->dst_btop = au_dbtop(a->dst_dentry); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC) ++ || au_ftest_ren(a->auren_flags, ISDIR_DST)) ++ au_fset_wrdir(wr_dir_args.flags, ISDIR); ++ wr_dir_args.force_btgt = a->src_btop; ++ if (a->dst_inode && a->dst_btop < a->src_btop) ++ wr_dir_args.force_btgt = a->dst_btop; ++ wr_dir_args.force_btgt = au_wbr(a->dst_dentry, wr_dir_args.force_btgt); ++ err = au_wr_dir(a->dst_dentry, a->src_dentry, &wr_dir_args); ++ a->btgt = err; ++ if (a->exchange) ++ au_update_dbtop(a->dst_dentry); ++ ++ return err; ++} ++ ++static void au_ren_dt(struct au_ren_args *a) ++{ ++ a->h_path.dentry = a->src_h_parent; ++ au_dtime_store(a->src_dt + AuPARENT, a->src_parent, &a->h_path); ++ if (!au_ftest_ren(a->auren_flags, ISSAMEDIR)) { ++ a->h_path.dentry = a->dst_h_parent; ++ au_dtime_store(a->dst_dt + AuPARENT, a->dst_parent, &a->h_path); ++ } ++ ++ au_fclr_ren(a->auren_flags, DT_DSTDIR); ++ if (!au_ftest_ren(a->auren_flags, ISDIR_SRC) ++ && !a->exchange) ++ return; ++ ++ a->h_path.dentry = a->src_h_dentry; ++ au_dtime_store(a->src_dt + AuCHILD, a->src_dentry, &a->h_path); ++ if (d_is_positive(a->dst_h_dentry)) { ++ au_fset_ren(a->auren_flags, DT_DSTDIR); ++ a->h_path.dentry = a->dst_h_dentry; ++ au_dtime_store(a->dst_dt + AuCHILD, a->dst_dentry, &a->h_path); ++ } ++} ++ ++static void au_ren_rev_dt(int err, struct au_ren_args *a) ++{ ++ struct dentry *h_d; ++ struct inode *h_inode; ++ ++ au_dtime_revert(a->src_dt + AuPARENT); ++ if (!au_ftest_ren(a->auren_flags, ISSAMEDIR)) ++ au_dtime_revert(a->dst_dt + AuPARENT); ++ ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC) && err != -EIO) { ++ h_d = a->src_dt[AuCHILD].dt_h_path.dentry; ++ h_inode = d_inode(h_d); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ au_dtime_revert(a->src_dt + AuCHILD); ++ inode_unlock(h_inode); ++ ++ if (au_ftest_ren(a->auren_flags, DT_DSTDIR)) { ++ h_d = a->dst_dt[AuCHILD].dt_h_path.dentry; ++ h_inode = d_inode(h_d); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ au_dtime_revert(a->dst_dt + AuCHILD); ++ inode_unlock(h_inode); ++ } ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_rename(struct user_namespace *userns, ++ struct inode *_src_dir, struct dentry *_src_dentry, ++ struct inode *_dst_dir, struct dentry *_dst_dentry, ++ unsigned int _flags) ++{ ++ int err, lock_flags; ++ void *rev; ++ /* reduce stack space */ ++ struct au_ren_args *a; ++ struct au_pin pin; ++ ++ AuDbg("%pd, %pd, 0x%x\n", _src_dentry, _dst_dentry, _flags); ++ IMustLock(_src_dir); ++ IMustLock(_dst_dir); ++ ++ err = -EINVAL; ++ if (unlikely(_flags & RENAME_WHITEOUT)) ++ goto out; ++ ++ err = -ENOMEM; ++ BUILD_BUG_ON(sizeof(*a) > PAGE_SIZE); ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ 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; ++ a->src_inode = NULL; ++ if (d_really_is_positive(a->src_dentry)) ++ a->src_inode = d_inode(a->src_dentry); ++ a->src_parent = a->src_dentry->d_parent; /* dir inode is locked */ ++ a->dst_dir = _dst_dir; ++ a->dst_dentry = _dst_dentry; ++ a->dst_inode = NULL; ++ if (d_really_is_positive(a->dst_dentry)) ++ a->dst_inode = d_inode(a->dst_dentry); ++ a->dst_parent = a->dst_dentry->d_parent; /* dir inode is locked */ ++ if (a->dst_inode) { ++ /* ++ * if EXCHANGE && src is non-dir && dst is dir, ++ * dst is not locked. ++ */ ++ /* IMustLock(a->dst_inode); */ ++ au_igrab(a->dst_inode); ++ } ++ ++ err = -ENOTDIR; ++ lock_flags = AuLock_FLUSH | AuLock_NOPLM | AuLock_GEN; ++ if (d_is_dir(a->src_dentry)) { ++ au_fset_ren(a->auren_flags, ISDIR_SRC); ++ if (unlikely(!a->exchange ++ && d_really_is_positive(a->dst_dentry) ++ && !d_is_dir(a->dst_dentry))) ++ goto out_free; ++ lock_flags |= AuLock_DIRS; ++ } ++ if (a->dst_inode && d_is_dir(a->dst_dentry)) { ++ au_fset_ren(a->auren_flags, ISDIR_DST); ++ if (unlikely(!a->exchange ++ && d_really_is_positive(a->src_dentry) ++ && !d_is_dir(a->src_dentry))) ++ goto out_free; ++ lock_flags |= AuLock_DIRS; ++ } ++ err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, ++ lock_flags); ++ if (unlikely(err)) ++ goto out_free; ++ ++ err = au_d_hashed_positive(a->src_dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ err = -ENOENT; ++ if (a->dst_inode) { ++ /* ++ * If it is a dir, VFS unhash it before this ++ * function. It means we cannot rely upon d_unhashed(). ++ */ ++ if (unlikely(!a->dst_inode->i_nlink)) ++ goto out_unlock; ++ if (!au_ftest_ren(a->auren_flags, ISDIR_DST)) { ++ err = au_d_hashed_positive(a->dst_dentry); ++ if (unlikely(err && !a->exchange)) ++ goto out_unlock; ++ } else if (unlikely(IS_DEADDIR(a->dst_inode))) ++ goto out_unlock; ++ } else if (unlikely(d_unhashed(a->dst_dentry))) ++ goto out_unlock; ++ ++ /* ++ * is it possible? ++ * yes, it happened (in linux-3.3-rcN) but I don't know why. ++ * there may exist a problem somewhere else. ++ */ ++ err = -EINVAL; ++ if (unlikely(d_inode(a->dst_parent) == d_inode(a->src_dentry))) ++ goto out_unlock; ++ ++ au_fset_ren(a->auren_flags, ISSAMEDIR); /* temporary */ ++ di_write_lock_parent(a->dst_parent); ++ ++ /* which branch we process */ ++ err = au_ren_wbr(a); ++ if (unlikely(err < 0)) ++ goto out_parent; ++ a->br = au_sbr(a->dst_dentry->d_sb, a->btgt); ++ a->h_path.mnt = au_br_mnt(a->br); ++ ++ /* are they available to be renamed */ ++ err = au_ren_may_dir(a); ++ if (unlikely(err)) ++ goto out_children; ++ ++ /* prepare the writable parent dir on the same branch */ ++ if (a->dst_btop == a->btgt) { ++ au_fset_ren(a->auren_flags, WHDST); ++ } else { ++ err = au_cpup_dirs(a->dst_dentry, a->btgt); ++ if (unlikely(err)) ++ goto out_children; ++ } ++ ++ err = 0; ++ if (!a->exchange) { ++ if (a->src_dir != a->dst_dir) { ++ /* ++ * this temporary unlock is safe, ++ * because both dir->i_mutex are locked. ++ */ ++ di_write_unlock(a->dst_parent); ++ di_write_lock_parent(a->src_parent); ++ err = au_wr_dir_need_wh(a->src_dentry, ++ au_ftest_ren(a->auren_flags, ++ ISDIR_SRC), ++ &a->btgt); ++ di_write_unlock(a->src_parent); ++ di_write_lock2_parent(a->src_parent, a->dst_parent, ++ /*isdir*/1); ++ au_fclr_ren(a->auren_flags, ISSAMEDIR); ++ } else ++ err = au_wr_dir_need_wh(a->src_dentry, ++ au_ftest_ren(a->auren_flags, ++ ISDIR_SRC), ++ &a->btgt); ++ } ++ if (unlikely(err < 0)) ++ goto out_children; ++ if (err) ++ au_fset_ren(a->auren_flags, WHSRC); ++ ++ /* cpup src */ ++ if (a->src_btop != a->btgt) { ++ err = au_pin(&pin, a->src_dentry, a->btgt, ++ au_opt_udba(a->src_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ struct au_cp_generic cpg = { ++ .dentry = a->src_dentry, ++ .bdst = a->btgt, ++ .bsrc = a->src_btop, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ AuDebugOn(au_dbtop(a->src_dentry) != a->src_btop); ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ if (unlikely(err)) ++ goto out_children; ++ a->src_btop = a->btgt; ++ a->src_h_dentry = au_h_dptr(a->src_dentry, a->btgt); ++ if (!a->exchange) ++ au_fset_ren(a->auren_flags, WHSRC); ++ } ++ ++ /* cpup dst */ ++ if (a->exchange && a->dst_inode ++ && a->dst_btop != a->btgt) { ++ err = au_pin(&pin, a->dst_dentry, a->btgt, ++ au_opt_udba(a->dst_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ struct au_cp_generic cpg = { ++ .dentry = a->dst_dentry, ++ .bdst = a->btgt, ++ .bsrc = a->dst_btop, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ if (unlikely(err)) ++ goto out_children; ++ a->dst_btop = a->btgt; ++ a->dst_h_dentry = au_h_dptr(a->dst_dentry, a->btgt); ++ } ++ ++ /* lock them all */ ++ err = au_ren_lock(a); ++ if (unlikely(err)) ++ /* leave the copied-up one */ ++ goto out_children; ++ ++ if (!a->exchange) { ++ if (!au_opt_test(au_mntflags(a->dst_dir->i_sb), UDBA_NONE)) ++ err = au_may_ren(a); ++ else if (unlikely(a->dst_dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ err = -ENAMETOOLONG; ++ if (unlikely(err)) ++ goto out_hdir; ++ } ++ ++ /* store timestamps to be revertible */ ++ au_ren_dt(a); ++ ++ /* store dirren info */ ++ if (au_ftest_ren(a->auren_flags, DIRREN)) { ++ err = au_dr_rename(a->src_dentry, a->btgt, ++ &a->dst_dentry->d_name, &rev); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out_dt; ++ } ++ ++ /* here we go */ ++ err = do_rename(a); ++ if (unlikely(err)) ++ goto out_dirren; ++ ++ if (au_ftest_ren(a->auren_flags, DIRREN)) ++ au_dr_rename_fin(a->src_dentry, a->btgt, rev); ++ ++ /* update dir attributes */ ++ au_ren_refresh_dir(a); ++ ++ /* dput/iput all lower dentries */ ++ au_ren_refresh(a); ++ ++ goto out_hdir; /* success */ ++ ++out_dirren: ++ if (au_ftest_ren(a->auren_flags, DIRREN)) ++ au_dr_rename_rev(a->src_dentry, a->btgt, rev); ++out_dt: ++ au_ren_rev_dt(err, a); ++out_hdir: ++ au_ren_unlock(a); ++out_children: ++ au_nhash_wh_free(&a->whlist); ++ if (err && a->dst_inode && a->dst_btop != a->btgt) { ++ AuDbg("btop %d, btgt %d\n", a->dst_btop, a->btgt); ++ au_set_h_dptr(a->dst_dentry, a->btgt, NULL); ++ au_set_dbtop(a->dst_dentry, a->dst_btop); ++ } ++out_parent: ++ if (!err) { ++ if (d_unhashed(a->src_dentry)) ++ au_fset_ren(a->auren_flags, DROPPED_SRC); ++ if (d_unhashed(a->dst_dentry)) ++ au_fset_ren(a->auren_flags, DROPPED_DST); ++ if (!a->exchange) ++ d_move(a->src_dentry, a->dst_dentry); ++ else { ++ d_exchange(a->src_dentry, a->dst_dentry); ++ if (au_ftest_ren(a->auren_flags, DROPPED_DST)) ++ d_drop(a->dst_dentry); ++ } ++ if (au_ftest_ren(a->auren_flags, DROPPED_SRC)) ++ d_drop(a->src_dentry); ++ } else { ++ au_update_dbtop(a->dst_dentry); ++ if (!a->dst_inode) ++ d_drop(a->dst_dentry); ++ } ++ if (au_ftest_ren(a->auren_flags, ISSAMEDIR)) ++ di_write_unlock(a->dst_parent); ++ else ++ di_write_unlock2(a->src_parent, a->dst_parent); ++out_unlock: ++ aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry); ++out_free: ++ iput(a->dst_inode); ++ if (a->thargs) ++ au_whtmp_rmdir_free(a->thargs); ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff -Naur null/fs/aufs/Kconfig linux-5.15.36/fs/aufs/Kconfig +--- /dev/null ++++ linux-5.15.36/fs/aufs/Kconfig 2022-05-10 16:51:39.866744220 +0300 +@@ -0,0 +1,199 @@ ++# SPDX-License-Identifier: GPL-2.0 ++config AUFS_FS ++ tristate "Aufs (Advanced multi layered unification filesystem) support" ++ help ++ Aufs is a stackable unification filesystem such as Unionfs, ++ which unifies several directories and provides a merged single ++ directory. ++ In the early days, aufs was entirely re-designed and ++ re-implemented Unionfs Version 1.x series. Introducing many ++ original ideas, approaches and improvements, it becomes totally ++ different from Unionfs while keeping the basic features. ++ ++if AUFS_FS ++choice ++ prompt "Maximum number of branches" ++ default AUFS_BRANCH_MAX_127 ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_127 ++ bool "127" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_511 ++ bool "511" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_1023 ++ bool "1023" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_32767 ++ bool "32767" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++endchoice ++ ++config AUFS_SBILIST ++ bool ++ depends on AUFS_MAGIC_SYSRQ || PROC_FS ++ default y ++ help ++ Automatic configuration for internal use. ++ When aufs supports Magic SysRq or /proc, enabled automatically. ++ ++config AUFS_HNOTIFY ++ bool "Detect direct branch access (bypassing aufs)" ++ help ++ If you want to modify files on branches directly, eg. bypassing aufs, ++ and want aufs to detect the changes of them fully, then enable this ++ option and use 'udba=notify' mount option. ++ Currently there is only one available configuration, "fsnotify". ++ It will have a negative impact to the performance. ++ See detail in aufs.5. ++ ++choice ++ prompt "method" if AUFS_HNOTIFY ++ default AUFS_HFSNOTIFY ++config AUFS_HFSNOTIFY ++ bool "fsnotify" ++ select FSNOTIFY ++endchoice ++ ++config AUFS_EXPORT ++ bool "NFS-exportable aufs" ++ depends on EXPORTFS ++ help ++ If you want to export your mounted aufs via NFS, then enable this ++ option. There are several requirements for this configuration. ++ See detail in aufs.5. ++ ++config AUFS_INO_T_64 ++ bool ++ depends on AUFS_EXPORT ++ depends on 64BIT && !(ALPHA || S390) ++ default y ++ help ++ Automatic configuration for internal use. ++ /* typedef unsigned long/int __kernel_ino_t */ ++ /* alpha and s390x are int */ ++ ++config AUFS_XATTR ++ bool "support for XATTR/EA (including Security Labels)" ++ help ++ If your branch fs supports XATTR/EA and you want to make them ++ available in aufs too, then enable this opsion and specify the ++ branch attributes for EA. ++ See detail in aufs.5. ++ ++config AUFS_FHSM ++ bool "File-based Hierarchical Storage Management" ++ help ++ Hierarchical Storage Management (or HSM) is a well-known feature ++ in the storage world. Aufs provides this feature as file-based. ++ with multiple branches. ++ These multiple branches are prioritized, ie. the topmost one ++ should be the fastest drive and be used heavily. ++ ++config AUFS_RDU ++ bool "Readdir in userspace" ++ help ++ Aufs has two methods to provide a merged view for a directory, ++ by a user-space library and by kernel-space natively. The latter ++ is always enabled but sometimes large and slow. ++ If you enable this option, install the library in aufs2-util ++ package, and set some environment variables for your readdir(3), ++ then the work will be handled in user-space which generally ++ shows better performance in most cases. ++ See detail in aufs.5. ++ ++config AUFS_DIRREN ++ bool "Workaround for rename(2)-ing a directory" ++ help ++ By default, aufs returns EXDEV error in renameing a dir who has ++ his child on the lower branch, since it is a bad idea to issue ++ rename(2) internally for every lower branch. But user may not ++ accept this behaviour. So here is a workaround to allow such ++ rename(2) and store some extra infromation on the writable ++ branch. Obviously this costs high (and I don't like it). ++ To use this feature, you need to enable this configuration AND ++ to specify the mount option `dirren.' ++ See details in aufs.5 and the design documents. ++ ++config AUFS_SHWH ++ bool "Show whiteouts" ++ help ++ If you want to make the whiteouts in aufs visible, then enable ++ this option and specify 'shwh' mount option. Although it may ++ sounds like philosophy or something, but in technically it ++ simply shows the name of whiteout with keeping its behaviour. ++ ++config AUFS_BR_RAMFS ++ bool "Ramfs (initramfs/rootfs) as an aufs branch" ++ help ++ If you want to use ramfs as an aufs branch fs, then enable this ++ option. Generally tmpfs is recommended. ++ Aufs prohibited them to be a branch fs by default, because ++ initramfs becomes unusable after switch_root or something ++ generally. If you sets initramfs as an aufs branch and boot your ++ system by switch_root, you will meet a problem easily since the ++ files in initramfs may be inaccessible. ++ Unless you are going to use ramfs as an aufs branch fs without ++ switch_root or something, leave it N. ++ ++config AUFS_BR_FUSE ++ bool "Fuse fs as an aufs branch" ++ depends on FUSE_FS ++ select AUFS_POLL ++ help ++ If you want to use fuse-based userspace filesystem as an aufs ++ branch fs, then enable this option. ++ It implements the internal poll(2) operation which is ++ implemented by fuse only (curretnly). ++ ++config AUFS_POLL ++ bool ++ help ++ Automatic configuration for internal use. ++ ++config AUFS_BR_HFSPLUS ++ bool "Hfsplus as an aufs branch" ++ depends on HFSPLUS_FS ++ default y ++ help ++ If you want to use hfsplus fs as an aufs branch fs, then enable ++ this option. This option introduces a small overhead at ++ copying-up a file on hfsplus. ++ ++config AUFS_BDEV_LOOP ++ bool ++ depends on BLK_DEV_LOOP ++ default y ++ help ++ Automatic configuration for internal use. ++ Convert =[ym] into =y. ++ ++config AUFS_DEBUG ++ bool "Debug aufs" ++ help ++ Enable this to compile aufs internal debug code. ++ It will have a negative impact to the performance. ++ ++config AUFS_MAGIC_SYSRQ ++ bool ++ depends on AUFS_DEBUG && MAGIC_SYSRQ ++ default y ++ help ++ Automatic configuration for internal use. ++ When aufs supports Magic SysRq, enabled automatically. ++endif +diff -Naur null/fs/aufs/lcnt.h linux-5.15.36/fs/aufs/lcnt.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/lcnt.h 2022-05-10 16:51:39.874744219 +0300 +@@ -0,0 +1,186 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2018-2021 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 -Naur null/fs/aufs/loop.c linux-5.15.36/fs/aufs/loop.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/loop.c 2022-05-10 16:51:39.874744219 +0300 +@@ -0,0 +1,148 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * support for loopback block device as a branch ++ */ ++ ++#include "aufs.h" ++ ++/* added into drivers/block/loop.c */ ++static struct file *(*backing_file_func)(struct super_block *sb); ++ ++/* ++ * test if two lower dentries have overlapping branches. ++ */ ++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding) ++{ ++ struct super_block *h_sb; ++ struct file *backing_file; ++ ++ if (unlikely(!backing_file_func)) { ++ /* don't load "loop" module here */ ++ backing_file_func = symbol_get(loop_backing_file); ++ if (unlikely(!backing_file_func)) ++ /* "loop" module is not loaded */ ++ return 0; ++ } ++ ++ h_sb = h_adding->d_sb; ++ backing_file = backing_file_func(h_sb); ++ if (!backing_file) ++ return 0; ++ ++ h_adding = backing_file->f_path.dentry; ++ /* ++ * h_adding can be local NFS. ++ * in this case aufs cannot detect the loop. ++ */ ++ if (unlikely(h_adding->d_sb == sb)) ++ return 1; ++ return !!au_test_subdir(h_adding, sb->s_root); ++} ++ ++/* true if a kernel thread named 'loop[0-9].*' accesses a file */ ++int au_test_loopback_kthread(void) ++{ ++ int ret; ++ struct task_struct *tsk = current; ++ char c, comm[sizeof(tsk->comm)]; ++ ++ ret = 0; ++ if (tsk->flags & PF_KTHREAD) { ++ get_task_comm(comm, tsk); ++ c = comm[4]; ++ ret = ('0' <= c && c <= '9' ++ && !strncmp(comm, "loop", 4)); ++ } ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define au_warn_loopback_step 16 ++static int au_warn_loopback_nelem = au_warn_loopback_step; ++static unsigned long *au_warn_loopback_array; ++ ++void au_warn_loopback(struct super_block *h_sb) ++{ ++ int i, new_nelem; ++ unsigned long *a, magic; ++ static DEFINE_SPINLOCK(spin); ++ ++ magic = h_sb->s_magic; ++ spin_lock(&spin); ++ a = au_warn_loopback_array; ++ for (i = 0; i < au_warn_loopback_nelem && *a; i++) ++ if (a[i] == magic) { ++ spin_unlock(&spin); ++ return; ++ } ++ ++ /* h_sb is new to us, print it */ ++ if (i < au_warn_loopback_nelem) { ++ a[i] = magic; ++ goto pr; ++ } ++ ++ /* expand the array */ ++ new_nelem = au_warn_loopback_nelem + au_warn_loopback_step; ++ a = au_kzrealloc(au_warn_loopback_array, ++ au_warn_loopback_nelem * sizeof(unsigned long), ++ new_nelem * sizeof(unsigned long), GFP_ATOMIC, ++ /*may_shrink*/0); ++ if (a) { ++ au_warn_loopback_nelem = new_nelem; ++ au_warn_loopback_array = a; ++ a[i] = magic; ++ goto pr; ++ } ++ ++ spin_unlock(&spin); ++ AuWarn1("realloc failed, ignored\n"); ++ return; ++ ++pr: ++ spin_unlock(&spin); ++ pr_warn("you may want to try another patch for loopback file " ++ "on %s(0x%lx) branch\n", au_sbtype(h_sb), magic); ++} ++ ++int au_loopback_init(void) ++{ ++ int err; ++ struct super_block *sb __maybe_unused; ++ ++ BUILD_BUG_ON(sizeof(sb->s_magic) != sizeof(*au_warn_loopback_array)); ++ ++ err = 0; ++ au_warn_loopback_array = kcalloc(au_warn_loopback_step, ++ sizeof(unsigned long), GFP_NOFS); ++ if (unlikely(!au_warn_loopback_array)) ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++void au_loopback_fin(void) ++{ ++ if (backing_file_func) ++ symbol_put(loop_backing_file); ++ au_kfree_try_rcu(au_warn_loopback_array); ++} +diff -Naur null/fs/aufs/loop.h linux-5.15.36/fs/aufs/loop.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/loop.h 2022-05-10 16:51:39.874744219 +0300 +@@ -0,0 +1,55 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * support for loopback mount as a branch ++ */ ++ ++#ifndef __AUFS_LOOP_H__ ++#define __AUFS_LOOP_H__ ++ ++#ifdef __KERNEL__ ++ ++struct dentry; ++struct super_block; ++ ++#ifdef CONFIG_AUFS_BDEV_LOOP ++/* drivers/block/loop.c */ ++struct file *loop_backing_file(struct super_block *sb); ++ ++/* loop.c */ ++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding); ++int au_test_loopback_kthread(void); ++void au_warn_loopback(struct super_block *h_sb); ++ ++int au_loopback_init(void); ++void au_loopback_fin(void); ++#else ++AuStub(struct file *, loop_backing_file, return NULL, struct super_block *sb) ++ ++AuStubInt0(au_test_loopback_overlap, struct super_block *sb, ++ struct dentry *h_adding) ++AuStubInt0(au_test_loopback_kthread, void) ++AuStubVoid(au_warn_loopback, struct super_block *h_sb) ++ ++AuStubInt0(au_loopback_init, void) ++AuStubVoid(au_loopback_fin, void) ++#endif /* BLK_DEV_LOOP */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_LOOP_H__ */ +diff -Naur null/fs/aufs/magic.mk linux-5.15.36/fs/aufs/magic.mk +--- /dev/null ++++ linux-5.15.36/fs/aufs/magic.mk 2022-05-10 16:51:39.874744219 +0300 +@@ -0,0 +1,31 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++# defined in ${srctree}/fs/fuse/inode.c ++# tristate ++ifdef CONFIG_FUSE_FS ++ccflags-y += -DFUSE_SUPER_MAGIC=0x65735546 ++endif ++ ++# defined in ${srctree}/fs/xfs/xfs_sb.h ++# tristate ++ifdef CONFIG_XFS_FS ++ccflags-y += -DXFS_SB_MAGIC=0x58465342 ++endif ++ ++# defined in ${srctree}/fs/configfs/mount.c ++# tristate ++ifdef CONFIG_CONFIGFS_FS ++ccflags-y += -DCONFIGFS_MAGIC=0x62656570 ++endif ++ ++# defined in ${srctree}/fs/ubifs/ubifs.h ++# tristate ++ifdef CONFIG_UBIFS_FS ++ccflags-y += -DUBIFS_SUPER_MAGIC=0x24051905 ++endif ++ ++# defined in ${srctree}/fs/hfsplus/hfsplus_raw.h ++# tristate ++ifdef CONFIG_HFSPLUS_FS ++ccflags-y += -DHFSPLUS_SUPER_MAGIC=0x482b ++endif +diff -Naur null/fs/aufs/Makefile linux-5.15.36/fs/aufs/Makefile +--- /dev/null ++++ linux-5.15.36/fs/aufs/Makefile 2022-05-10 16:51:39.866744220 +0300 +@@ -0,0 +1,46 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++include ${src}/magic.mk ++ifeq (${CONFIG_AUFS_FS},m) ++include ${src}/conf.mk ++endif ++-include ${src}/priv_def.mk ++ ++# cf. include/linux/kernel.h ++# enable pr_debug ++ccflags-y += -DDEBUG ++# sparse requires the full pathname ++ifdef M ++ccflags-y += -include ${M}/../../include/uapi/linux/aufs_type.h ++else ++ccflags-y += -include ${srctree}/include/uapi/linux/aufs_type.h ++endif ++ ++obj-$(CONFIG_AUFS_FS) += aufs.o ++aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o fsctx.o \ ++ wkq.o vfsub.o dcsub.o \ ++ cpup.o whout.o wbr_policy.o \ ++ dinfo.o dentry.o \ ++ dynop.o \ ++ finfo.o file.o f_op.o \ ++ dir.o vdir.o \ ++ iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o \ ++ mvdown.o ioctl.o ++ ++# all are boolean ++aufs-$(CONFIG_PROC_FS) += procfs.o plink.o ++aufs-$(CONFIG_SYSFS) += sysfs.o ++aufs-$(CONFIG_DEBUG_FS) += dbgaufs.o ++aufs-$(CONFIG_AUFS_BDEV_LOOP) += loop.o ++aufs-$(CONFIG_AUFS_HNOTIFY) += hnotify.o ++aufs-$(CONFIG_AUFS_HFSNOTIFY) += hfsnotify.o ++aufs-$(CONFIG_AUFS_EXPORT) += export.o ++aufs-$(CONFIG_AUFS_XATTR) += xattr.o ++aufs-$(CONFIG_FS_POSIX_ACL) += posix_acl.o ++aufs-$(CONFIG_AUFS_DIRREN) += dirren.o ++aufs-$(CONFIG_AUFS_FHSM) += fhsm.o ++aufs-$(CONFIG_AUFS_POLL) += poll.o ++aufs-$(CONFIG_AUFS_RDU) += rdu.o ++aufs-$(CONFIG_AUFS_BR_HFSPLUS) += hfsplus.o ++aufs-$(CONFIG_AUFS_DEBUG) += debug.o ++aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o +diff -Naur null/fs/aufs/module.c linux-5.15.36/fs/aufs/module.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/module.c 2022-05-10 16:51:39.874744219 +0300 +@@ -0,0 +1,273 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * module global variables and operations ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++/* shrinkable realloc */ ++void *au_krealloc(void *p, unsigned int new_sz, gfp_t gfp, int may_shrink) ++{ ++ size_t sz; ++ int diff; ++ ++ sz = 0; ++ diff = -1; ++ if (p) { ++#if 0 /* unused */ ++ if (!new_sz) { ++ au_kfree_rcu(p); ++ p = NULL; ++ goto out; ++ } ++#else ++ AuDebugOn(!new_sz); ++#endif ++ sz = ksize(p); ++ diff = au_kmidx_sub(sz, new_sz); ++ } ++ if (sz && !diff) ++ goto out; ++ ++ if (sz < new_sz) ++ /* expand or SLOB */ ++ p = krealloc(p, new_sz, gfp); ++ else if (new_sz < sz && may_shrink) { ++ /* shrink */ ++ void *q; ++ ++ q = kmalloc(new_sz, gfp); ++ if (q) { ++ if (p) { ++ memcpy(q, p, new_sz); ++ au_kfree_try_rcu(p); ++ } ++ p = q; ++ } else ++ p = NULL; ++ } ++ ++out: ++ return p; ++} ++ ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp, ++ int may_shrink) ++{ ++ p = au_krealloc(p, new_sz, gfp, may_shrink); ++ if (p && new_sz > nused) ++ memset(p + nused, 0, new_sz - nused); ++ return p; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * aufs caches ++ */ ++struct kmem_cache *au_cache[AuCache_Last]; ++ ++static void au_cache_fin(void) ++{ ++ int i; ++ ++ /* ++ * Make sure all delayed rcu free inodes are flushed before we ++ * destroy cache. ++ */ ++ rcu_barrier(); ++ ++ /* excluding AuCache_HNOTIFY */ ++ BUILD_BUG_ON(AuCache_HNOTIFY + 1 != AuCache_Last); ++ for (i = 0; i < AuCache_HNOTIFY; i++) { ++ kmem_cache_destroy(au_cache[i]); ++ au_cache[i] = NULL; ++ } ++} ++ ++static int __init au_cache_init(void) ++{ ++ au_cache[AuCache_DINFO] = AuCacheCtor(au_dinfo, au_di_init_once); ++ if (au_cache[AuCache_DINFO]) ++ /* SLAB_DESTROY_BY_RCU */ ++ au_cache[AuCache_ICNTNR] = AuCacheCtor(au_icntnr, ++ au_icntnr_init_once); ++ if (au_cache[AuCache_ICNTNR]) ++ au_cache[AuCache_FINFO] = AuCacheCtor(au_finfo, ++ au_fi_init_once); ++ if (au_cache[AuCache_FINFO]) ++ au_cache[AuCache_VDIR] = AuCache(au_vdir); ++ if (au_cache[AuCache_VDIR]) ++ au_cache[AuCache_DEHSTR] = AuCache(au_vdir_dehstr); ++ if (au_cache[AuCache_DEHSTR]) ++ return 0; ++ ++ au_cache_fin(); ++ return -ENOMEM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dir_roflags; ++ ++#ifdef CONFIG_AUFS_SBILIST ++/* ++ * iterate_supers_type() doesn't protect us from ++ * remounting (branch management) ++ */ ++struct hlist_bl_head au_sbilist; ++#endif ++ ++/* ++ * functions for module interface. ++ */ ++MODULE_LICENSE("GPL"); ++/* MODULE_LICENSE("GPL v2"); */ ++MODULE_AUTHOR("Junjiro R. Okajima "); ++MODULE_DESCRIPTION(AUFS_NAME ++ " -- Advanced multi layered unification filesystem"); ++MODULE_VERSION(AUFS_VERSION); ++MODULE_ALIAS_FS(AUFS_NAME); ++ ++/* 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, 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, 0444); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */ ++ ++int au_seq_path(struct seq_file *seq, struct path *path) ++{ ++ int err; ++ ++ err = seq_path(seq, path, au_esc_chars); ++ if (err >= 0) ++ err = 0; ++ else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int __init aufs_init(void) ++{ ++ int err, i; ++ char *p; ++ ++ p = au_esc_chars; ++ for (i = 1; i <= ' '; i++) ++ *p++ = i; ++ *p++ = '\\'; ++ *p++ = '\x7f'; ++ *p = 0; ++ ++ au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE); ++ ++ memcpy(aufs_iop_nogetattr, aufs_iop, sizeof(aufs_iop)); ++ for (i = 0; i < AuIop_Last; i++) ++ aufs_iop_nogetattr[i].getattr = NULL; ++ ++ memset(au_cache, 0, sizeof(au_cache)); /* including hnotify */ ++ ++ au_sbilist_init(); ++ sysaufs_brs_init(); ++ au_debug_init(); ++ au_dy_init(); ++ err = sysaufs_init(); ++ if (unlikely(err)) ++ goto out; ++ 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; ++ err = au_loopback_init(); ++ if (unlikely(err)) ++ goto out_wkq; ++ err = au_hnotify_init(); ++ if (unlikely(err)) ++ goto out_loopback; ++ err = au_sysrq_init(); ++ if (unlikely(err)) ++ goto out_hin; ++ err = au_cache_init(); ++ if (unlikely(err)) ++ goto out_sysrq; ++ ++ aufs_fs_type.fs_flags |= au_userns ? FS_USERNS_MOUNT : 0; ++ err = register_filesystem(&aufs_fs_type); ++ if (unlikely(err)) ++ goto out_cache; ++ ++ /* since we define pr_fmt, call printk directly */ ++ printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n"); ++ goto out; /* success */ ++ ++out_cache: ++ au_cache_fin(); ++out_sysrq: ++ au_sysrq_fin(); ++out_hin: ++ au_hnotify_fin(); ++out_loopback: ++ au_loopback_fin(); ++out_wkq: ++ au_wkq_fin(); ++out_procfs: ++ au_procfs_fin(); ++out_dbgaufs: ++ dbgaufs_fin(); ++out_sysaufs: ++ sysaufs_fin(); ++ au_dy_fin(); ++out: ++ return err; ++} ++ ++static void __exit aufs_exit(void) ++{ ++ unregister_filesystem(&aufs_fs_type); ++ au_cache_fin(); ++ au_sysrq_fin(); ++ au_hnotify_fin(); ++ au_loopback_fin(); ++ au_wkq_fin(); ++ au_procfs_fin(); ++ dbgaufs_fin(); ++ sysaufs_fin(); ++ au_dy_fin(); ++} ++ ++module_init(aufs_init); ++module_exit(aufs_exit); +diff -Naur null/fs/aufs/module.h linux-5.15.36/fs/aufs/module.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/module.h 2022-05-10 16:51:39.874744219 +0300 +@@ -0,0 +1,166 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * module initialization and module-global ++ */ ++ ++#ifndef __AUFS_MODULE_H__ ++#define __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; ++ ++/* module parameters */ ++extern int sysaufs_brs; ++extern bool au_userns; ++ ++/* ---------------------------------------------------------------------- */ ++ ++extern int au_dir_roflags; ++ ++void *au_krealloc(void *p, unsigned int new_sz, gfp_t gfp, int may_shrink); ++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 ++ return __kmalloc_index(sz, false) - __kmalloc_index(new_sz, false); ++#else ++ return -1; /* SLOB is untested */ ++#endif ++} ++ ++int au_seq_path(struct seq_file *seq, struct path *path); ++ ++#ifdef CONFIG_PROC_FS ++/* procfs.c */ ++int __init au_procfs_init(void); ++void au_procfs_fin(void); ++#else ++AuStubInt0(au_procfs_init, void); ++AuStubVoid(au_procfs_fin, void); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* kmem cache */ ++enum { ++ AuCache_DINFO, ++ AuCache_ICNTNR, ++ AuCache_FINFO, ++ AuCache_VDIR, ++ AuCache_DEHSTR, ++ AuCache_HNOTIFY, /* must be last */ ++ AuCache_Last ++}; ++ ++extern struct kmem_cache *au_cache[AuCache_Last]; ++ ++#define AuCacheFlags (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD) ++#define AuCache(type) KMEM_CACHE(type, AuCacheFlags) ++#define AuCacheCtor(type, ctor) \ ++ 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##_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); ++AuCacheFuncs(finfo, FINFO); ++AuCacheFuncs(vdir, VDIR); ++AuCacheFuncs(vdir_dehstr, DEHSTR); ++#ifdef CONFIG_AUFS_HNOTIFY ++AuCacheFuncs(hnotify, HNOTIFY); ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_MODULE_H__ */ +diff -Naur null/fs/aufs/mvdown.c linux-5.15.36/fs/aufs/mvdown.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/mvdown.c 2022-05-10 16:51:39.874744219 +0300 +@@ -0,0 +1,706 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2011-2021 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 . ++ */ ++ ++/* ++ * move-down, opposite of copy-up ++ */ ++ ++#include "aufs.h" ++ ++struct au_mvd_args { ++ struct { ++ struct super_block *h_sb; ++ struct dentry *h_parent; ++ struct au_hinode *hdir; ++ struct inode *h_dir, *h_inode; ++ struct au_pin pin; ++ } info[AUFS_MVDOWN_NARRAY]; ++ ++ struct aufs_mvdown mvdown; ++ struct dentry *dentry, *parent; ++ struct inode *inode, *dir; ++ struct super_block *sb; ++ aufs_bindex_t bopq, bwh, bfound; ++ unsigned char rename_lock; ++}; ++ ++#define mvd_errno mvdown.au_errno ++#define mvd_bsrc mvdown.stbr[AUFS_MVDOWN_UPPER].bindex ++#define mvd_src_brid mvdown.stbr[AUFS_MVDOWN_UPPER].brid ++#define mvd_bdst mvdown.stbr[AUFS_MVDOWN_LOWER].bindex ++#define mvd_dst_brid mvdown.stbr[AUFS_MVDOWN_LOWER].brid ++ ++#define mvd_h_src_sb info[AUFS_MVDOWN_UPPER].h_sb ++#define mvd_h_src_parent info[AUFS_MVDOWN_UPPER].h_parent ++#define mvd_hdir_src info[AUFS_MVDOWN_UPPER].hdir ++#define mvd_h_src_dir info[AUFS_MVDOWN_UPPER].h_dir ++#define mvd_h_src_inode info[AUFS_MVDOWN_UPPER].h_inode ++#define mvd_pin_src info[AUFS_MVDOWN_UPPER].pin ++ ++#define mvd_h_dst_sb info[AUFS_MVDOWN_LOWER].h_sb ++#define mvd_h_dst_parent info[AUFS_MVDOWN_LOWER].h_parent ++#define mvd_hdir_dst info[AUFS_MVDOWN_LOWER].hdir ++#define mvd_h_dst_dir info[AUFS_MVDOWN_LOWER].h_dir ++#define mvd_h_dst_inode info[AUFS_MVDOWN_LOWER].h_inode ++#define mvd_pin_dst info[AUFS_MVDOWN_LOWER].pin ++ ++#define AU_MVD_PR(flag, ...) do { \ ++ if (flag) \ ++ pr_err(__VA_ARGS__); \ ++ } while (0) ++ ++static int find_lower_writable(struct au_mvd_args *a) ++{ ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ sb = a->sb; ++ bindex = a->mvd_bsrc; ++ bbot = au_sbbot(sb); ++ if (a->mvdown.flags & AUFS_MVDOWN_FHSM_LOWER) ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm) ++ && !sb_rdonly(au_br_sb(br))) ++ return bindex; ++ } ++ else if (!(a->mvdown.flags & AUFS_MVDOWN_ROLOWER)) ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_rdonly(br)) ++ return bindex; ++ } ++ else ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!sb_rdonly(au_br_sb(br))) { ++ if (au_br_rdonly(br)) ++ a->mvdown.flags ++ |= AUFS_MVDOWN_ROLOWER_R; ++ return bindex; ++ } ++ } ++ ++ return -1; ++} ++ ++/* make the parent dir on bdst */ ++static int au_do_mkdir(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = 0; ++ a->mvd_hdir_src = au_hi(a->dir, a->mvd_bsrc); ++ a->mvd_hdir_dst = au_hi(a->dir, a->mvd_bdst); ++ a->mvd_h_src_parent = au_h_dptr(a->parent, a->mvd_bsrc); ++ a->mvd_h_dst_parent = NULL; ++ if (au_dbbot(a->parent) >= a->mvd_bdst) ++ a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); ++ if (!a->mvd_h_dst_parent) { ++ err = au_cpdown_dirs(a->dentry, a->mvd_bdst); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "cpdown_dirs failed\n"); ++ goto out; ++ } ++ a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* lock them all */ ++static int au_do_lock(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct dentry *h_trap; ++ ++ a->mvd_h_src_sb = au_sbr_sb(a->sb, a->mvd_bsrc); ++ a->mvd_h_dst_sb = au_sbr_sb(a->sb, a->mvd_bdst); ++ err = au_pin(&a->mvd_pin_dst, a->dentry, a->mvd_bdst, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ AuTraceErr(err); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_dst failed\n"); ++ goto out; ++ } ++ ++ if (a->mvd_h_src_sb != a->mvd_h_dst_sb) { ++ a->rename_lock = 0; ++ au_pin_init(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, ++ AuLsc_DI_PARENT, AuLsc_I_PARENT3, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ err = au_do_pin(&a->mvd_pin_src); ++ AuTraceErr(err); ++ a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_src failed\n"); ++ goto out_dst; ++ } ++ goto out; /* success */ ++ } ++ ++ a->rename_lock = 1; ++ au_pin_hdir_unlock(&a->mvd_pin_dst); ++ err = au_pin(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ AuTraceErr(err); ++ a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_src failed\n"); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ goto out_dst; ++ } ++ au_pin_hdir_unlock(&a->mvd_pin_src); ++ h_trap = vfsub_lock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ if (h_trap) { ++ err = (h_trap != a->mvd_h_src_parent); ++ if (err) ++ err = (h_trap != a->mvd_h_dst_parent); ++ } ++ BUG_ON(err); /* it should never happen */ ++ if (unlikely(a->mvd_h_src_dir != au_pinned_h_dir(&a->mvd_pin_src))) { ++ err = -EBUSY; ++ AuTraceErr(err); ++ vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ au_pin_hdir_lock(&a->mvd_pin_src); ++ au_unpin(&a->mvd_pin_src); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ goto out_dst; ++ } ++ goto out; /* success */ ++ ++out_dst: ++ au_unpin(&a->mvd_pin_dst); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static void au_do_unlock(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ if (!a->rename_lock) ++ au_unpin(&a->mvd_pin_src); ++ else { ++ vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ au_pin_hdir_lock(&a->mvd_pin_src); ++ au_unpin(&a->mvd_pin_src); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ } ++ au_unpin(&a->mvd_pin_dst); ++} ++ ++/* copy-down the file */ ++static int au_do_cpdown(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_cp_generic cpg = { ++ .dentry = a->dentry, ++ .bdst = a->mvd_bdst, ++ .bsrc = a->mvd_bsrc, ++ .len = -1, ++ .pin = &a->mvd_pin_dst, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ ++ AuDbg("b%d, b%d\n", cpg.bsrc, cpg.bdst); ++ if (a->mvdown.flags & AUFS_MVDOWN_OWLOWER) ++ au_fset_cpup(cpg.flags, OVERWRITE); ++ if (a->mvdown.flags & AUFS_MVDOWN_ROLOWER) ++ au_fset_cpup(cpg.flags, RWDST); ++ err = au_sio_cpdown_simple(&cpg); ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "cpdown failed\n"); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * unlink the whiteout on bdst if exist which may be created by UDBA while we ++ * were sleeping ++ */ ++static int au_do_unlink_wh(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct path h_path; ++ struct au_branch *br; ++ struct inode *delegated; ++ ++ br = au_sbr(a->sb, a->mvd_bdst); ++ h_path.dentry = au_wh_lkup(a->mvd_h_dst_parent, &a->dentry->d_name, br); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) { ++ AU_MVD_PR(dmsg, "wh_lkup failed\n"); ++ goto out; ++ } ++ ++ err = 0; ++ if (d_is_positive(h_path.dentry)) { ++ h_path.mnt = au_br_mnt(br); ++ delegated = NULL; ++ err = vfsub_unlink(d_inode(a->mvd_h_dst_parent), &h_path, ++ &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "wh_unlink failed\n"); ++ } ++ dput(h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * unlink the topmost h_dentry ++ */ ++static int au_do_unlink(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct path h_path; ++ struct inode *delegated; ++ ++ h_path.mnt = au_sbr_mnt(a->sb, a->mvd_bsrc); ++ h_path.dentry = au_h_dptr(a->dentry, a->mvd_bsrc); ++ delegated = NULL; ++ err = vfsub_unlink(a->mvd_h_src_dir, &h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "unlink failed\n"); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* Since mvdown succeeded, we ignore an error of this function */ ++static void au_do_stfs(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_branch *br; ++ ++ a->mvdown.flags |= AUFS_MVDOWN_STFS_FAILED; ++ br = au_sbr(a->sb, a->mvd_bsrc); ++ err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_UPPER].stfs); ++ if (!err) { ++ br = au_sbr(a->sb, a->mvd_bdst); ++ a->mvdown.stbr[AUFS_MVDOWN_LOWER].brid = br->br_id; ++ err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_LOWER].stfs); ++ } ++ if (!err) ++ a->mvdown.flags &= ~AUFS_MVDOWN_STFS_FAILED; ++ else ++ AU_MVD_PR(dmsg, "statfs failed (%d), ignored\n", err); ++} ++ ++/* ++ * copy-down the file and unlink the bsrc file. ++ * - unlink the bdst whout if exist ++ * - copy-down the file (with whtmp name and rename) ++ * - unlink the bsrc file ++ */ ++static int au_do_mvdown(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = au_do_mkdir(dmsg, a); ++ if (!err) ++ err = au_do_lock(dmsg, a); ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * do not revert the activities we made on bdst since they should be ++ * harmless in aufs. ++ */ ++ ++ err = au_do_cpdown(dmsg, a); ++ if (!err) ++ err = au_do_unlink_wh(dmsg, a); ++ if (!err && !(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) ++ err = au_do_unlink(dmsg, a); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ AuDbg("%pd2, 0x%x, %d --> %d\n", ++ a->dentry, a->mvdown.flags, a->mvd_bsrc, a->mvd_bdst); ++ if (find_lower_writable(a) < 0) ++ a->mvdown.flags |= AUFS_MVDOWN_BOTTOM; ++ ++ if (a->mvdown.flags & AUFS_MVDOWN_STFS) ++ au_do_stfs(dmsg, a); ++ ++ /* maintain internal array */ ++ if (!(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) { ++ au_set_h_dptr(a->dentry, a->mvd_bsrc, NULL); ++ au_set_dbtop(a->dentry, a->mvd_bdst); ++ au_set_h_iptr(a->inode, a->mvd_bsrc, NULL, /*flags*/0); ++ au_set_ibtop(a->inode, a->mvd_bdst); ++ } else { ++ /* hide the lower */ ++ au_set_h_dptr(a->dentry, a->mvd_bdst, NULL); ++ au_set_dbbot(a->dentry, a->mvd_bsrc); ++ au_set_h_iptr(a->inode, a->mvd_bdst, NULL, /*flags*/0); ++ au_set_ibbot(a->inode, a->mvd_bsrc); ++ } ++ if (au_dbbot(a->dentry) < a->mvd_bdst) ++ au_set_dbbot(a->dentry, a->mvd_bdst); ++ if (au_ibbot(a->inode) < a->mvd_bdst) ++ au_set_ibbot(a->inode, a->mvd_bdst); ++ ++out_unlock: ++ au_do_unlock(dmsg, a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* make sure the file is idle */ ++static int au_mvd_args_busy(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err, plinked; ++ ++ err = 0; ++ plinked = !!au_opt_test(au_mntflags(a->sb), PLINK); ++ if (au_dbtop(a->dentry) == a->mvd_bsrc ++ && au_dcount(a->dentry) == 1 ++ && atomic_read(&a->inode->i_count) == 1 ++ /* && a->mvd_h_src_inode->i_nlink == 1 */ ++ && (!plinked || !au_plink_test(a->inode)) ++ && a->inode->i_nlink == 1) ++ goto out; ++ ++ err = -EBUSY; ++ AU_MVD_PR(dmsg, ++ "b%d, d{b%d, c%d?}, i{c%d?, l%u}, hi{l%u}, p{%d, %d}\n", ++ a->mvd_bsrc, au_dbtop(a->dentry), au_dcount(a->dentry), ++ atomic_read(&a->inode->i_count), a->inode->i_nlink, ++ a->mvd_h_src_inode->i_nlink, ++ plinked, plinked ? au_plink_test(a->inode) : 0); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* make sure the parent dir is fine */ ++static int au_mvd_args_parent(const unsigned char dmsg, ++ struct au_mvd_args *a) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ ++ err = 0; ++ if (unlikely(au_alive_dir(a->parent))) { ++ err = -ENOENT; ++ AU_MVD_PR(dmsg, "parent dir is dead\n"); ++ goto out; ++ } ++ ++ a->bopq = au_dbdiropq(a->parent); ++ bindex = au_wbr_nonopq(a->dentry, a->mvd_bdst); ++ AuDbg("b%d\n", bindex); ++ if (unlikely((bindex >= 0 && bindex < a->mvd_bdst) ++ || (a->bopq != -1 && a->bopq < a->mvd_bdst))) { ++ err = -EINVAL; ++ a->mvd_errno = EAU_MVDOWN_OPAQUE; ++ AU_MVD_PR(dmsg, "ancestor is opaque b%d, b%d\n", ++ a->bopq, a->mvd_bdst); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args_intermediate(const unsigned char dmsg, ++ struct au_mvd_args *a) ++{ ++ int err; ++ struct au_dinfo *dinfo, *tmp; ++ ++ /* lookup the next lower positive entry */ ++ err = -ENOMEM; ++ tmp = au_di_alloc(a->sb, AuLsc_DI_TMP); ++ if (unlikely(!tmp)) ++ goto out; ++ ++ a->bfound = -1; ++ a->bwh = -1; ++ dinfo = au_di(a->dentry); ++ au_di_cp(tmp, dinfo); ++ au_di_swap(tmp, dinfo); ++ ++ /* returns the number of positive dentries */ ++ err = au_lkup_dentry(a->dentry, a->mvd_bsrc + 1, ++ /* AuLkup_IGNORE_PERM */ 0); ++ if (!err) ++ a->bwh = au_dbwh(a->dentry); ++ else if (err > 0) ++ a->bfound = au_dbtop(a->dentry); ++ ++ au_di_swap(tmp, dinfo); ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ if (unlikely(err < 0)) ++ AU_MVD_PR(dmsg, "failed look-up lower\n"); ++ ++ /* ++ * here, we have these cases. ++ * bfound == -1 ++ * no positive dentry under bsrc. there are more sub-cases. ++ * bwh < 0 ++ * there no whiteout, we can safely move-down. ++ * bwh <= bsrc ++ * impossible ++ * bsrc < bwh && bwh < bdst ++ * there is a whiteout on RO branch. cannot proceed. ++ * bwh == bdst ++ * there is a whiteout on the RW target branch. it should ++ * be removed. ++ * bdst < bwh ++ * there is a whiteout somewhere unrelated branch. ++ * -1 < bfound && bfound <= bsrc ++ * impossible. ++ * bfound < bdst ++ * found, but it is on RO branch between bsrc and bdst. cannot ++ * proceed. ++ * bfound == bdst ++ * found, replace it if AUFS_MVDOWN_FORCE is set. otherwise return ++ * error. ++ * bdst < bfound ++ * found, after we create the file on bdst, it will be hidden. ++ */ ++ ++ AuDebugOn(a->bfound == -1 ++ && a->bwh != -1 ++ && a->bwh <= a->mvd_bsrc); ++ AuDebugOn(-1 < a->bfound ++ && a->bfound <= a->mvd_bsrc); ++ ++ err = -EINVAL; ++ if (a->bfound == -1 ++ && a->mvd_bsrc < a->bwh ++ && a->bwh != -1 ++ && a->bwh < a->mvd_bdst) { ++ a->mvd_errno = EAU_MVDOWN_WHITEOUT; ++ AU_MVD_PR(dmsg, "bsrc %d, bdst %d, bfound %d, bwh %d\n", ++ a->mvd_bsrc, a->mvd_bdst, a->bfound, a->bwh); ++ goto out; ++ } else if (a->bfound != -1 && a->bfound < a->mvd_bdst) { ++ a->mvd_errno = EAU_MVDOWN_UPPER; ++ AU_MVD_PR(dmsg, "bdst %d, bfound %d\n", ++ a->mvd_bdst, a->bfound); ++ goto out; ++ } ++ ++ err = 0; /* success */ ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args_exist(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = 0; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_OWLOWER) ++ && a->bfound == a->mvd_bdst) ++ err = -EEXIST; ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_branch *br; ++ ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(a->inode->i_mode))) ++ goto out; ++ ++ err = -EINVAL; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_UPPER)) ++ a->mvd_bsrc = au_ibtop(a->inode); ++ else { ++ a->mvd_bsrc = au_br_index(a->sb, a->mvd_src_brid); ++ if (unlikely(a->mvd_bsrc < 0 ++ || (a->mvd_bsrc < au_dbtop(a->dentry) ++ || au_dbbot(a->dentry) < a->mvd_bsrc ++ || !au_h_dptr(a->dentry, a->mvd_bsrc)) ++ || (a->mvd_bsrc < au_ibtop(a->inode) ++ || au_ibbot(a->inode) < a->mvd_bsrc ++ || !au_h_iptr(a->inode, a->mvd_bsrc)))) { ++ a->mvd_errno = EAU_MVDOWN_NOUPPER; ++ AU_MVD_PR(dmsg, "no upper\n"); ++ goto out; ++ } ++ } ++ if (unlikely(a->mvd_bsrc == au_sbbot(a->sb))) { ++ a->mvd_errno = EAU_MVDOWN_BOTTOM; ++ AU_MVD_PR(dmsg, "on the bottom\n"); ++ goto out; ++ } ++ a->mvd_h_src_inode = au_h_iptr(a->inode, a->mvd_bsrc); ++ br = au_sbr(a->sb, a->mvd_bsrc); ++ err = au_br_rdonly(br); ++ if (!(a->mvdown.flags & AUFS_MVDOWN_ROUPPER)) { ++ if (unlikely(err)) ++ goto out; ++ } else if (!(vfsub_native_ro(a->mvd_h_src_inode) ++ || IS_APPEND(a->mvd_h_src_inode))) { ++ if (err) ++ a->mvdown.flags |= AUFS_MVDOWN_ROUPPER_R; ++ /* go on */ ++ } else ++ goto out; ++ ++ err = -EINVAL; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_LOWER)) { ++ a->mvd_bdst = find_lower_writable(a); ++ if (unlikely(a->mvd_bdst < 0)) { ++ a->mvd_errno = EAU_MVDOWN_BOTTOM; ++ AU_MVD_PR(dmsg, "no writable lower branch\n"); ++ goto out; ++ } ++ } else { ++ a->mvd_bdst = au_br_index(a->sb, a->mvd_dst_brid); ++ if (unlikely(a->mvd_bdst < 0 ++ || au_sbbot(a->sb) < a->mvd_bdst)) { ++ a->mvd_errno = EAU_MVDOWN_NOLOWERBR; ++ AU_MVD_PR(dmsg, "no lower brid\n"); ++ goto out; ++ } ++ } ++ ++ err = au_mvd_args_busy(dmsg, a); ++ if (!err) ++ err = au_mvd_args_parent(dmsg, a); ++ if (!err) ++ err = au_mvd_args_intermediate(dmsg, a); ++ if (!err) ++ err = au_mvd_args_exist(dmsg, a); ++ if (!err) ++ AuDbg("b%d, b%d\n", a->mvd_bsrc, a->mvd_bdst); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *uarg) ++{ ++ int err, e; ++ unsigned char dmsg; ++ struct au_mvd_args *args; ++ struct inode *inode; ++ ++ inode = d_inode(dentry); ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -ENOMEM; ++ args = kmalloc(sizeof(*args), GFP_NOFS); ++ if (unlikely(!args)) ++ goto out; ++ ++ err = copy_from_user(&args->mvdown, uarg, sizeof(args->mvdown)); ++ if (!err) ++ /* VERIFY_WRITE */ ++ err = !access_ok(uarg, sizeof(*uarg)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out_free; ++ } ++ AuDbg("flags 0x%x\n", args->mvdown.flags); ++ args->mvdown.flags &= ~(AUFS_MVDOWN_ROLOWER_R | AUFS_MVDOWN_ROUPPER_R); ++ args->mvdown.au_errno = 0; ++ args->dentry = dentry; ++ args->inode = inode; ++ args->sb = dentry->d_sb; ++ ++ err = -ENOENT; ++ dmsg = !!(args->mvdown.flags & AUFS_MVDOWN_DMSG); ++ args->parent = dget_parent(dentry); ++ args->dir = d_inode(args->parent); ++ inode_lock_nested(args->dir, I_MUTEX_PARENT); ++ dput(args->parent); ++ if (unlikely(args->parent != dentry->d_parent)) { ++ AU_MVD_PR(dmsg, "parent dir is moved\n"); ++ goto out_dir; ++ } ++ ++ inode_lock_nested(inode, I_MUTEX_CHILD); ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_NOPLMW); ++ if (unlikely(err)) ++ goto out_inode; ++ ++ di_write_lock_parent(args->parent); ++ err = au_mvd_args(dmsg, args); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ err = au_do_mvdown(dmsg, args); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ au_cpup_attr_timesizes(args->dir); ++ au_cpup_attr_timesizes(inode); ++ if (!(args->mvdown.flags & AUFS_MVDOWN_KUPPER)) ++ au_cpup_igen(inode, au_h_iptr(inode, args->mvd_bdst)); ++ /* au_digen_dec(dentry); */ ++ ++out_parent: ++ di_write_unlock(args->parent); ++ aufs_read_unlock(dentry, AuLock_DW); ++out_inode: ++ inode_unlock(inode); ++out_dir: ++ inode_unlock(args->dir); ++out_free: ++ e = copy_to_user(uarg, &args->mvdown, sizeof(args->mvdown)); ++ if (unlikely(e)) ++ err = -EFAULT; ++ au_kfree_rcu(args); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff -Naur null/fs/aufs/opts.c linux-5.15.36/fs/aufs/opts.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/opts.c 2022-05-10 16:51:39.875744219 +0300 +@@ -0,0 +1,1032 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * mount options/flags ++ */ ++ ++#include /* a distribution requires */ ++#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const char *au_parser_pattern(int val, match_table_t tbl) ++{ ++ struct match_token *p; ++ ++ p = tbl; ++ while (p->pattern) { ++ if (p->token == val) ++ return p->pattern; ++ p++; ++ } ++ BUG(); ++ return "??"; ++} ++ ++static const char *au_optstr(int *val, match_table_t tbl) ++{ ++ struct match_token *p; ++ int v; ++ ++ v = *val; ++ if (!v) ++ goto out; ++ p = tbl; ++ while (p->pattern) { ++ if (p->token ++ && (v & p->token) == p->token) { ++ *val &= ~p->token; ++ return p->pattern; ++ } ++ p++; ++ } ++ ++out: ++ return NULL; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t brperm = { ++ {AuBrPerm_RO, AUFS_BRPERM_RO}, ++ {AuBrPerm_RR, AUFS_BRPERM_RR}, ++ {AuBrPerm_RW, AUFS_BRPERM_RW}, ++ {0, NULL} ++}; ++ ++static match_table_t brattr = { ++ /* general */ ++ {AuBrAttr_COO_REG, AUFS_BRATTR_COO_REG}, ++ {AuBrAttr_COO_ALL, AUFS_BRATTR_COO_ALL}, ++ /* 'unpin' attrib is meaningless since linux-3.18-rc1 */ ++ {AuBrAttr_UNPIN, AUFS_BRATTR_UNPIN}, ++#ifdef CONFIG_AUFS_FHSM ++ {AuBrAttr_FHSM, AUFS_BRATTR_FHSM}, ++#endif ++#ifdef CONFIG_AUFS_XATTR ++ {AuBrAttr_ICEX, AUFS_BRATTR_ICEX}, ++ {AuBrAttr_ICEX_SEC, AUFS_BRATTR_ICEX_SEC}, ++ {AuBrAttr_ICEX_SYS, AUFS_BRATTR_ICEX_SYS}, ++ {AuBrAttr_ICEX_TR, AUFS_BRATTR_ICEX_TR}, ++ {AuBrAttr_ICEX_USR, AUFS_BRATTR_ICEX_USR}, ++ {AuBrAttr_ICEX_OTH, AUFS_BRATTR_ICEX_OTH}, ++#endif ++ ++ /* ro/rr branch */ ++ {AuBrRAttr_WH, AUFS_BRRATTR_WH}, ++ ++ /* rw branch */ ++ {AuBrWAttr_MOO, AUFS_BRWATTR_MOO}, ++ {AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH}, ++ ++ {0, NULL} ++}; ++ ++static int br_attr_val(char *str, match_table_t table, substring_t args[]) ++{ ++ int attr, v; ++ char *p; ++ ++ attr = 0; ++ do { ++ p = strchr(str, '+'); ++ if (p) ++ *p = 0; ++ v = match_token(str, table, args); ++ if (v) { ++ if (v & AuBrAttr_CMOO_Mask) ++ attr &= ~AuBrAttr_CMOO_Mask; ++ attr |= v; ++ } else { ++ if (p) ++ *p = '+'; ++ pr_warn("ignored branch attribute %s\n", str); ++ break; ++ } ++ if (p) ++ str = p + 1; ++ } while (p); ++ ++ return attr; ++} ++ ++static int au_do_optstr_br_attr(au_br_perm_str_t *str, int perm) ++{ ++ int sz; ++ const char *p; ++ char *q; ++ ++ q = str->a; ++ *q = 0; ++ p = au_optstr(&perm, brattr); ++ if (p) { ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ } else ++ goto out; ++ ++ do { ++ p = au_optstr(&perm, brattr); ++ if (p) { ++ *q++ = '+'; ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ } ++ } while (p); ++ ++out: ++ return q - str->a; ++} ++ ++int au_br_perm_val(char *perm) ++{ ++ int val, bad, sz; ++ char *p; ++ substring_t args[MAX_OPT_ARGS]; ++ au_br_perm_str_t attr; ++ ++ p = strchr(perm, '+'); ++ if (p) ++ *p = 0; ++ val = match_token(perm, brperm, args); ++ if (!val) { ++ if (p) ++ *p = '+'; ++ pr_warn("ignored branch permission %s\n", perm); ++ val = AuBrPerm_RO; ++ goto out; ++ } ++ if (!p) ++ goto out; ++ ++ val |= br_attr_val(p + 1, brattr, args); ++ ++ bad = 0; ++ switch (val & AuBrPerm_Mask) { ++ case AuBrPerm_RO: ++ case AuBrPerm_RR: ++ bad = val & AuBrWAttr_Mask; ++ val &= ~AuBrWAttr_Mask; ++ break; ++ case AuBrPerm_RW: ++ bad = val & AuBrRAttr_Mask; ++ val &= ~AuBrRAttr_Mask; ++ break; ++ } ++ ++ /* ++ * 'unpin' attrib becomes meaningless since linux-3.18-rc1, but aufs ++ * does not treat it as an error, just warning. ++ * this is a tiny guard for the user operation. ++ */ ++ if (val & AuBrAttr_UNPIN) { ++ bad |= AuBrAttr_UNPIN; ++ val &= ~AuBrAttr_UNPIN; ++ } ++ ++ if (unlikely(bad)) { ++ sz = au_do_optstr_br_attr(&attr, bad); ++ AuDebugOn(!sz); ++ pr_warn("ignored branch attribute %s\n", attr.a); ++ } ++ ++out: ++ return val; ++} ++ ++void au_optstr_br_perm(au_br_perm_str_t *str, int perm) ++{ ++ au_br_perm_str_t attr; ++ const char *p; ++ char *q; ++ int sz; ++ ++ q = str->a; ++ p = au_optstr(&perm, brperm); ++ AuDebugOn(!p || !*p); ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ ++ sz = au_do_optstr_br_attr(&attr, perm); ++ if (sz) { ++ *q++ = '+'; ++ memcpy(q, attr.a, sz + 1); ++ } ++ ++ AuDebugOn(strlen(str->a) >= sizeof(str->a)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t udbalevel = { ++ {AuOpt_UDBA_REVAL, "reval"}, ++ {AuOpt_UDBA_NONE, "none"}, ++#ifdef CONFIG_AUFS_HNOTIFY ++ {AuOpt_UDBA_HNOTIFY, "notify"}, /* abstraction */ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ {AuOpt_UDBA_HNOTIFY, "fsnotify"}, ++#endif ++#endif ++ {-1, NULL} ++}; ++ ++int au_udba_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ ++ return match_token(str, udbalevel, args); ++} ++ ++const char *au_optstr_udba(int udba) ++{ ++ return au_parser_pattern(udba, udbalevel); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t au_wbr_create_policy = { ++ {AuWbrCreate_TDP, "tdp"}, ++ {AuWbrCreate_TDP, "top-down-parent"}, ++ {AuWbrCreate_RR, "rr"}, ++ {AuWbrCreate_RR, "round-robin"}, ++ {AuWbrCreate_MFS, "mfs"}, ++ {AuWbrCreate_MFS, "most-free-space"}, ++ {AuWbrCreate_MFSV, "mfs:%d"}, ++ {AuWbrCreate_MFSV, "most-free-space:%d"}, ++ ++ /* top-down regardless the parent, and then mfs */ ++ {AuWbrCreate_TDMFS, "tdmfs:%d"}, ++ {AuWbrCreate_TDMFSV, "tdmfs:%d:%d"}, ++ ++ {AuWbrCreate_MFSRR, "mfsrr:%d"}, ++ {AuWbrCreate_MFSRRV, "mfsrr:%d:%d"}, ++ {AuWbrCreate_PMFS, "pmfs"}, ++ {AuWbrCreate_PMFSV, "pmfs:%d"}, ++ {AuWbrCreate_PMFSRR, "pmfsrr:%d"}, ++ {AuWbrCreate_PMFSRRV, "pmfsrr:%d:%d"}, ++ ++ {-1, NULL} ++}; ++ ++static int au_wbr_mfs_wmark(substring_t *arg, char *str, ++ struct au_opt_wbr_create *create) ++{ ++ int err; ++ unsigned long long ull; ++ ++ err = 0; ++ if (!match_u64(arg, &ull)) ++ create->mfsrr_watermark = ull; ++ else { ++ pr_err("bad integer in %s\n", str); ++ err = -EINVAL; ++ } ++ ++ return err; ++} ++ ++static int au_wbr_mfs_sec(substring_t *arg, char *str, ++ struct au_opt_wbr_create *create) ++{ ++ int n, err; ++ ++ err = 0; ++ if (!match_int(arg, &n) && 0 <= n && n <= AUFS_MFS_MAX_SEC) ++ create->mfs_second = n; ++ else { ++ pr_err("bad integer in %s\n", str); ++ err = -EINVAL; ++ } ++ ++ return err; ++} ++ ++int au_wbr_create_val(char *str, struct au_opt_wbr_create *create) ++{ ++ int err, e; ++ substring_t args[MAX_OPT_ARGS]; ++ ++ err = match_token(str, au_wbr_create_policy, args); ++ create->wbr_create = err; ++ switch (err) { ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRRV: ++ e = au_wbr_mfs_wmark(&args[0], str, create); ++ if (!e) ++ e = au_wbr_mfs_sec(&args[1], str, create); ++ if (unlikely(e)) ++ err = e; ++ break; ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_TDMFS: ++ case AuWbrCreate_PMFSRR: ++ e = au_wbr_mfs_wmark(&args[0], str, create); ++ if (unlikely(e)) { ++ err = e; ++ break; ++ } ++ fallthrough; ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_PMFS: ++ create->mfs_second = AUFS_MFS_DEF_SEC; ++ break; ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFSV: ++ e = au_wbr_mfs_sec(&args[0], str, create); ++ if (unlikely(e)) ++ err = e; ++ break; ++ } ++ ++ return err; ++} ++ ++const char *au_optstr_wbr_create(int wbr_create) ++{ ++ return au_parser_pattern(wbr_create, au_wbr_create_policy); ++} ++ ++static match_table_t au_wbr_copyup_policy = { ++ {AuWbrCopyup_TDP, "tdp"}, ++ {AuWbrCopyup_TDP, "top-down-parent"}, ++ {AuWbrCopyup_BUP, "bup"}, ++ {AuWbrCopyup_BUP, "bottom-up-parent"}, ++ {AuWbrCopyup_BU, "bu"}, ++ {AuWbrCopyup_BU, "bottom-up"}, ++ {-1, NULL} ++}; ++ ++int au_wbr_copyup_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ ++ return match_token(str, au_wbr_copyup_policy, args); ++} ++ ++const char *au_optstr_wbr_copyup(int wbr_copyup) ++{ ++ return au_parser_pattern(wbr_copyup, au_wbr_copyup_policy); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ struct au_opt_add *add = &opt->add; ++ char *p; ++ ++ add->bindex = bindex; ++ add->perm = AuBrPerm_RO; ++ add->pathname = opt_str; ++ p = strchr(opt_str, '='); ++ if (p) { ++ *p++ = 0; ++ if (*p) ++ add->perm = au_br_perm_val(p); ++ } ++ ++ err = vfsub_kern_path(add->pathname, AuOpt_LkupDirFlags, &add->path); ++ if (!err) { ++ if (!p) { ++ add->perm = AuBrPerm_RO; ++ if (au_test_fs_rr(add->path.dentry->d_sb)) ++ add->perm = AuBrPerm_RR; ++ else if (!bindex && !(sb_flags & SB_RDONLY)) ++ add->perm = AuBrPerm_RW; ++ } ++ opt->type = Opt_add; ++ goto out; ++ } ++ pr_err("lookup failed %s (%d)\n", add->pathname, err); ++ err = -EINVAL; ++ ++out: ++ return err; ++} ++ ++static int au_opt_wbr_create(struct super_block *sb, ++ struct au_opt_wbr_create *create) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 1; /* handled */ ++ sbinfo = au_sbi(sb); ++ if (sbinfo->si_wbr_create_ops->fin) { ++ err = sbinfo->si_wbr_create_ops->fin(sb); ++ if (!err) ++ err = 1; ++ } ++ ++ sbinfo->si_wbr_create = create->wbr_create; ++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + create->wbr_create; ++ switch (create->wbr_create) { ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_TDMFS: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRR: ++ case AuWbrCreate_PMFSRRV: ++ sbinfo->si_wbr_mfs.mfsrr_watermark = create->mfsrr_watermark; ++ fallthrough; ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFS: ++ case AuWbrCreate_PMFSV: ++ sbinfo->si_wbr_mfs.mfs_expire ++ = msecs_to_jiffies(create->mfs_second * MSEC_PER_SEC); ++ break; ++ } ++ ++ if (sbinfo->si_wbr_create_ops->init) ++ sbinfo->si_wbr_create_ops->init(sb); /* ignore */ ++ ++ return err; ++} ++ ++/* ++ * returns, ++ * plus: processed without an error ++ * zero: unprocessed ++ */ ++static int au_opt_simple(struct super_block *sb, struct au_opt *opt, ++ struct au_opts *opts) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 1; /* handled */ ++ sbinfo = au_sbi(sb); ++ switch (opt->type) { ++ case Opt_udba: ++ sbinfo->si_mntflags &= ~AuOptMask_UDBA; ++ sbinfo->si_mntflags |= opt->udba; ++ opts->given_udba |= opt->udba; ++ break; ++ ++ case Opt_plink: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, PLINK); ++ else { ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_put(sb, /*verbose*/1); ++ au_opt_clr(sbinfo->si_mntflags, PLINK); ++ } ++ break; ++ case Opt_list_plink: ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_list(sb); ++ break; ++ ++ case Opt_dio: ++ if (opt->tf) { ++ au_opt_set(sbinfo->si_mntflags, DIO); ++ au_fset_opts(opts->flags, REFRESH_DYAOP); ++ } else { ++ au_opt_clr(sbinfo->si_mntflags, DIO); ++ au_fset_opts(opts->flags, REFRESH_DYAOP); ++ } ++ break; ++ ++ case Opt_fhsm_sec: ++ au_fhsm_set(sbinfo, opt->fhsm_second); ++ break; ++ ++ case Opt_diropq_a: ++ au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ); ++ break; ++ case Opt_diropq_w: ++ au_opt_clr(sbinfo->si_mntflags, ALWAYS_DIROPQ); ++ break; ++ ++ case Opt_warn_perm: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, WARN_PERM); ++ else ++ au_opt_clr(sbinfo->si_mntflags, WARN_PERM); ++ break; ++ ++ case Opt_verbose: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, VERBOSE); ++ else ++ au_opt_clr(sbinfo->si_mntflags, VERBOSE); ++ break; ++ ++ case Opt_sum: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, SUM); ++ else { ++ au_opt_clr(sbinfo->si_mntflags, SUM); ++ au_opt_clr(sbinfo->si_mntflags, SUM_W); ++ } ++ break; ++ case Opt_wsum: ++ au_opt_clr(sbinfo->si_mntflags, SUM); ++ au_opt_set(sbinfo->si_mntflags, SUM_W); ++ break; ++ ++ case Opt_wbr_create: ++ err = au_opt_wbr_create(sb, &opt->wbr_create); ++ break; ++ case Opt_wbr_copyup: ++ sbinfo->si_wbr_copyup = opt->wbr_copyup; ++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup; ++ break; ++ ++ case Opt_dirwh: ++ sbinfo->si_dirwh = opt->dirwh; ++ break; ++ ++ case Opt_rdcache: ++ sbinfo->si_rdcache ++ = msecs_to_jiffies(opt->rdcache * MSEC_PER_SEC); ++ break; ++ case Opt_rdblk: ++ sbinfo->si_rdblk = opt->rdblk; ++ break; ++ case Opt_rdhash: ++ sbinfo->si_rdhash = opt->rdhash; ++ break; ++ ++ case Opt_shwh: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, SHWH); ++ else ++ au_opt_clr(sbinfo->si_mntflags, SHWH); ++ break; ++ ++ case Opt_dirperm1: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, DIRPERM1); ++ else ++ au_opt_clr(sbinfo->si_mntflags, DIRPERM1); ++ break; ++ ++ case Opt_trunc_xino: ++ if (opt->tf) ++ au_opt_set(sbinfo->si_mntflags, TRUNC_XINO); ++ else ++ au_opt_clr(sbinfo->si_mntflags, TRUNC_XINO); ++ break; ++ ++ case Opt_trunc_xino_path: ++ case Opt_itrunc_xino: ++ err = au_xino_trunc(sb, opt->xino_itrunc.bindex, ++ /*idx_begin*/0); ++ if (!err) ++ err = 1; ++ break; ++ ++ case Opt_trunc_xib: ++ if (opt->tf) ++ au_fset_opts(opts->flags, TRUNC_XIB); ++ else ++ au_fclr_opts(opts->flags, TRUNC_XIB); ++ break; ++ ++ case Opt_dirren: ++ err = 1; ++ if (opt->tf) { ++ if (!au_opt_test(sbinfo->si_mntflags, DIRREN)) { ++ err = au_dr_opt_set(sb); ++ if (!err) ++ err = 1; ++ } ++ if (err == 1) ++ au_opt_set(sbinfo->si_mntflags, DIRREN); ++ } else { ++ if (au_opt_test(sbinfo->si_mntflags, DIRREN)) { ++ err = au_dr_opt_clr(sb, au_ftest_opts(opts->flags, ++ DR_FLUSHED)); ++ if (!err) ++ err = 1; ++ } ++ if (err == 1) ++ au_opt_clr(sbinfo->si_mntflags, DIRREN); ++ } ++ break; ++ ++ case Opt_acl: ++ if (opt->tf) ++ sb->s_flags |= SB_POSIXACL; ++ else ++ sb->s_flags &= ~SB_POSIXACL; ++ break; ++ ++ default: ++ err = 0; ++ break; ++ } ++ ++ return err; ++} ++ ++/* ++ * returns tri-state. ++ * plus: processed without an error ++ * zero: unprocessed ++ * minus: error ++ */ ++static int au_opt_br(struct super_block *sb, struct au_opt *opt, ++ struct au_opts *opts) ++{ ++ int err, do_refresh; ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_append: ++ opt->add.bindex = au_sbbot(sb) + 1; ++ if (opt->add.bindex < 0) ++ opt->add.bindex = 0; ++ goto add; ++ /* Always goto add, not fallthrough */ ++ case Opt_prepend: ++ opt->add.bindex = 0; ++ fallthrough; ++ add: /* indented label */ ++ case Opt_add: ++ err = au_br_add(sb, &opt->add, ++ au_ftest_opts(opts->flags, REMOUNT)); ++ if (!err) { ++ err = 1; ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ ++ case Opt_del: ++ case Opt_idel: ++ err = au_br_del(sb, &opt->del, ++ au_ftest_opts(opts->flags, REMOUNT)); ++ if (!err) { ++ err = 1; ++ au_fset_opts(opts->flags, TRUNC_XIB); ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ ++ case Opt_mod: ++ case Opt_imod: ++ err = au_br_mod(sb, &opt->mod, ++ au_ftest_opts(opts->flags, REMOUNT), ++ &do_refresh); ++ if (!err) { ++ err = 1; ++ if (do_refresh) ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ } ++ return err; ++} ++ ++static int au_opt_xino(struct super_block *sb, struct au_opt *opt, ++ struct au_opt_xino **opt_xino, ++ struct au_opts *opts) ++{ ++ int err; ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_xino: ++ err = au_xino_set(sb, &opt->xino, ++ !!au_ftest_opts(opts->flags, REMOUNT)); ++ if (!err) ++ *opt_xino = &opt->xino; ++ break; ++ case Opt_noxino: ++ au_xino_clr(sb); ++ *opt_xino = (void *)-1; ++ break; ++ } ++ ++ return err; ++} ++ ++int au_opts_verify(struct super_block *sb, unsigned long sb_flags, ++ unsigned int pending) ++{ ++ int err, fhsm; ++ aufs_bindex_t bindex, bbot; ++ unsigned char do_plink, skip, do_free, can_no_dreval; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *root, *dentry; ++ struct inode *dir, *h_dir; ++ struct au_sbinfo *sbinfo; ++ struct au_hinode *hdir; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA)); ++ ++ if (!(sb_flags & SB_RDONLY)) { ++ if (unlikely(!au_br_writable(au_sbr_perm(sb, 0)))) ++ pr_warn("first branch should be rw\n"); ++ if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH))) ++ pr_warn_once("shwh should be used with ro\n"); ++ } ++ ++ if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HNOTIFY) ++ && !au_opt_test(sbinfo->si_mntflags, XINO)) ++ pr_warn_once("udba=*notify requires xino\n"); ++ ++ if (au_opt_test(sbinfo->si_mntflags, DIRPERM1)) ++ pr_warn_once("dirperm1 breaks the protection" ++ " by the permission bits on the lower branch\n"); ++ ++ err = 0; ++ fhsm = 0; ++ root = sb->s_root; ++ dir = d_inode(root); ++ do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK); ++ can_no_dreval = !!au_opt_test((sbinfo->si_mntflags | pending), ++ UDBA_NONE); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) { ++ skip = 0; ++ h_dir = au_h_iptr(dir, bindex); ++ br = au_sbr(sb, bindex); ++ ++ if ((br->br_perm & AuBrAttr_ICEX) ++ && !h_dir->i_op->listxattr) ++ br->br_perm &= ~AuBrAttr_ICEX; ++#if 0 /* untested */ ++ if ((br->br_perm & AuBrAttr_ICEX_SEC) ++ && (au_br_sb(br)->s_flags & SB_NOSEC)) ++ br->br_perm &= ~AuBrAttr_ICEX_SEC; ++#endif ++ ++ do_free = 0; ++ wbr = br->br_wbr; ++ if (wbr) ++ wbr_wh_read_lock(wbr); ++ ++ if (!au_br_writable(br->br_perm)) { ++ do_free = !!wbr; ++ skip = (!wbr ++ || (!wbr->wbr_whbase ++ && !wbr->wbr_plink ++ && !wbr->wbr_orph)); ++ } else if (!au_br_wh_linkable(br->br_perm)) { ++ /* skip = (!br->br_whbase && !br->br_orph); */ ++ skip = (!wbr || !wbr->wbr_whbase); ++ if (skip && wbr) { ++ if (do_plink) ++ skip = !!wbr->wbr_plink; ++ else ++ skip = !wbr->wbr_plink; ++ } ++ } else { ++ /* skip = (br->br_whbase && br->br_ohph); */ ++ skip = (wbr && wbr->wbr_whbase); ++ if (skip) { ++ if (do_plink) ++ skip = !!wbr->wbr_plink; ++ else ++ skip = !wbr->wbr_plink; ++ } ++ } ++ if (wbr) ++ wbr_wh_read_unlock(wbr); ++ ++ if (can_no_dreval) { ++ dentry = br->br_path.dentry; ++ spin_lock(&dentry->d_lock); ++ if (dentry->d_flags & ++ (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE)) ++ can_no_dreval = 0; ++ spin_unlock(&dentry->d_lock); ++ } ++ ++ if (au_br_fhsm(br->br_perm)) { ++ fhsm++; ++ AuDebugOn(!br->br_fhsm); ++ } ++ ++ if (skip) ++ continue; ++ ++ hdir = au_hi(dir, bindex); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ if (wbr) ++ wbr_wh_write_lock(wbr); ++ err = au_wh_init(br, sb); ++ if (wbr) ++ wbr_wh_write_unlock(wbr); ++ au_hn_inode_unlock(hdir); ++ ++ if (!err && do_free) { ++ au_kfree_rcu(wbr); ++ br->br_wbr = NULL; ++ } ++ } ++ ++ if (can_no_dreval) ++ au_fset_si(sbinfo, NO_DREVAL); ++ else ++ au_fclr_si(sbinfo, NO_DREVAL); ++ ++ if (fhsm >= 2) { ++ au_fset_si(sbinfo, FHSM); ++ for (bindex = bbot; bindex >= 0; bindex--) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) { ++ au_fhsm_set_bottom(sb, bindex); ++ break; ++ } ++ } ++ } else { ++ au_fclr_si(sbinfo, FHSM); ++ au_fhsm_set_bottom(sb, -1); ++ } ++ ++ return err; ++} ++ ++int au_opts_mount(struct super_block *sb, struct au_opts *opts) ++{ ++ int err; ++ unsigned int tmp; ++ aufs_bindex_t bindex, bbot; ++ struct au_opt *opt; ++ struct au_opt_xino *opt_xino, xino; ++ struct au_sbinfo *sbinfo; ++ struct au_branch *br; ++ struct inode *dir; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_opt_simple(sb, opt++, opts); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ /* disable xino and udba temporary */ ++ sbinfo = au_sbi(sb); ++ tmp = sbinfo->si_mntflags; ++ au_opt_clr(sbinfo->si_mntflags, XINO); ++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL); ++ ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_opt_br(sb, opt++, opts); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ bbot = au_sbbot(sb); ++ if (unlikely(bbot < 0)) { ++ err = -EINVAL; ++ pr_err("no branches\n"); ++ goto out; ++ } ++ ++ if (au_opt_test(tmp, XINO)) ++ au_opt_set(sbinfo->si_mntflags, XINO); ++ opt = opts->opt; ++ while (!err && opt->type != Opt_tail) ++ err = au_opt_xino(sb, opt++, &opt_xino, opts); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_opts_verify(sb, sb->s_flags, tmp); ++ if (unlikely(err)) ++ goto out; ++ ++ /* restore xino */ ++ if (au_opt_test(tmp, XINO) && !opt_xino) { ++ xino.file = au_xino_def(sb); ++ err = PTR_ERR(xino.file); ++ if (IS_ERR(xino.file)) ++ goto out; ++ ++ err = au_xino_set(sb, &xino, /*remount*/0); ++ fput(xino.file); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ /* restore udba */ ++ tmp &= AuOptMask_UDBA; ++ sbinfo->si_mntflags &= ~AuOptMask_UDBA; ++ sbinfo->si_mntflags |= tmp; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_hnotify_reset_br(tmp, br, br->br_perm); ++ if (unlikely(err)) ++ AuIOErr("hnotify failed on br %d, %d, ignored\n", ++ bindex, err); ++ /* go on even if err */ ++ } ++ if (au_opt_test(tmp, UDBA_HNOTIFY)) { ++ dir = d_inode(sb->s_root); ++ au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO); ++ } ++ ++out: ++ return err; ++} ++ ++int au_opts_remount(struct super_block *sb, struct au_opts *opts) ++{ ++ int err, rerr; ++ unsigned char no_dreval; ++ struct inode *dir; ++ struct au_opt_xino *opt_xino; ++ struct au_opt *opt; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = au_dr_opt_flush(sb); ++ if (unlikely(err)) ++ goto out; ++ au_fset_opts(opts->flags, DR_FLUSHED); ++ ++ dir = d_inode(sb->s_root); ++ sbinfo = au_sbi(sb); ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) { ++ err = au_opt_simple(sb, opt, opts); ++ if (!err) ++ err = au_opt_br(sb, opt, opts); ++ if (!err) ++ err = au_opt_xino(sb, opt, &opt_xino, opts); ++ opt++; ++ } ++ if (err > 0) ++ err = 0; ++ AuTraceErr(err); ++ /* go on even err */ ++ ++ no_dreval = !!au_ftest_si(sbinfo, NO_DREVAL); ++ rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0); ++ if (unlikely(rerr && !err)) ++ err = rerr; ++ ++ if (no_dreval != !!au_ftest_si(sbinfo, NO_DREVAL)) ++ au_fset_opts(opts->flags, REFRESH_IDOP); ++ ++ if (au_ftest_opts(opts->flags, TRUNC_XIB)) { ++ rerr = au_xib_trunc(sb); ++ if (unlikely(rerr && !err)) ++ err = rerr; ++ } ++ ++ /* will be handled by the caller */ ++ if (!au_ftest_opts(opts->flags, REFRESH) ++ && (opts->given_udba ++ || au_opt_test(sbinfo->si_mntflags, XINO) ++ || au_ftest_opts(opts->flags, REFRESH_IDOP) ++ )) ++ au_fset_opts(opts->flags, REFRESH); ++ ++ AuDbg("status 0x%x\n", opts->flags); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++unsigned int au_opt_udba(struct super_block *sb) ++{ ++ return au_mntflags(sb) & AuOptMask_UDBA; ++} +diff -Naur null/fs/aufs/opts.h linux-5.15.36/fs/aufs/opts.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/opts.h 2022-05-10 16:51:39.875744219 +0300 +@@ -0,0 +1,263 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * mount options/flags ++ */ ++ ++#ifndef __AUFS_OPTS_H__ ++#define __AUFS_OPTS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++ ++enum { ++ Opt_br, ++ Opt_add, Opt_del, Opt_mod, Opt_append, Opt_prepend, ++ Opt_idel, Opt_imod, ++ Opt_dirwh, Opt_rdcache, Opt_rdblk, Opt_rdhash, ++ Opt_xino, Opt_noxino, ++ Opt_trunc_xino, Opt_trunc_xino_v, ++ Opt_trunc_xino_path, Opt_itrunc_xino, ++ Opt_trunc_xib, ++ Opt_shwh, ++ Opt_plink, Opt_list_plink, ++ Opt_udba, ++ Opt_dio, ++ Opt_diropq, Opt_diropq_a, Opt_diropq_w, ++ Opt_warn_perm, ++ Opt_wbr_copyup, Opt_wbr_create, ++ Opt_fhsm_sec, ++ Opt_verbose, Opt_noverbose, ++ Opt_sum, Opt_wsum, ++ Opt_dirperm1, ++ Opt_dirren, ++ Opt_acl, ++ Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* mount flags */ ++#define AuOpt_XINO 1 /* external inode number bitmap ++ and translation table */ ++#define AuOpt_TRUNC_XINO (1 << 1) /* truncate xino files */ ++#define AuOpt_UDBA_NONE (1 << 2) /* users direct branch access */ ++#define AuOpt_UDBA_REVAL (1 << 3) ++#define AuOpt_UDBA_HNOTIFY (1 << 4) ++#define AuOpt_SHWH (1 << 5) /* show whiteout */ ++#define AuOpt_PLINK (1 << 6) /* pseudo-link */ ++#define AuOpt_DIRPERM1 (1 << 7) /* ignore the lower dir's perm ++ bits */ ++#define AuOpt_ALWAYS_DIROPQ (1 << 9) /* policy to creating diropq */ ++#define AuOpt_SUM (1 << 10) /* summation for statfs(2) */ ++#define AuOpt_SUM_W (1 << 11) /* unimplemented */ ++#define AuOpt_WARN_PERM (1 << 12) /* warn when add-branch */ ++#define AuOpt_VERBOSE (1 << 13) /* print the cause of error */ ++#define AuOpt_DIO (1 << 14) /* direct io */ ++#define AuOpt_DIRREN (1 << 15) /* directory rename */ ++ ++#ifndef CONFIG_AUFS_HNOTIFY ++#undef AuOpt_UDBA_HNOTIFY ++#define AuOpt_UDBA_HNOTIFY 0 ++#endif ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuOpt_DIRREN ++#define AuOpt_DIRREN 0 ++#endif ++#ifndef CONFIG_AUFS_SHWH ++#undef AuOpt_SHWH ++#define AuOpt_SHWH 0 ++#endif ++ ++#define AuOpt_Def (AuOpt_XINO \ ++ | AuOpt_UDBA_REVAL \ ++ | AuOpt_PLINK \ ++ /* | AuOpt_DIRPERM1 */ \ ++ | AuOpt_WARN_PERM) ++#define AuOptMask_UDBA (AuOpt_UDBA_NONE \ ++ | AuOpt_UDBA_REVAL \ ++ | AuOpt_UDBA_HNOTIFY) ++ ++#define AuOpt_LkupDirFlags (LOOKUP_FOLLOW | LOOKUP_DIRECTORY) ++ ++#define au_opt_test(flags, name) (flags & AuOpt_##name) ++#define au_opt_set(flags, name) do { \ ++ BUILD_BUG_ON(AuOpt_##name & AuOptMask_UDBA); \ ++ ((flags) |= AuOpt_##name); \ ++} while (0) ++#define au_opt_set_udba(flags, name) do { \ ++ (flags) &= ~AuOptMask_UDBA; \ ++ ((flags) |= AuOpt_##name); \ ++} while (0) ++#define au_opt_clr(flags, name) do { \ ++ ((flags) &= ~AuOpt_##name); \ ++} while (0) ++ ++static inline unsigned int au_opts_plink(unsigned int mntflags) ++{ ++#ifdef CONFIG_PROC_FS ++ return mntflags; ++#else ++ return mntflags & ~AuOpt_PLINK; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies to select one among multiple writable branches */ ++enum { ++ AuWbrCreate_TDP, /* top down parent */ ++ AuWbrCreate_RR, /* round robin */ ++ AuWbrCreate_MFS, /* most free space */ ++ AuWbrCreate_MFSV, /* mfs with seconds */ ++ AuWbrCreate_MFSRR, /* mfs then rr */ ++ AuWbrCreate_MFSRRV, /* mfs then rr with seconds */ ++ AuWbrCreate_TDMFS, /* top down regardless parent and mfs */ ++ AuWbrCreate_TDMFSV, /* top down regardless parent and mfs */ ++ AuWbrCreate_PMFS, /* parent and mfs */ ++ AuWbrCreate_PMFSV, /* parent and mfs with seconds */ ++ AuWbrCreate_PMFSRR, /* parent, mfs and round-robin */ ++ AuWbrCreate_PMFSRRV, /* plus seconds */ ++ ++ AuWbrCreate_Def = AuWbrCreate_TDP ++}; ++ ++enum { ++ AuWbrCopyup_TDP, /* top down parent */ ++ AuWbrCopyup_BUP, /* bottom up parent */ ++ AuWbrCopyup_BU, /* bottom up */ ++ ++ AuWbrCopyup_Def = AuWbrCopyup_TDP ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct file; ++ ++struct au_opt_add { ++ aufs_bindex_t bindex; ++ char *pathname; ++ int perm; ++ struct path path; ++}; ++ ++struct au_opt_del { ++ char *pathname; ++ struct path h_path; ++}; ++ ++struct au_opt_mod { ++ char *path; ++ int perm; ++ struct dentry *h_root; ++}; ++ ++struct au_opt_xino { ++ char *path; ++ struct file *file; ++}; ++ ++struct au_opt_xino_itrunc { ++ aufs_bindex_t bindex; ++}; ++ ++struct au_opt_wbr_create { ++ int wbr_create; ++ int mfs_second; ++ unsigned long long mfsrr_watermark; ++}; ++ ++struct au_opt { ++ int type; ++ union { ++ struct au_opt_xino xino; ++ struct au_opt_xino_itrunc xino_itrunc; ++ struct au_opt_add add; ++ struct au_opt_del del; ++ struct au_opt_mod mod; ++ int dirwh; ++ int rdcache; ++ unsigned int rdblk; ++ unsigned int rdhash; ++ int udba; ++ struct au_opt_wbr_create wbr_create; ++ int wbr_copyup; ++ unsigned int fhsm_second; ++ bool tf; /* generic flag, true or false */ ++ }; ++}; ++ ++/* opts flags */ ++#define AuOpts_REMOUNT 1 ++#define AuOpts_REFRESH (1 << 1) ++#define AuOpts_TRUNC_XIB (1 << 2) ++#define AuOpts_REFRESH_DYAOP (1 << 3) ++#define AuOpts_REFRESH_IDOP (1 << 4) ++#define AuOpts_DR_FLUSHED (1 << 5) ++#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name) ++#define au_fset_opts(flags, name) \ ++ do { (flags) |= AuOpts_##name; } while (0) ++#define au_fclr_opts(flags, name) \ ++ do { (flags) &= ~AuOpts_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuOpts_DR_FLUSHED ++#define AuOpts_DR_FLUSHED 0 ++#endif ++ ++struct au_opts { ++ struct au_opt *opt; ++ int max_opt; ++ ++ unsigned int given_udba; ++ unsigned int flags; ++ unsigned long sb_flags; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* opts.c */ ++int au_br_perm_val(char *perm); ++void au_optstr_br_perm(au_br_perm_str_t *str, int perm); ++int au_udba_val(char *str); ++const char *au_optstr_udba(int udba); ++int au_wbr_create_val(char *str, struct au_opt_wbr_create *create); ++const char *au_optstr_wbr_create(int wbr_create); ++int au_wbr_copyup_val(char *str); ++const char *au_optstr_wbr_copyup(int wbr_copyup); ++ ++int au_opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags, ++ aufs_bindex_t bindex); ++struct super_block; ++int au_opts_verify(struct super_block *sb, unsigned long sb_flags, ++ unsigned int pending); ++int au_opts_mount(struct super_block *sb, struct au_opts *opts); ++int au_opts_remount(struct super_block *sb, struct au_opts *opts); ++ ++unsigned int au_opt_udba(struct super_block *sb); ++ ++/* fsctx.c */ ++int aufs_fsctx_init(struct fs_context *fc); ++extern const struct fs_parameter_spec aufs_fsctx_paramspec[]; ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_OPTS_H__ */ +diff -Naur null/fs/aufs/plink.c linux-5.15.36/fs/aufs/plink.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/plink.c 2022-05-10 16:51:39.875744219 +0300 +@@ -0,0 +1,516 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * pseudo-link ++ */ ++ ++#include "aufs.h" ++ ++/* ++ * the pseudo-link maintenance mode. ++ * during a user process maintains the pseudo-links, ++ * prohibit adding a new plink and branch manipulation. ++ * ++ * Flags ++ * NOPLM: ++ * For entry functions which will handle plink, and i_mutex is already held ++ * in VFS. ++ * They cannot wait and should return an error at once. ++ * Callers has to check the error. ++ * NOPLMW: ++ * For entry functions which will handle plink, but i_mutex is not held ++ * in VFS. ++ * They can wait the plink maintenance mode to finish. ++ * ++ * They behave like F_SETLK and F_SETLKW. ++ * If the caller never handle plink, then both flags are unnecessary. ++ */ ++ ++int au_plink_maint(struct super_block *sb, int flags) ++{ ++ int err; ++ pid_t pid, ppid; ++ struct task_struct *parent, *prev; ++ struct au_sbinfo *sbi; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (!au_opt_test(au_mntflags(sb), PLINK)) ++ goto out; ++ ++ sbi = au_sbi(sb); ++ pid = sbi->si_plink_maint_pid; ++ if (!pid || pid == current->pid) ++ goto out; ++ ++ /* todo: it highly depends upon /sbin/mount.aufs */ ++ prev = NULL; ++ parent = current; ++ ppid = 0; ++ rcu_read_lock(); ++ while (1) { ++ parent = rcu_dereference(parent->real_parent); ++ if (parent == prev) ++ break; ++ ppid = task_pid_vnr(parent); ++ if (pid == ppid) { ++ rcu_read_unlock(); ++ goto out; ++ } ++ prev = parent; ++ } ++ rcu_read_unlock(); ++ ++ if (au_ftest_lock(flags, NOPLMW)) { ++ /* if there is no i_mutex lock in VFS, we don't need to wait */ ++ /* AuDebugOn(!lockdep_depth(current)); */ ++ while (sbi->si_plink_maint_pid) { ++ si_read_unlock(sb); ++ /* gave up wake_up_bit() */ ++ wait_event(sbi->si_plink_wq, !sbi->si_plink_maint_pid); ++ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&sbi->si_nowait); ++ si_noflush_read_lock(sb); ++ } ++ } else if (au_ftest_lock(flags, NOPLM)) { ++ AuDbg("ppid %d, pid %d\n", ppid, pid); ++ err = -EAGAIN; ++ } ++ ++out: ++ return err; ++} ++ ++void au_plink_maint_leave(struct au_sbinfo *sbinfo) ++{ ++ spin_lock(&sbinfo->si_plink_maint_lock); ++ sbinfo->si_plink_maint_pid = 0; ++ spin_unlock(&sbinfo->si_plink_maint_lock); ++ wake_up_all(&sbinfo->si_plink_wq); ++} ++ ++int au_plink_maint_enter(struct super_block *sb) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ /* make sure i am the only one in this fs */ ++ si_write_lock(sb, AuLock_FLUSH); ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ spin_lock(&sbinfo->si_plink_maint_lock); ++ if (!sbinfo->si_plink_maint_pid) ++ sbinfo->si_plink_maint_pid = current->pid; ++ else ++ err = -EBUSY; ++ spin_unlock(&sbinfo->si_plink_maint_lock); ++ } ++ si_write_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DEBUG ++void au_plink_list(struct super_block *sb) ++{ ++ int i; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_icntnr *icntnr; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ hbl = sbinfo->si_plink + i; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(icntnr, pos, hbl, plink) ++ AuDbg("%lu\n", icntnr->vfs_inode.i_ino); ++ hlist_bl_unlock(hbl); ++ } ++} ++#endif ++ ++/* is the inode pseudo-linked? */ ++int au_plink_test(struct inode *inode) ++{ ++ int found, i; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_icntnr *icntnr; ++ ++ sbinfo = au_sbi(inode->i_sb); ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ AuDebugOn(!au_opt_test(au_mntflags(inode->i_sb), PLINK)); ++ AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM)); ++ ++ found = 0; ++ i = au_plink_hash(inode->i_ino); ++ hbl = sbinfo->si_plink + i; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(icntnr, pos, hbl, plink) ++ if (&icntnr->vfs_inode == inode) { ++ found = 1; ++ break; ++ } ++ hlist_bl_unlock(hbl); ++ return found; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * generate a name for plink. ++ * the file will be stored under AUFS_WH_PLINKDIR. ++ */ ++/* 20 is max digits length of ulong 64 */ ++#define PLINK_NAME_LEN ((20 + 1) * 2) ++ ++static int plink_name(char *name, int len, struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ int rlen; ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, bindex); ++ rlen = snprintf(name, len, "%lu.%lu", inode->i_ino, h_inode->i_ino); ++ return rlen; ++} ++ ++struct au_do_plink_lkup_args { ++ struct dentry **errp; ++ struct qstr *tgtname; ++ struct path *h_ppath; ++}; ++ ++static struct dentry *au_do_plink_lkup(struct qstr *tgtname, ++ struct path *h_ppath) ++{ ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ h_inode = d_inode(h_ppath->dentry); ++ inode_lock_shared_nested(h_inode, AuLsc_I_CHILD2); ++ h_dentry = vfsub_lkup_one(tgtname, h_ppath); ++ inode_unlock_shared(h_inode); ++ ++ return h_dentry; ++} ++ ++static void au_call_do_plink_lkup(void *args) ++{ ++ struct au_do_plink_lkup_args *a = args; ++ *a->errp = au_do_plink_lkup(a->tgtname, a->h_ppath); ++} ++ ++/* lookup the plink-ed @inode under the branch at @bindex */ ++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct dentry *h_dentry; ++ struct au_branch *br; ++ struct path h_ppath; ++ int wkq_err; ++ char a[PLINK_NAME_LEN]; ++ struct qstr tgtname = QSTR_INIT(a, 0); ++ ++ AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM)); ++ ++ br = au_sbr(inode->i_sb, bindex); ++ h_ppath.dentry = br->br_wbr->wbr_plink; ++ h_ppath.mnt = au_br_mnt(br); ++ tgtname.len = plink_name(a, sizeof(a), inode, bindex); ++ ++ if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) { ++ struct au_do_plink_lkup_args args = { ++ .errp = &h_dentry, ++ .tgtname = &tgtname, ++ .h_ppath = &h_ppath ++ }; ++ ++ wkq_err = au_wkq_wait(au_call_do_plink_lkup, &args); ++ if (unlikely(wkq_err)) ++ h_dentry = ERR_PTR(wkq_err); ++ } else ++ h_dentry = au_do_plink_lkup(&tgtname, &h_ppath); ++ ++ return h_dentry; ++} ++ ++/* create a pseudo-link */ ++static int do_whplink(struct qstr *tgt, struct path *h_ppath, ++ struct dentry *h_dentry) ++{ ++ int err; ++ struct path h_path; ++ struct inode *h_dir, *delegated; ++ ++ h_dir = d_inode(h_ppath->dentry); ++ inode_lock_nested(h_dir, AuLsc_I_CHILD2); ++ h_path.mnt = h_ppath->mnt; ++again: ++ h_path.dentry = vfsub_lkup_one(tgt, h_ppath); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ err = 0; ++ /* wh.plink dir is not monitored */ ++ /* todo: is it really safe? */ ++ if (d_is_positive(h_path.dentry) ++ && d_inode(h_path.dentry) != d_inode(h_dentry)) { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ dput(h_path.dentry); ++ h_path.dentry = NULL; ++ if (!err) ++ goto again; ++ } ++ if (!err && d_is_negative(h_path.dentry)) { ++ delegated = NULL; ++ err = vfsub_link(h_dentry, h_dir, &h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ dput(h_path.dentry); ++ ++out: ++ inode_unlock(h_dir); ++ return err; ++} ++ ++struct do_whplink_args { ++ int *errp; ++ struct qstr *tgt; ++ struct path *h_ppath; ++ struct dentry *h_dentry; ++}; ++ ++static void call_do_whplink(void *args) ++{ ++ struct do_whplink_args *a = args; ++ *a->errp = do_whplink(a->tgt, a->h_ppath, a->h_dentry); ++} ++ ++static int whplink(struct dentry *h_dentry, struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ int err, wkq_err; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct path h_ppath; ++ char a[PLINK_NAME_LEN]; ++ struct qstr tgtname = QSTR_INIT(a, 0); ++ ++ br = au_sbr(inode->i_sb, bindex); ++ wbr = br->br_wbr; ++ h_ppath.dentry = wbr->wbr_plink; ++ h_ppath.mnt = au_br_mnt(br); ++ tgtname.len = plink_name(a, sizeof(a), inode, bindex); ++ ++ /* always superio. */ ++ if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) { ++ struct do_whplink_args args = { ++ .errp = &err, ++ .tgt = &tgtname, ++ .h_ppath = &h_ppath, ++ .h_dentry = h_dentry ++ }; ++ wkq_err = au_wkq_wait(call_do_whplink, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } else ++ err = do_whplink(&tgtname, &h_ppath, h_dentry); ++ ++ return err; ++} ++ ++/* ++ * create a new pseudo-link for @h_dentry on @bindex. ++ * the linked inode is held in aufs @inode. ++ */ ++void au_plink_append(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry) ++{ ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_icntnr *icntnr; ++ int found, err, cnt, i; ++ ++ sb = inode->i_sb; ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ found = au_plink_test(inode); ++ if (found) ++ return; ++ ++ i = au_plink_hash(inode->i_ino); ++ hbl = sbinfo->si_plink + i; ++ au_igrab(inode); ++ ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(icntnr, pos, hbl, plink) { ++ if (&icntnr->vfs_inode == inode) { ++ found = 1; ++ break; ++ } ++ } ++ if (!found) { ++ icntnr = container_of(inode, struct au_icntnr, vfs_inode); ++ hlist_bl_add_head(&icntnr->plink, hbl); ++ } ++ hlist_bl_unlock(hbl); ++ if (!found) { ++ cnt = au_hbl_count(hbl); ++#define msg "unexpectedly unbalanced or too many pseudo-links" ++ if (cnt > AUFS_PLINK_WARN) ++ AuWarn1(msg ", %d\n", cnt); ++#undef msg ++ err = whplink(h_dentry, inode, bindex); ++ if (unlikely(err)) { ++ pr_warn("err %d, damaged pseudo link.\n", err); ++ au_hbl_del(&icntnr->plink, hbl); ++ iput(&icntnr->vfs_inode); ++ } ++ } else ++ iput(&icntnr->vfs_inode); ++} ++ ++/* free all plinks */ ++void au_plink_put(struct super_block *sb, int verbose) ++{ ++ int i, warned; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *tmp; ++ struct au_icntnr *icntnr; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ /* no spin_lock since sbinfo is write-locked */ ++ warned = 0; ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ hbl = sbinfo->si_plink + i; ++ if (!warned && verbose && !hlist_bl_empty(hbl)) { ++ pr_warn("pseudo-link is not flushed"); ++ warned = 1; ++ } ++ hlist_bl_for_each_entry_safe(icntnr, pos, tmp, hbl, plink) ++ iput(&icntnr->vfs_inode); ++ INIT_HLIST_BL_HEAD(hbl); ++ } ++} ++ ++void au_plink_clean(struct super_block *sb, int verbose) ++{ ++ struct dentry *root; ++ ++ root = sb->s_root; ++ aufs_write_lock(root); ++ if (au_opt_test(au_mntflags(sb), PLINK)) ++ au_plink_put(sb, verbose); ++ aufs_write_unlock(root); ++} ++ ++static int au_plink_do_half_refresh(struct inode *inode, aufs_bindex_t br_id) ++{ ++ int do_put; ++ aufs_bindex_t btop, bbot, bindex; ++ ++ do_put = 0; ++ btop = au_ibtop(inode); ++ bbot = au_ibbot(inode); ++ if (btop >= 0) { ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ if (!au_h_iptr(inode, bindex) ++ || au_ii_br_id(inode, bindex) != br_id) ++ continue; ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ do_put = 1; ++ break; ++ } ++ if (do_put) ++ for (bindex = btop; bindex <= bbot; bindex++) ++ if (au_h_iptr(inode, bindex)) { ++ do_put = 0; ++ break; ++ } ++ } else ++ do_put = 1; ++ ++ return do_put; ++} ++ ++/* free the plinks on a branch specified by @br_id */ ++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id) ++{ ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *tmp; ++ struct au_icntnr *icntnr; ++ struct inode *inode; ++ int i, do_put; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ /* no bit_lock since sbinfo is write-locked */ ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ hbl = sbinfo->si_plink + i; ++ hlist_bl_for_each_entry_safe(icntnr, pos, tmp, hbl, plink) { ++ inode = au_igrab(&icntnr->vfs_inode); ++ ii_write_lock_child(inode); ++ do_put = au_plink_do_half_refresh(inode, br_id); ++ if (do_put) { ++ hlist_bl_del(&icntnr->plink); ++ iput(inode); ++ } ++ ii_write_unlock(inode); ++ iput(inode); ++ } ++ } ++} +diff -Naur null/fs/aufs/poll.c linux-5.15.36/fs/aufs/poll.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/poll.c 2022-05-10 16:51:39.875744219 +0300 +@@ -0,0 +1,51 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * poll operation ++ * There is only one filesystem which implements ->poll operation, currently. ++ */ ++ ++#include "aufs.h" ++ ++__poll_t aufs_poll(struct file *file, struct poll_table_struct *pt) ++{ ++ __poll_t mask; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ /* We should pretend an error happened. */ ++ mask = EPOLLERR /* | EPOLLIN | EPOLLOUT */; ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); ++ if (IS_ERR(h_file)) { ++ AuDbg("h_file %ld\n", PTR_ERR(h_file)); ++ goto out; ++ } ++ ++ mask = vfs_poll(h_file, pt); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ if (mask & EPOLLERR) ++ AuDbg("mask 0x%x\n", mask); ++ return mask; ++} +diff -Naur null/fs/aufs/posix_acl.c linux-5.15.36/fs/aufs/posix_acl.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/posix_acl.c 2022-05-10 16:51:39.875744219 +0300 +@@ -0,0 +1,111 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2014-2021 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 . ++ */ ++ ++/* ++ * posix acl operations ++ */ ++ ++#include ++#include "aufs.h" ++ ++struct posix_acl *aufs_get_acl(struct inode *inode, int type, bool rcu) ++{ ++ struct posix_acl *acl; ++ int err; ++ aufs_bindex_t bindex; ++ struct inode *h_inode; ++ struct super_block *sb; ++ ++ acl = ERR_PTR(-ECHILD); ++ if (rcu) ++ goto out; ++ ++ acl = NULL; ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_read_lock_child(inode); ++ if (!(sb->s_flags & SB_POSIXACL)) ++ goto unlock; ++ ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(!h_inode ++ || ((h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT)))) { ++ err = au_busy_or_stale(); ++ acl = ERR_PTR(err); ++ goto unlock; ++ } ++ ++ /* always topmost only */ ++ acl = get_acl(h_inode, type); ++ if (IS_ERR(acl)) ++ forget_cached_acl(inode, type); ++ else ++ set_cached_acl(inode, type, acl); ++ ++unlock: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++ ++out: ++ AuTraceErrPtr(acl); ++ return acl; ++} ++ ++int aufs_set_acl(struct user_namespace *userns, struct inode *inode, ++ struct posix_acl *acl, int type) ++{ ++ int err; ++ ssize_t ssz; ++ struct dentry *dentry; ++ struct au_sxattr arg = { ++ .type = AU_ACL_SET, ++ .u.acl_set = { ++ .acl = acl, ++ .type = type ++ }, ++ }; ++ ++ IMustLock(inode); ++ ++ if (inode->i_ino == AUFS_ROOT_INO) ++ dentry = dget(inode->i_sb->s_root); ++ else { ++ dentry = d_find_alias(inode); ++ if (!dentry) ++ dentry = d_find_any_alias(inode); ++ if (!dentry) { ++ pr_warn("cannot handle this inode, " ++ "please report to aufs-users ML\n"); ++ err = -ENOENT; ++ goto out; ++ } ++ } ++ ++ ssz = au_sxattr(dentry, inode, &arg); ++ /* forget even it if succeeds since the branch might set differently */ ++ forget_cached_acl(inode, type); ++ dput(dentry); ++ err = ssz; ++ if (ssz >= 0) ++ err = 0; ++ ++out: ++ return err; ++} +diff -Naur null/fs/aufs/procfs.c linux-5.15.36/fs/aufs/procfs.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/procfs.c 2022-05-10 16:51:39.875744219 +0300 +@@ -0,0 +1,170 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2021 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 . ++ */ ++ ++/* ++ * procfs interfaces ++ */ ++ ++#include ++#include "aufs.h" ++ ++static int au_procfs_plm_release(struct inode *inode, struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = file->private_data; ++ if (sbinfo) { ++ au_plink_maint_leave(sbinfo); ++ kobject_put(&sbinfo->si_kobj); ++ } ++ ++ return 0; ++} ++ ++static void au_procfs_plm_write_clean(struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = file->private_data; ++ if (sbinfo) ++ au_plink_clean(sbinfo->si_sb, /*verbose*/0); ++} ++ ++static int au_procfs_plm_write_si(struct file *file, unsigned long id) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_node *pos; ++ ++ err = -EBUSY; ++ if (unlikely(file->private_data)) ++ goto out; ++ ++ sb = NULL; ++ /* don't use au_sbilist_lock() here */ ++ hlist_bl_lock(&au_sbilist); ++ hlist_bl_for_each_entry(sbinfo, pos, &au_sbilist, si_list) ++ if (id == sysaufs_si_id(sbinfo)) { ++ if (kobject_get_unless_zero(&sbinfo->si_kobj)) ++ sb = sbinfo->si_sb; ++ break; ++ } ++ hlist_bl_unlock(&au_sbilist); ++ ++ err = -EINVAL; ++ if (unlikely(!sb)) ++ goto out; ++ ++ err = au_plink_maint_enter(sb); ++ if (!err) ++ /* keep kobject_get() */ ++ file->private_data = sbinfo; ++ else ++ kobject_put(&sbinfo->si_kobj); ++out: ++ return err; ++} ++ ++/* ++ * Accept a valid "si=xxxx" only. ++ * Once it is accepted successfully, accept "clean" too. ++ */ ++static ssize_t au_procfs_plm_write(struct file *file, const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ unsigned long id; ++ /* last newline is allowed */ ++ char buf[3 + sizeof(unsigned long) * 2 + 1]; ++ ++ err = -EACCES; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(count > sizeof(buf))) ++ goto out; ++ ++ err = copy_from_user(buf, ubuf, count); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ goto out; ++ } ++ buf[count] = 0; ++ ++ err = -EINVAL; ++ if (!strcmp("clean", buf)) { ++ au_procfs_plm_write_clean(file); ++ goto out_success; ++ } else if (unlikely(strncmp("si=", buf, 3))) ++ goto out; ++ ++ err = kstrtoul(buf + 3, 16, &id); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_procfs_plm_write_si(file, id); ++ if (unlikely(err)) ++ goto out; ++ ++out_success: ++ err = count; /* success */ ++out: ++ return err; ++} ++ ++static const struct proc_ops au_procfs_plm_op = { ++ .proc_write = au_procfs_plm_write, ++ .proc_release = au_procfs_plm_release ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct proc_dir_entry *au_procfs_dir; ++ ++void au_procfs_fin(void) ++{ ++ remove_proc_entry(AUFS_PLINK_MAINT_NAME, au_procfs_dir); ++ remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); ++} ++ ++int __init au_procfs_init(void) ++{ ++ int err; ++ struct proc_dir_entry *entry; ++ ++ err = -ENOMEM; ++ au_procfs_dir = proc_mkdir(AUFS_PLINK_MAINT_DIR, NULL); ++ if (unlikely(!au_procfs_dir)) ++ goto out; ++ ++ entry = proc_create(AUFS_PLINK_MAINT_NAME, S_IFREG | 0200, ++ au_procfs_dir, &au_procfs_plm_op); ++ if (unlikely(!entry)) ++ goto out_dir; ++ ++ err = 0; ++ goto out; /* success */ ++ ++ ++out_dir: ++ remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); ++out: ++ return err; ++} +diff -Naur null/fs/aufs/rdu.c linux-5.15.36/fs/aufs/rdu.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/rdu.c 2022-05-10 16:51:39.876744219 +0300 +@@ -0,0 +1,384 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * readdir in userspace. ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* bits for struct aufs_rdu.flags */ ++#define AuRdu_CALLED 1 ++#define AuRdu_CONT (1 << 1) ++#define AuRdu_FULL (1 << 2) ++#define au_ftest_rdu(flags, name) ((flags) & AuRdu_##name) ++#define au_fset_rdu(flags, name) \ ++ do { (flags) |= AuRdu_##name; } while (0) ++#define au_fclr_rdu(flags, name) \ ++ do { (flags) &= ~AuRdu_##name; } while (0) ++ ++struct au_rdu_arg { ++ struct dir_context ctx; ++ struct aufs_rdu *rdu; ++ union au_rdu_ent_ul ent; ++ unsigned long end; ++ ++ struct super_block *sb; ++ int err; ++}; ++ ++static int au_rdu_fill(struct dir_context *ctx, const char *name, int nlen, ++ loff_t offset, u64 h_ino, unsigned int d_type) ++{ ++ int err, len; ++ struct au_rdu_arg *arg = container_of(ctx, struct au_rdu_arg, ctx); ++ struct aufs_rdu *rdu = arg->rdu; ++ struct au_rdu_ent ent; ++ ++ err = 0; ++ arg->err = 0; ++ au_fset_rdu(rdu->cookie.flags, CALLED); ++ len = au_rdu_len(nlen); ++ if (arg->ent.ul + len < arg->end) { ++ ent.ino = h_ino; ++ ent.bindex = rdu->cookie.bindex; ++ ent.type = d_type; ++ ent.nlen = nlen; ++ if (unlikely(nlen > AUFS_MAX_NAMELEN)) ++ ent.type = DT_UNKNOWN; ++ ++ /* unnecessary to support mmap_sem since this is a dir */ ++ err = -EFAULT; ++ if (copy_to_user(arg->ent.e, &ent, sizeof(ent))) ++ goto out; ++ if (copy_to_user(arg->ent.e->name, name, nlen)) ++ goto out; ++ /* the terminating NULL */ ++ if (__put_user(0, arg->ent.e->name + nlen)) ++ goto out; ++ err = 0; ++ /* AuDbg("%p, %.*s\n", arg->ent.p, nlen, name); */ ++ arg->ent.ul += len; ++ rdu->rent++; ++ } else { ++ err = -EFAULT; ++ au_fset_rdu(rdu->cookie.flags, FULL); ++ rdu->full = 1; ++ rdu->tail = arg->ent; ++ } ++ ++out: ++ /* AuTraceErr(err); */ ++ return err; ++} ++ ++static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg) ++{ ++ int err; ++ loff_t offset; ++ struct au_rdu_cookie *cookie = &arg->rdu->cookie; ++ ++ /* we don't have to care (FMODE_32BITHASH | FMODE_64BITHASH) for ext4 */ ++ offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET); ++ err = offset; ++ if (unlikely(offset != cookie->h_pos)) ++ goto out; ++ ++ err = 0; ++ do { ++ arg->err = 0; ++ au_fclr_rdu(cookie->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(h_file, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err ++ && au_ftest_rdu(cookie->flags, CALLED) ++ && !au_ftest_rdu(cookie->flags, FULL)); ++ cookie->h_pos = h_file->f_pos; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_rdu(struct file *file, struct aufs_rdu *rdu) ++{ ++ int err; ++ aufs_bindex_t bbot; ++ struct au_rdu_arg arg = { ++ .ctx = { ++ .actor = au_rdu_fill ++ } ++ }; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct file *h_file; ++ struct au_rdu_cookie *cookie = &rdu->cookie; ++ ++ /* VERIFY_WRITE */ ++ err = !access_ok(rdu->ent.e, rdu->sz); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ rdu->rent = 0; ++ rdu->tail = rdu->ent; ++ rdu->full = 0; ++ arg.rdu = rdu; ++ arg.ent = rdu->ent; ++ arg.end = arg.ent.ul; ++ arg.end += rdu->sz; ++ ++ err = -ENOTDIR; ++ if (unlikely(!file->f_op->iterate && !file->f_op->iterate_shared)) ++ goto out; ++ ++ err = security_file_permission(file, MAY_READ); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ inode_lock_shared(inode); ++ ++ arg.sb = inode->i_sb; ++ err = si_read_lock(arg.sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_mtx; ++ err = au_alive_dir(dentry); ++ if (unlikely(err)) ++ goto out_si; ++ /* todo: reval? */ ++ fi_read_lock(file); ++ ++ err = -EAGAIN; ++ if (unlikely(au_ftest_rdu(cookie->flags, CONT) ++ && cookie->generation != au_figen(file))) ++ goto out_unlock; ++ ++ err = 0; ++ if (!rdu->blk) { ++ rdu->blk = au_sbi(arg.sb)->si_rdblk; ++ if (!rdu->blk) ++ rdu->blk = au_dir_size(file, /*dentry*/NULL); ++ } ++ bbot = au_fbtop(file); ++ if (cookie->bindex < bbot) ++ cookie->bindex = bbot; ++ bbot = au_fbbot_dir(file); ++ /* AuDbg("b%d, b%d\n", cookie->bindex, bbot); */ ++ for (; !err && cookie->bindex <= bbot; ++ cookie->bindex++, cookie->h_pos = 0) { ++ h_file = au_hf_dir(file, cookie->bindex); ++ if (!h_file) ++ continue; ++ ++ au_fclr_rdu(cookie->flags, FULL); ++ err = au_rdu_do(h_file, &arg); ++ AuTraceErr(err); ++ if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err)) ++ break; ++ } ++ AuDbg("rent %llu\n", rdu->rent); ++ ++ if (!err && !au_ftest_rdu(cookie->flags, CONT)) { ++ rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH); ++ au_fset_rdu(cookie->flags, CONT); ++ cookie->generation = au_figen(file); ++ } ++ ++ ii_read_lock_child(inode); ++ fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibtop(inode))); ++ ii_read_unlock(inode); ++ ++out_unlock: ++ fi_read_unlock(file); ++out_si: ++ si_read_unlock(arg.sb); ++out_mtx: ++ inode_unlock_shared(inode); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu) ++{ ++ int err; ++ ino_t ino; ++ unsigned long long nent; ++ union au_rdu_ent_ul *u; ++ struct au_rdu_ent ent; ++ struct super_block *sb; ++ ++ err = 0; ++ nent = rdu->nent; ++ u = &rdu->ent; ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ while (nent-- > 0) { ++ /* unnecessary to support mmap_sem since this is a dir */ ++ err = copy_from_user(&ent, u->e, sizeof(ent)); ++ if (!err) ++ /* VERIFY_WRITE */ ++ err = !access_ok(&u->e->ino, sizeof(ino)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ break; ++ } ++ ++ /* AuDbg("b%d, i%llu\n", ent.bindex, ent.ino); */ ++ if (!ent.wh) ++ err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino); ++ else ++ err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type, ++ &ino); ++ if (unlikely(err)) { ++ AuTraceErr(err); ++ break; ++ } ++ ++ err = __put_user(ino, &u->e->ino); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ break; ++ } ++ u->ul += au_rdu_len(ent.nlen); ++ } ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_rdu_verify(struct aufs_rdu *rdu) ++{ ++ AuDbg("rdu{%llu, %p, %u | %u | %llu, %u, %u | " ++ "%llu, b%d, 0x%x, g%u}\n", ++ rdu->sz, rdu->ent.e, rdu->verify[AufsCtlRduV_SZ], ++ rdu->blk, ++ rdu->rent, rdu->shwh, rdu->full, ++ rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags, ++ rdu->cookie.generation); ++ ++ if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu)) ++ return 0; ++ ++ AuDbg("%u:%u\n", ++ rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu)); ++ return -EINVAL; ++} ++ ++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err, e; ++ struct aufs_rdu rdu; ++ void __user *p = (void __user *)arg; ++ ++ err = copy_from_user(&rdu, p, sizeof(rdu)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ err = au_rdu_verify(&rdu); ++ if (unlikely(err)) ++ goto out; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ err = au_rdu(file, &rdu); ++ if (unlikely(err)) ++ break; ++ ++ e = copy_to_user(p, &rdu, sizeof(rdu)); ++ if (unlikely(e)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ break; ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ino(file, &rdu); ++ break; ++ ++ default: ++ /* err = -ENOTTY; */ ++ err = -EINVAL; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#ifdef CONFIG_COMPAT ++long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err, e; ++ struct aufs_rdu rdu; ++ void __user *p = compat_ptr(arg); ++ ++ /* todo: get_user()? */ ++ err = copy_from_user(&rdu, p, sizeof(rdu)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ rdu.ent.e = compat_ptr(rdu.ent.ul); ++ err = au_rdu_verify(&rdu); ++ if (unlikely(err)) ++ goto out; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ err = au_rdu(file, &rdu); ++ if (unlikely(err)) ++ break; ++ ++ rdu.ent.ul = ptr_to_compat(rdu.ent.e); ++ rdu.tail.ul = ptr_to_compat(rdu.tail.e); ++ e = copy_to_user(p, &rdu, sizeof(rdu)); ++ if (unlikely(e)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ break; ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ino(file, &rdu); ++ break; ++ ++ default: ++ /* err = -ENOTTY; */ ++ err = -EINVAL; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++#endif +diff -Naur null/fs/aufs/rwsem.h linux-5.15.36/fs/aufs/rwsem.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/rwsem.h 2022-05-10 16:51:39.876744219 +0300 +@@ -0,0 +1,85 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 read-write semaphore wrappers ++ */ ++ ++#ifndef __AUFS_RWSEM_H__ ++#define __AUFS_RWSEM_H__ ++ ++#ifdef __KERNEL__ ++ ++#include "debug.h" ++ ++/* 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 */ ++#define AuRwMustNoWaiters(rw) AuDebugOn(rwsem_is_contended(rw)) ++ ++#ifdef CONFIG_LOCKDEP ++/* rwsem_is_locked() is unusable */ ++#define AuRwMustReadLock(rw) AuDebugOn(IS_ENABLED(CONFIG_LOCKDEP) \ ++ && !lockdep_recursing(current) \ ++ && debug_locks \ ++ && !lockdep_is_held_type(rw, 1)) ++#define AuRwMustWriteLock(rw) AuDebugOn(IS_ENABLED(CONFIG_LOCKDEP) \ ++ && !lockdep_recursing(current) \ ++ && debug_locks \ ++ && !lockdep_is_held_type(rw, 0)) ++#define AuRwMustAnyLock(rw) AuDebugOn(IS_ENABLED(CONFIG_LOCKDEP) \ ++ && !lockdep_recursing(current) \ ++ && debug_locks \ ++ && !lockdep_is_held(rw)) ++#define AuRwDestroy(rw) AuDebugOn(IS_ENABLED(CONFIG_LOCKDEP) \ ++ && !lockdep_recursing(current) \ ++ && debug_locks \ ++ && lockdep_is_held(rw)) ++#else ++#define AuRwMustReadLock(rw) do {} while (0) ++#define AuRwMustWriteLock(rw) do {} while (0) ++#define AuRwMustAnyLock(rw) do {} while (0) ++#define AuRwDestroy(rw) do {} while (0) ++#endif ++ ++#define au_rw_init(rw) init_rwsem(rw) ++ ++#define au_rw_init_wlock(rw) do { \ ++ au_rw_init(rw); \ ++ down_write(rw); \ ++ } while (0) ++ ++#define au_rw_init_wlock_nested(rw, lsc) do { \ ++ au_rw_init(rw); \ ++ down_write_nested(rw, lsc); \ ++ } while (0) ++ ++#define au_rw_read_lock(rw) down_read(rw) ++#define au_rw_read_lock_nested(rw, lsc) down_read_nested(rw, lsc) ++#define au_rw_read_unlock(rw) up_read(rw) ++#define au_rw_dgrade_lock(rw) downgrade_write(rw) ++#define au_rw_write_lock(rw) down_write(rw) ++#define au_rw_write_lock_nested(rw, lsc) down_write_nested(rw, lsc) ++#define au_rw_write_unlock(rw) up_write(rw) ++/* why is not _nested version defined? */ ++#define au_rw_read_trylock(rw) down_read_trylock(rw) ++#define au_rw_write_trylock(rw) down_write_trylock(rw) ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_RWSEM_H__ */ +diff -Naur null/fs/aufs/sbinfo.c linux-5.15.36/fs/aufs/sbinfo.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/sbinfo.c 2022-05-10 16:51:39.876744219 +0300 +@@ -0,0 +1,316 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * superblock private data ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * they are necessary regardless sysfs is disabled. ++ */ ++void au_si_free(struct kobject *kobj) ++{ ++ int i; ++ struct au_sbinfo *sbinfo; ++ char *locked __maybe_unused; /* debug only */ ++ ++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); ++ for (i = 0; i < AuPlink_NHASH; i++) ++ AuDebugOn(!hlist_bl_empty(sbinfo->si_plink + i)); ++ AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len)); ++ ++ 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); ++ ++ au_kfree_try_rcu(sbinfo->si_branch); ++ mutex_destroy(&sbinfo->si_xib_mtx); ++ AuRwDestroy(&sbinfo->si_rwsem); ++ ++ au_lcnt_wait_for_fin(&sbinfo->si_ninodes); ++ /* si_nfiles is waited too */ ++ au_kfree_rcu(sbinfo); ++} ++ ++struct au_sbinfo *au_si_alloc(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ int err, i; ++ ++ err = -ENOMEM; ++ sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS); ++ if (unlikely(!sbinfo)) ++ goto out; ++ ++ /* will be reallocated separately */ ++ sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS); ++ if (unlikely(!sbinfo->si_branch)) ++ 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); ++ ++ 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; ++ ++ sbinfo->si_wbr_copyup = AuWbrCopyup_Def; ++ sbinfo->si_wbr_create = AuWbrCreate_Def; ++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup; ++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create; ++ ++ au_fhsm_init(sbinfo); ++ ++ sbinfo->si_mntflags = au_opts_plink(AuOpt_Def); ++ ++ sbinfo->si_xino_jiffy = jiffies; ++ sbinfo->si_xino_expire ++ = msecs_to_jiffies(AUFS_XINO_DEF_SEC * MSEC_PER_SEC); ++ mutex_init(&sbinfo->si_xib_mtx); ++ /* leave si_xib_last_pindex and si_xib_next_bit */ ++ ++ INIT_HLIST_BL_HEAD(&sbinfo->si_aopen); ++ ++ sbinfo->si_rdcache = msecs_to_jiffies(AUFS_RDCACHE_DEF * MSEC_PER_SEC); ++ sbinfo->si_rdblk = AUFS_RDBLK_DEF; ++ sbinfo->si_rdhash = AUFS_RDHASH_DEF; ++ sbinfo->si_dirwh = AUFS_DIRWH_DEF; ++ ++ for (i = 0; i < AuPlink_NHASH; i++) ++ INIT_HLIST_BL_HEAD(sbinfo->si_plink + i); ++ init_waitqueue_head(&sbinfo->si_plink_wq); ++ spin_lock_init(&sbinfo->si_plink_maint_lock); ++ ++ INIT_HLIST_BL_HEAD(&sbinfo->si_files); ++ ++ /* with getattr by default */ ++ sbinfo->si_iop_array = aufs_iop; ++ ++ /* leave other members for sysaufs and si_mnt. */ ++ sbinfo->si_sb = sb; ++ if (sb) { ++ sb->s_fs_info = sbinfo; ++ si_pid_set(sb); ++ } ++ return sbinfo; /* success */ ++ ++out_br: ++ au_kfree_try_rcu(sbinfo->si_branch); ++out_sbinfo: ++ au_kfree_rcu(sbinfo); ++out: ++ return ERR_PTR(err); ++} ++ ++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr, int may_shrink) ++{ ++ int err, sz; ++ struct au_branch **brp; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*brp) * (sbinfo->si_bbot + 1); ++ if (unlikely(!sz)) ++ sz = sizeof(*brp); ++ brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS, ++ may_shrink); ++ if (brp) { ++ sbinfo->si_branch = brp; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++unsigned int au_sigen_inc(struct super_block *sb) ++{ ++ unsigned int gen; ++ struct inode *inode; ++ ++ SiMustWriteLock(sb); ++ ++ gen = ++au_sbi(sb)->si_generation; ++ au_update_digen(sb->s_root); ++ inode = d_inode(sb->s_root); ++ au_update_iigen(inode, /*half*/0); ++ inode_inc_iversion(inode); ++ return gen; ++} ++ ++aufs_bindex_t au_new_br_id(struct super_block *sb) ++{ ++ aufs_bindex_t br_id; ++ int i; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ for (i = 0; i <= AUFS_BRANCH_MAX; i++) { ++ br_id = ++sbinfo->si_last_br_id; ++ AuDebugOn(br_id < 0); ++ if (br_id && au_br_index(sb, br_id) < 0) ++ return br_id; ++ } ++ ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* it is ok that new 'nwt' tasks are appended while we are sleeping */ ++int si_read_lock(struct super_block *sb, int flags) ++{ ++ int err; ++ ++ err = 0; ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ ++ si_noflush_read_lock(sb); ++ err = au_plink_maint(sb, flags); ++ if (unlikely(err)) ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++int si_write_lock(struct super_block *sb, int flags) ++{ ++ int err; ++ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ ++ si_noflush_write_lock(sb); ++ err = au_plink_maint(sb, flags); ++ if (unlikely(err)) ++ si_write_unlock(sb); ++ ++ return err; ++} ++ ++/* dentry and super_block lock. call at entry point */ ++int aufs_read_lock(struct dentry *dentry, int flags) ++{ ++ int err; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, flags); ++ if (unlikely(err)) ++ goto out; ++ ++ if (au_ftest_lock(flags, DW)) ++ di_write_lock_child(dentry); ++ else ++ di_read_lock_child(dentry, flags); ++ ++ if (au_ftest_lock(flags, GEN)) { ++ err = au_digen_test(dentry, au_sigen(sb)); ++ if (!au_opt_test(au_mntflags(sb), UDBA_NONE)) ++ AuDebugOn(!err && au_dbrange_test(dentry)); ++ else if (!err) ++ err = au_dbrange_test(dentry); ++ if (unlikely(err)) ++ aufs_read_unlock(dentry, flags); ++ } ++ ++out: ++ return err; ++} ++ ++void aufs_read_unlock(struct dentry *dentry, int flags) ++{ ++ if (au_ftest_lock(flags, DW)) ++ di_write_unlock(dentry); ++ else ++ di_read_unlock(dentry, flags); ++ si_read_unlock(dentry->d_sb); ++} ++ ++void aufs_write_lock(struct dentry *dentry) ++{ ++ si_write_lock(dentry->d_sb, AuLock_FLUSH | AuLock_NOPLMW); ++ di_write_lock_child(dentry); ++} ++ ++void aufs_write_unlock(struct dentry *dentry) ++{ ++ di_write_unlock(dentry); ++ si_write_unlock(dentry->d_sb); ++} ++ ++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags) ++{ ++ int err; ++ unsigned int sigen; ++ struct super_block *sb; ++ ++ sb = d1->d_sb; ++ err = si_read_lock(sb, flags); ++ if (unlikely(err)) ++ goto out; ++ ++ di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIRS)); ++ ++ if (au_ftest_lock(flags, GEN)) { ++ sigen = au_sigen(sb); ++ err = au_digen_test(d1, sigen); ++ AuDebugOn(!err && au_dbrange_test(d1)); ++ if (!err) { ++ err = au_digen_test(d2, sigen); ++ AuDebugOn(!err && au_dbrange_test(d2)); ++ } ++ if (unlikely(err)) ++ aufs_read_and_write_unlock2(d1, d2); ++ } ++ ++out: ++ return err; ++} ++ ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ di_write_unlock2(d1, d2); ++ si_read_unlock(d1->d_sb); ++} +diff -Naur null/fs/aufs/super.c linux-5.15.36/fs/aufs/super.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/super.c 2022-05-10 16:51:39.876744219 +0300 +@@ -0,0 +1,871 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * mount and super_block operations ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * super_operations ++ */ ++static struct inode *aufs_alloc_inode(struct super_block *sb __maybe_unused) ++{ ++ struct au_icntnr *c; ++ ++ c = au_cache_alloc_icntnr(); ++ if (c) { ++ au_icntnr_init(c); ++ inode_set_iversion(&c->vfs_inode, 1); /* sigen(sb); */ ++ c->iinfo.ii_hinode = NULL; ++ return &c->vfs_inode; ++ } ++ return NULL; ++} ++ ++static void aufs_destroy_inode(struct inode *inode) ++{ ++ if (!au_is_bad_inode(inode)) ++ au_iinfo_fin(inode); ++} ++ ++static void aufs_free_inode(struct inode *inode) ++{ ++ au_cache_free_icntnr(container_of(inode, struct au_icntnr, vfs_inode)); ++} ++ ++struct inode *au_iget_locked(struct super_block *sb, ino_t ino) ++{ ++ struct inode *inode; ++ int err; ++ ++ inode = iget_locked(sb, ino); ++ if (unlikely(!inode)) { ++ inode = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ if (!(inode->i_state & I_NEW)) ++ goto out; ++ ++ err = au_xigen_new(inode); ++ if (!err) ++ err = au_iinfo_init(inode); ++ if (!err) ++ inode_inc_iversion(inode); ++ else { ++ iget_failed(inode); ++ inode = ERR_PTR(err); ++ } ++ ++out: ++ /* never return NULL */ ++ AuDebugOn(!inode); ++ AuTraceErrPtr(inode); ++ return inode; ++} ++ ++/* lock free root dinfo */ ++static int au_show_brs(struct seq_file *seq, struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct path path; ++ struct au_hdentry *hdp; ++ struct au_branch *br; ++ au_br_perm_str_t perm; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ bindex = 0; ++ hdp = au_hdentry(au_di(sb->s_root), bindex); ++ for (; !err && bindex <= bbot; bindex++, hdp++) { ++ br = au_sbr(sb, bindex); ++ path.mnt = au_br_mnt(br); ++ path.dentry = hdp->hd_dentry; ++ err = au_seq_path(seq, &path); ++ if (!err) { ++ au_optstr_br_perm(&perm, br->br_perm); ++ seq_printf(seq, "=%s", perm.a); ++ if (bindex != bbot) ++ seq_putc(seq, ':'); ++ } ++ } ++ if (unlikely(err || seq_has_overflowed(seq))) ++ err = -E2BIG; ++ ++ return err; ++} ++ ++static void au_gen_fmt(char *fmt, int len __maybe_unused, const char *pat, ++ const char *append) ++{ ++ char *p; ++ ++ p = fmt; ++ while (*pat != ':') ++ *p++ = *pat++; ++ *p++ = *pat++; ++ strcpy(p, append); ++ AuDebugOn(strlen(fmt) >= len); ++} ++ ++static void au_show_wbr_create(struct seq_file *m, int v, ++ struct au_sbinfo *sbinfo) ++{ ++ const char *pat; ++ char fmt[32]; ++ struct au_wbr_mfs *mfs; ++ ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ ++ seq_puts(m, ",create="); ++ pat = au_optstr_wbr_create(v); ++ mfs = &sbinfo->si_wbr_mfs; ++ switch (v) { ++ case AuWbrCreate_TDP: ++ case AuWbrCreate_RR: ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_PMFS: ++ seq_puts(m, pat); ++ break; ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_TDMFS: ++ case AuWbrCreate_PMFSRR: ++ au_gen_fmt(fmt, sizeof(fmt), pat, "%llu"); ++ seq_printf(m, fmt, mfs->mfsrr_watermark); ++ break; ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFSV: ++ au_gen_fmt(fmt, sizeof(fmt), pat, "%lu"); ++ seq_printf(m, fmt, ++ jiffies_to_msecs(mfs->mfs_expire) ++ / MSEC_PER_SEC); ++ break; ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRRV: ++ au_gen_fmt(fmt, sizeof(fmt), pat, "%llu:%lu"); ++ seq_printf(m, fmt, mfs->mfsrr_watermark, ++ jiffies_to_msecs(mfs->mfs_expire) / MSEC_PER_SEC); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static int au_show_xino(struct seq_file *seq, struct super_block *sb) ++{ ++#ifdef CONFIG_SYSFS ++ return 0; ++#else ++ int err; ++ const int len = sizeof(AUFS_XINO_FNAME) - 1; ++ aufs_bindex_t bindex, brid; ++ struct qstr *name; ++ struct file *f; ++ struct dentry *d, *h_root; ++ struct au_branch *br; ++ ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ ++ err = 0; ++ f = au_sbi(sb)->si_xib; ++ if (!f) ++ goto out; ++ ++ /* stop printing the default xino path on the first writable branch */ ++ h_root = NULL; ++ 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 */ ++ if (d->d_parent == h_root ++ && name->len == len ++ && !memcmp(name->name, AUFS_XINO_FNAME, len)) ++ goto out; ++ ++ seq_puts(seq, ",xino="); ++ err = au_xino_path(seq, f); ++ ++out: ++ return err; ++#endif ++} ++ ++/* seq_file will re-call me in case of too long string */ ++static int aufs_show_options(struct seq_file *m, struct dentry *dentry) ++{ ++ int err; ++ unsigned int mnt_flags, v; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++#define AuBool(name, str) do { \ ++ v = au_opt_test(mnt_flags, name); \ ++ if (v != au_opt_test(AuOpt_Def, name)) \ ++ seq_printf(m, ",%s" #str, v ? "" : "no"); \ ++} while (0) ++ ++#define AuStr(name, str) do { \ ++ v = mnt_flags & AuOptMask_##name; \ ++ if (v != (AuOpt_Def & AuOptMask_##name)) \ ++ seq_printf(m, "," #str "=%s", au_optstr_##str(v)); \ ++} while (0) ++ ++#define AuUInt(name, str, val) do { \ ++ if (val != AUFS_##name##_DEF) \ ++ seq_printf(m, "," #str "=%u", val); \ ++} while (0) ++ ++ sb = dentry->d_sb; ++ if (sb->s_flags & SB_POSIXACL) ++ seq_puts(m, ",acl"); ++#if 0 /* reserved for future use */ ++ if (sb->s_flags & SB_I_VERSION) ++ seq_puts(m, ",i_version"); ++#endif ++ ++ /* lock free root dinfo */ ++ si_noflush_read_lock(sb); ++ sbinfo = au_sbi(sb); ++ seq_printf(m, ",si=%lx", sysaufs_si_id(sbinfo)); ++ ++ mnt_flags = au_mntflags(sb); ++ if (au_opt_test(mnt_flags, XINO)) { ++ err = au_show_xino(m, sb); ++ if (unlikely(err)) ++ goto out; ++ } else ++ seq_puts(m, ",noxino"); ++ ++ AuBool(TRUNC_XINO, trunc_xino); ++ AuStr(UDBA, udba); ++ AuBool(SHWH, shwh); ++ AuBool(PLINK, plink); ++ AuBool(DIO, dio); ++ AuBool(DIRPERM1, dirperm1); ++ ++ v = sbinfo->si_wbr_create; ++ if (v != AuWbrCreate_Def) ++ au_show_wbr_create(m, v, sbinfo); ++ ++ v = sbinfo->si_wbr_copyup; ++ if (v != AuWbrCopyup_Def) ++ seq_printf(m, ",cpup=%s", au_optstr_wbr_copyup(v)); ++ ++ v = au_opt_test(mnt_flags, ALWAYS_DIROPQ); ++ if (v != au_opt_test(AuOpt_Def, ALWAYS_DIROPQ)) ++ seq_printf(m, ",diropq=%c", v ? 'a' : 'w'); ++ ++ AuUInt(DIRWH, dirwh, sbinfo->si_dirwh); ++ ++ v = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC; ++ AuUInt(RDCACHE, rdcache, v); ++ ++ AuUInt(RDBLK, rdblk, sbinfo->si_rdblk); ++ AuUInt(RDHASH, rdhash, sbinfo->si_rdhash); ++ ++ au_fhsm_show(m, sbinfo); ++ ++ AuBool(DIRREN, dirren); ++ AuBool(SUM, sum); ++ /* AuBool(SUM_W, wsum); */ ++ AuBool(WARN_PERM, warn_perm); ++ AuBool(VERBOSE, verbose); ++ ++out: ++ /* be sure to print "br:" last */ ++ if (!sysaufs_brs) { ++ seq_puts(m, ",br:"); ++ au_show_brs(m, sb); ++ } ++ si_read_unlock(sb); ++ return 0; ++ ++#undef AuBool ++#undef AuStr ++#undef AuUInt ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* sum mode which returns the summation for statfs(2) */ ++ ++static u64 au_add_till_max(u64 a, u64 b) ++{ ++ u64 old; ++ ++ old = a; ++ a += b; ++ if (old <= a) ++ return a; ++ return ULLONG_MAX; ++} ++ ++static u64 au_mul_till_max(u64 a, long mul) ++{ ++ u64 old; ++ ++ old = a; ++ a *= mul; ++ if (old <= a) ++ return a; ++ return ULLONG_MAX; ++} ++ ++static int au_statfs_sum(struct super_block *sb, struct kstatfs *buf) ++{ ++ int err; ++ long bsize, factor; ++ u64 blocks, bfree, bavail, files, ffree; ++ aufs_bindex_t bbot, bindex, i; ++ unsigned char shared; ++ struct path h_path; ++ struct super_block *h_sb; ++ ++ err = 0; ++ bsize = LONG_MAX; ++ files = 0; ++ ffree = 0; ++ blocks = 0; ++ bfree = 0; ++ bavail = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ h_sb = h_path.mnt->mnt_sb; ++ shared = 0; ++ for (i = 0; !shared && i < bindex; i++) ++ shared = (au_sbr_sb(sb, i) == h_sb); ++ if (shared) ++ continue; ++ ++ /* sb->s_root for NFS is unreliable */ ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, buf); ++ if (unlikely(err)) ++ goto out; ++ ++ if (bsize > buf->f_bsize) { ++ /* ++ * we will reduce bsize, so we have to expand blocks ++ * etc. to match them again ++ */ ++ factor = (bsize / buf->f_bsize); ++ blocks = au_mul_till_max(blocks, factor); ++ bfree = au_mul_till_max(bfree, factor); ++ bavail = au_mul_till_max(bavail, factor); ++ bsize = buf->f_bsize; ++ } ++ ++ factor = (buf->f_bsize / bsize); ++ blocks = au_add_till_max(blocks, ++ au_mul_till_max(buf->f_blocks, factor)); ++ bfree = au_add_till_max(bfree, ++ au_mul_till_max(buf->f_bfree, factor)); ++ bavail = au_add_till_max(bavail, ++ au_mul_till_max(buf->f_bavail, factor)); ++ files = au_add_till_max(files, buf->f_files); ++ ffree = au_add_till_max(ffree, buf->f_ffree); ++ } ++ ++ buf->f_bsize = bsize; ++ buf->f_blocks = blocks; ++ buf->f_bfree = bfree; ++ buf->f_bavail = bavail; ++ buf->f_files = files; ++ buf->f_ffree = ffree; ++ buf->f_frsize = 0; ++ ++out: ++ return err; ++} ++ ++static int aufs_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ int err; ++ struct path h_path; ++ struct super_block *sb; ++ ++ /* lock free root dinfo */ ++ sb = dentry->d_sb; ++ si_noflush_read_lock(sb); ++ if (!au_opt_test(au_mntflags(sb), SUM)) { ++ /* sb->s_root for NFS is unreliable */ ++ h_path.mnt = au_sbr_mnt(sb, 0); ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, buf); ++ } else ++ err = au_statfs_sum(sb, buf); ++ si_read_unlock(sb); ++ ++ if (!err) { ++ buf->f_type = AUFS_SUPER_MAGIC; ++ buf->f_namelen = AUFS_MAX_NAMELEN; ++ memset(&buf->f_fsid, 0, sizeof(buf->f_fsid)); ++ } ++ /* buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; */ ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_sync_fs(struct super_block *sb, int wait) ++{ ++ int err, e; ++ aufs_bindex_t bbot, bindex; ++ struct au_branch *br; ++ struct super_block *h_sb; ++ ++ err = 0; ++ si_noflush_read_lock(sb); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_writable(br->br_perm)) ++ continue; ++ ++ h_sb = au_sbr_sb(sb, bindex); ++ e = vfsub_sync_filesystem(h_sb); ++ if (unlikely(e && !err)) ++ err = e; ++ /* go on even if an error happens */ ++ } ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* final actions when unmounting a file system */ ++static void aufs_put_super(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = au_sbi(sb); ++ if (sbinfo) ++ kobject_put(&sbinfo->si_kobj); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, ++ struct super_block *sb, void *arg) ++{ ++ void *array; ++ unsigned long long n, sz; ++ ++ array = NULL; ++ n = 0; ++ if (!*hint) ++ goto out; ++ ++ if (*hint > ULLONG_MAX / sizeof(array)) { ++ array = ERR_PTR(-EMFILE); ++ pr_err("hint %llu\n", *hint); ++ goto out; ++ } ++ ++ sz = sizeof(array) * *hint; ++ array = kzalloc(sz, GFP_NOFS); ++ if (unlikely(!array)) ++ array = vzalloc(sz); ++ if (unlikely(!array)) { ++ array = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ n = cb(sb, array, *hint, arg); ++ AuDebugOn(n > *hint); ++ ++out: ++ *hint = n; ++ return array; ++} ++ ++static unsigned long long au_iarray_cb(struct super_block *sb, void *a, ++ unsigned long long max __maybe_unused, ++ void *arg) ++{ ++ unsigned long long n; ++ struct inode **p, *inode; ++ struct list_head *head; ++ ++ n = 0; ++ p = a; ++ head = arg; ++ spin_lock(&sb->s_inode_list_lock); ++ list_for_each_entry(inode, head, i_sb_list) { ++ if (!au_is_bad_inode(inode) ++ && au_ii(inode)->ii_btop >= 0) { ++ spin_lock(&inode->i_lock); ++ if (atomic_read(&inode->i_count)) { ++ au_igrab(inode); ++ *p++ = inode; ++ n++; ++ AuDebugOn(n > max); ++ } ++ spin_unlock(&inode->i_lock); ++ } ++ } ++ spin_unlock(&sb->s_inode_list_lock); ++ ++ return n; ++} ++ ++struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max) ++{ ++ 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); ++} ++ ++void au_iarray_free(struct inode **a, unsigned long long max) ++{ ++ unsigned long long ull; ++ ++ for (ull = 0; ull < max; ull++) ++ iput(a[ull]); ++ kvfree(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * refresh dentry and inode at remount time. ++ */ ++/* todo: consolidate with simple_reval_dpath() and au_reval_for_attr() */ ++static int au_do_refresh(struct dentry *dentry, unsigned int dir_flags, ++ struct dentry *parent) ++{ ++ int err; ++ ++ di_write_lock_child(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(dentry, parent); ++ if (!err && dir_flags) ++ au_hn_reset(d_inode(dentry), dir_flags); ++ di_read_unlock(parent, AuLock_IR); ++ di_write_unlock(dentry); ++ ++ return err; ++} ++ ++static int au_do_refresh_d(struct dentry *dentry, unsigned int sigen, ++ struct au_sbinfo *sbinfo, ++ const unsigned int dir_flags, unsigned int do_idop) ++{ ++ int err; ++ struct dentry *parent; ++ ++ err = 0; ++ parent = dget_parent(dentry); ++ if (!au_digen_test(parent, sigen) && au_digen_test(dentry, sigen)) { ++ if (d_really_is_positive(dentry)) { ++ if (!d_is_dir(dentry)) ++ err = au_do_refresh(dentry, /*dir_flags*/0, ++ parent); ++ else { ++ err = au_do_refresh(dentry, dir_flags, parent); ++ if (unlikely(err)) ++ au_fset_si(sbinfo, FAILED_REFRESH_DIR); ++ } ++ } else ++ err = au_do_refresh(dentry, /*dir_flags*/0, parent); ++ AuDbgDentry(dentry); ++ } ++ dput(parent); ++ ++ if (!err) { ++ if (do_idop) ++ au_refresh_dop(dentry, /*force_reval*/0); ++ } else ++ au_refresh_dop(dentry, /*force_reval*/1); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_refresh_d(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, i, j, ndentry, e; ++ unsigned int sigen; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries, *d; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root = sb->s_root; ++ const unsigned int dir_flags = au_hi_flags(d_inode(root), /*isdir*/1); ++ ++ if (do_idop) ++ au_refresh_dop(root, /*force_reval*/0); ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, root, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ sigen = au_sigen(sb); ++ sbinfo = au_sbi(sb); ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ d = dentries[j]; ++ e = au_do_refresh_d(d, sigen, sbinfo, dir_flags, ++ do_idop); ++ if (unlikely(e && !err)) ++ err = e; ++ /* go on even err */ ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int au_refresh_i(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, e; ++ unsigned int sigen; ++ unsigned long long max, ull; ++ struct inode *inode, **array; ++ ++ array = au_iarray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ sigen = au_sigen(sb); ++ for (ull = 0; ull < max; ull++) { ++ inode = array[ull]; ++ if (unlikely(!inode)) ++ break; ++ ++ e = 0; ++ ii_write_lock_child(inode); ++ if (au_iigen(inode, NULL) != sigen) { ++ e = au_refresh_hinode_self(inode); ++ if (unlikely(e)) { ++ au_refresh_iop(inode, /*force_getattr*/1); ++ pr_err("error %d, i%lu\n", e, inode->i_ino); ++ if (!err) ++ err = e; ++ /* go on even if err */ ++ } ++ } ++ if (!e && do_idop) ++ au_refresh_iop(inode, /*force_getattr*/0); ++ ii_write_unlock(inode); ++ } ++ ++ au_iarray_free(array, max); ++ ++out: ++ return err; ++} ++ ++void au_remount_refresh(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, e; ++ unsigned int udba; ++ aufs_bindex_t bindex, bbot; ++ struct dentry *root; ++ struct inode *inode; ++ struct au_branch *br; ++ struct au_sbinfo *sbi; ++ ++ au_sigen_inc(sb); ++ sbi = au_sbi(sb); ++ au_fclr_si(sbi, FAILED_REFRESH_DIR); ++ ++ root = sb->s_root; ++ DiMustNoWaiters(root); ++ inode = d_inode(root); ++ IiMustNoWaiters(inode); ++ ++ udba = au_opt_udba(sb); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_hnotify_reset_br(udba, br, br->br_perm); ++ if (unlikely(err)) ++ AuIOErr("hnotify failed on br %d, %d, ignored\n", ++ bindex, err); ++ /* go on even if err */ ++ } ++ au_hn_reset(inode, au_hi_flags(inode, /*isdir*/1)); ++ ++ if (do_idop) { ++ if (au_ftest_si(sbi, NO_DREVAL)) { ++ AuDebugOn(sb->s_d_op == &aufs_dop_noreval); ++ sb->s_d_op = &aufs_dop_noreval; ++ AuDebugOn(sbi->si_iop_array == aufs_iop_nogetattr); ++ sbi->si_iop_array = aufs_iop_nogetattr; ++ } else { ++ AuDebugOn(sb->s_d_op == &aufs_dop); ++ sb->s_d_op = &aufs_dop; ++ AuDebugOn(sbi->si_iop_array == aufs_iop); ++ sbi->si_iop_array = aufs_iop; ++ } ++ pr_info("reset to %ps and %ps\n", ++ sb->s_d_op, sbi->si_iop_array); ++ } ++ ++ di_write_unlock(root); ++ err = au_refresh_d(sb, do_idop); ++ e = au_refresh_i(sb, do_idop); ++ if (unlikely(e && !err)) ++ err = e; ++ /* aufs_write_lock() calls ..._child() */ ++ di_write_lock_child(root); ++ ++ au_cpup_attr_all(inode, /*force*/1); ++ ++ if (unlikely(err)) ++ AuIOErr("refresh failed, ignored, %d\n", err); ++} ++ ++const struct super_operations aufs_sop = { ++ .alloc_inode = aufs_alloc_inode, ++ .destroy_inode = aufs_destroy_inode, ++ .free_inode = aufs_free_inode, ++ /* always deleting, no clearing */ ++ .drop_inode = generic_delete_inode, ++ .show_options = aufs_show_options, ++ .statfs = aufs_statfs, ++ .put_super = aufs_put_super, ++ .sync_fs = aufs_sync_fs ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_alloc_root(struct super_block *sb) ++{ ++ int err; ++ struct inode *inode; ++ struct dentry *root; ++ ++ err = -ENOMEM; ++ inode = au_iget_locked(sb, AUFS_ROOT_INO); ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out; ++ ++ inode->i_op = aufs_iop + AuIop_DIR; /* with getattr by default */ ++ inode->i_fop = &aufs_dir_fop; ++ inode->i_mode = S_IFDIR; ++ set_nlink(inode, 2); ++ unlock_new_inode(inode); ++ ++ root = d_make_root(inode); ++ if (unlikely(!root)) ++ goto out; ++ err = PTR_ERR(root); ++ if (IS_ERR(root)) ++ goto out; ++ ++ err = au_di_init(root); ++ if (!err) { ++ sb->s_root = root; ++ return 0; /* success */ ++ } ++ dput(root); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void aufs_kill_sb(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ struct dentry *root; ++ ++ sbinfo = au_sbi(sb); ++ if (!sbinfo) ++ goto out; ++ ++ au_sbilist_del(sb); ++ ++ root = sb->s_root; ++ if (root) ++ aufs_write_lock(root); ++ else ++ __si_write_lock(sb); ++ ++ au_fhsm_fin(sb); ++ if (sbinfo->si_wbr_create_ops->fin) ++ sbinfo->si_wbr_create_ops->fin(sb); ++ if (au_opt_test(sbinfo->si_mntflags, UDBA_HNOTIFY)) { ++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_NONE); ++ au_remount_refresh(sb, /*do_idop*/0); ++ } ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_put(sb, /*verbose*/1); ++ au_xino_clr(sb); ++ if (root) ++ au_dr_opt_flush(sb); ++ ++ if (root) ++ aufs_write_unlock(root); ++ else ++ __si_write_unlock(sb); ++ ++ sbinfo->si_sb = NULL; ++ au_nwt_flush(&sbinfo->si_nowait); ++ ++out: ++ kill_anon_super(sb); ++} ++ ++struct file_system_type aufs_fs_type = { ++ .name = AUFS_FSTYPE, ++ /* a race between rename and others */ ++ .fs_flags = FS_RENAME_DOES_D_MOVE ++ /* untested */ ++ /*| FS_ALLOW_IDMAP*/ ++ , ++ .init_fs_context = aufs_fsctx_init, ++ .parameters = aufs_fsctx_paramspec, ++ .kill_sb = aufs_kill_sb, ++ /* no need to __module_get() and module_put(). */ ++ .owner = THIS_MODULE, ++}; +diff -Naur null/fs/aufs/super.h linux-5.15.36/fs/aufs/super.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/super.h 2022-05-10 16:51:39.876744219 +0300 +@@ -0,0 +1,592 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * super_block operations ++ */ ++ ++#ifndef __AUFS_SUPER_H__ ++#define __AUFS_SUPER_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include "hbl.h" ++#include "lcnt.h" ++#include "rwsem.h" ++#include "wkq.h" ++ ++/* policies to select one among multiple writable branches */ ++struct au_wbr_copyup_operations { ++ int (*copyup)(struct dentry *dentry); ++}; ++ ++#define AuWbr_DIR 1 /* target is a dir */ ++#define AuWbr_PARENT (1 << 1) /* always require a parent */ ++ ++#define au_ftest_wbr(flags, name) ((flags) & AuWbr_##name) ++#define au_fset_wbr(flags, name) { (flags) |= AuWbr_##name; } ++#define au_fclr_wbr(flags, name) { (flags) &= ~AuWbr_##name; } ++ ++struct au_wbr_create_operations { ++ int (*create)(struct dentry *dentry, unsigned int flags); ++ int (*init)(struct super_block *sb); ++ int (*fin)(struct super_block *sb); ++}; ++ ++struct au_wbr_mfs { ++ struct mutex mfs_lock; /* protect this structure */ ++ unsigned long mfs_jiffy; ++ unsigned long mfs_expire; ++ aufs_bindex_t mfs_bindex; ++ ++ unsigned long long mfsrr_bytes; ++ unsigned long long mfsrr_watermark; ++}; ++ ++#define AuPlink_NHASH 100 ++static inline int au_plink_hash(ino_t ino) ++{ ++ return ino % AuPlink_NHASH; ++} ++ ++/* File-based Hierarchical Storage Management */ ++struct au_fhsm { ++#ifdef CONFIG_AUFS_FHSM ++ /* allow only one process who can receive the notification */ ++ spinlock_t fhsm_spin; ++ pid_t fhsm_pid; ++ wait_queue_head_t fhsm_wqh; ++ atomic_t fhsm_readable; ++ ++ /* these are protected by si_rwsem */ ++ unsigned long fhsm_expire; ++ aufs_bindex_t fhsm_bottom; ++#endif ++}; ++ ++struct au_branch; ++struct au_sbinfo { ++ /* nowait tasks in the system-wide workqueue */ ++ struct au_nowait_tasks si_nowait; ++ ++ /* ++ * tried sb->s_umount, but failed due to the dependency between i_mutex. ++ * rwsem for au_sbinfo is necessary. ++ */ ++ struct au_rwsem si_rwsem; ++ ++ /* ++ * dirty approach to protect sb->sb_inodes and ->s_files (gone) from ++ * remount. ++ */ ++ au_lcnt_t si_ninodes, si_nfiles; ++ ++ /* branch management */ ++ unsigned int si_generation; ++ ++ /* see AuSi_ flags */ ++ unsigned char au_si_status; ++ ++ aufs_bindex_t si_bbot; ++ ++ /* dirty trick to keep br_id plus */ ++ unsigned int si_last_br_id : ++ sizeof(aufs_bindex_t) * BITS_PER_BYTE - 1; ++ struct au_branch **si_branch; ++ ++ /* policy to select a writable branch */ ++ unsigned char si_wbr_copyup; ++ unsigned char si_wbr_create; ++ struct au_wbr_copyup_operations *si_wbr_copyup_ops; ++ struct au_wbr_create_operations *si_wbr_create_ops; ++ ++ /* round robin */ ++ atomic_t si_wbr_rr_next; ++ ++ /* most free space */ ++ struct au_wbr_mfs si_wbr_mfs; ++ ++ /* File-based Hierarchical Storage Management */ ++ struct au_fhsm si_fhsm; ++ ++ /* mount flags */ ++ /* include/asm-ia64/siginfo.h defines a macro named si_flags */ ++ unsigned int si_mntflags; ++ ++ /* external inode number (bitmap and translation table) */ ++ 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; ++ ++ unsigned long si_xino_jiffy; ++ unsigned long si_xino_expire; ++ /* reserved for future use */ ++ /* unsigned long long si_xib_limit; */ /* Max xib file size */ ++ ++#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 support atomic_open */ ++ struct hlist_bl_head si_aopen; ++ ++ /* vdir parameters */ ++ unsigned long si_rdcache; /* max cache time in jiffies */ ++ unsigned int si_rdblk; /* deblk size */ ++ unsigned int si_rdhash; /* hash size */ ++ ++ /* ++ * If the number of whiteouts are larger than si_dirwh, leave all of ++ * them after au_whtmp_ren to reduce the cost of rmdir(2). ++ * future fsck.aufs or kernel thread will remove them later. ++ * Otherwise, remove all whiteouts and the dir in rmdir(2). ++ */ ++ unsigned int si_dirwh; ++ ++ /* pseudo_link list */ ++ struct hlist_bl_head si_plink[AuPlink_NHASH]; ++ wait_queue_head_t si_plink_wq; ++ spinlock_t si_plink_maint_lock; ++ pid_t si_plink_maint_pid; ++ ++ /* file list */ ++ struct hlist_bl_head si_files; ++ ++ /* with/without getattr, brother of sb->s_d_op */ ++ const struct inode_operations *si_iop_array; ++ ++ /* ++ * sysfs and lifetime management. ++ * this is not a small structure and it may be a waste of memory in case ++ * of sysfs is disabled, particularly when many aufs-es are mounted. ++ * but using sysfs is majority. ++ */ ++ struct kobject si_kobj; ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *si_dbgaufs; ++ struct dentry *si_dbgaufs_plink; ++ struct dentry *si_dbgaufs_xib; ++#ifdef CONFIG_AUFS_EXPORT ++ struct dentry *si_dbgaufs_xigen; ++#endif ++#endif ++ ++#ifdef CONFIG_AUFS_SBILIST ++ struct hlist_bl_node si_list; ++#endif ++ ++ /* dirty, necessary for unmounting, sysfs and sysrq */ ++ struct super_block *si_sb; ++}; ++ ++/* sbinfo status flags */ ++/* ++ * 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 unnecessary ++ */ ++#define AuSi_FAILED_REFRESH_DIR 1 ++#define AuSi_FHSM (1 << 1) /* fhsm is active now */ ++#define AuSi_NO_DREVAL (1 << 2) /* disable all d_revalidate */ ++ ++#ifndef CONFIG_AUFS_FHSM ++#undef AuSi_FHSM ++#define AuSi_FHSM 0 ++#endif ++ ++static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi, ++ unsigned int flag) ++{ ++ AuRwMustAnyLock(&sbi->si_rwsem); ++ return sbi->au_si_status & flag; ++} ++#define au_ftest_si(sbinfo, name) au_do_ftest_si(sbinfo, AuSi_##name) ++#define au_fset_si(sbinfo, name) do { \ ++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ ++ (sbinfo)->au_si_status |= AuSi_##name; \ ++} while (0) ++#define au_fclr_si(sbinfo, name) do { \ ++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ ++ (sbinfo)->au_si_status &= ~AuSi_##name; \ ++} while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policy to select one among writable branches */ ++#define AuWbrCopyup(sbinfo, ...) \ ++ ((sbinfo)->si_wbr_copyup_ops->copyup(__VA_ARGS__)) ++#define AuWbrCreate(sbinfo, ...) \ ++ ((sbinfo)->si_wbr_create_ops->create(__VA_ARGS__)) ++ ++/* flags for si_read_lock()/aufs_read_lock()/di_read_lock() */ ++#define AuLock_DW 1 /* write-lock dentry */ ++#define AuLock_IR (1 << 1) /* read-lock inode */ ++#define AuLock_IW (1 << 2) /* write-lock inode */ ++#define AuLock_FLUSH (1 << 3) /* wait for 'nowait' tasks */ ++#define AuLock_DIRS (1 << 4) /* target is a pair of dirs */ ++ /* except RENAME_EXCHANGE */ ++#define AuLock_NOPLM (1 << 5) /* return err in plm mode */ ++#define AuLock_NOPLMW (1 << 6) /* wait for plm mode ends */ ++#define AuLock_GEN (1 << 7) /* test digen/iigen */ ++#define au_ftest_lock(flags, name) ((flags) & AuLock_##name) ++#define au_fset_lock(flags, name) \ ++ do { (flags) |= AuLock_##name; } while (0) ++#define au_fclr_lock(flags, name) \ ++ do { (flags) &= ~AuLock_##name; } while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* super.c */ ++struct inode *au_iget_locked(struct super_block *sb, ino_t ino); ++ ++typedef unsigned long long (*au_arraycb_t)(struct super_block *sb, void *array, ++ unsigned long long max, void *arg); ++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, ++ struct super_block *sb, void *arg); ++struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max); ++void au_iarray_free(struct inode **a, unsigned long long max); ++ ++void au_remount_refresh(struct super_block *sb, unsigned int do_idop); ++extern const struct super_operations aufs_sop; ++int au_alloc_root(struct super_block *sb); ++extern struct file_system_type aufs_fs_type; ++ ++/* sbinfo.c */ ++void au_si_free(struct kobject *kobj); ++struct au_sbinfo *au_si_alloc(struct super_block *sb); ++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr, int may_shrink); ++ ++unsigned int au_sigen_inc(struct super_block *sb); ++aufs_bindex_t au_new_br_id(struct super_block *sb); ++ ++int si_read_lock(struct super_block *sb, int flags); ++int si_write_lock(struct super_block *sb, int flags); ++int aufs_read_lock(struct dentry *dentry, int flags); ++void aufs_read_unlock(struct dentry *dentry, int flags); ++void aufs_write_lock(struct dentry *dentry); ++void aufs_write_unlock(struct dentry *dentry); ++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags); ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++/* wbr_policy.c */ ++extern struct au_wbr_copyup_operations au_wbr_copyup_ops[]; ++extern struct au_wbr_create_operations au_wbr_create_ops[]; ++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex); ++int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t btop); ++ ++/* mvdown.c */ ++int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *arg); ++ ++#ifdef CONFIG_AUFS_FHSM ++/* fhsm.c */ ++ ++static inline pid_t au_fhsm_pid(struct au_fhsm *fhsm) ++{ ++ pid_t pid; ++ ++ spin_lock(&fhsm->fhsm_spin); ++ pid = fhsm->fhsm_pid; ++ spin_unlock(&fhsm->fhsm_spin); ++ ++ return pid; ++} ++ ++void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force); ++void au_fhsm_wrote_all(struct super_block *sb, int force); ++int au_fhsm_fd(struct super_block *sb, int oflags); ++int au_fhsm_br_alloc(struct au_branch *br); ++void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex); ++void au_fhsm_fin(struct super_block *sb); ++void au_fhsm_init(struct au_sbinfo *sbinfo); ++void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec); ++void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo); ++#else ++AuStubVoid(au_fhsm_wrote, struct super_block *sb, aufs_bindex_t bindex, ++ int force) ++AuStubVoid(au_fhsm_wrote_all, struct super_block *sb, int force) ++AuStub(int, au_fhsm_fd, return -EOPNOTSUPP, struct super_block *sb, int oflags) ++AuStub(pid_t, au_fhsm_pid, return 0, struct au_fhsm *fhsm) ++AuStubInt0(au_fhsm_br_alloc, struct au_branch *br) ++AuStubVoid(au_fhsm_set_bottom, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(au_fhsm_fin, struct super_block *sb) ++AuStubVoid(au_fhsm_init, struct au_sbinfo *sbinfo) ++AuStubVoid(au_fhsm_set, struct au_sbinfo *sbinfo, unsigned int sec) ++AuStubVoid(au_fhsm_show, struct seq_file *seq, struct au_sbinfo *sbinfo) ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_sbinfo *au_sbi(struct super_block *sb) ++{ ++ return sb->s_fs_info; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++int au_test_nfsd(void); ++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 path *path); ++void au_xigen_clr(struct super_block *sb); ++ ++static inline int au_busy_or_stale(void) ++{ ++ if (!au_test_nfsd()) ++ return -EBUSY; ++ return -ESTALE; ++} ++#else ++AuStubInt0(au_test_nfsd, void) ++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 path *path) ++AuStubVoid(au_xigen_clr, struct super_block *sb) ++AuStub(int, au_busy_or_stale, return -EBUSY, void) ++#endif /* CONFIG_AUFS_EXPORT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_SBILIST ++/* module.c */ ++extern struct hlist_bl_head au_sbilist; ++ ++static inline void au_sbilist_init(void) ++{ ++ INIT_HLIST_BL_HEAD(&au_sbilist); ++} ++ ++static inline void au_sbilist_add(struct super_block *sb) ++{ ++ au_hbl_add(&au_sbi(sb)->si_list, &au_sbilist); ++} ++ ++static inline void au_sbilist_del(struct super_block *sb) ++{ ++ au_hbl_del(&au_sbi(sb)->si_list, &au_sbilist); ++} ++ ++#ifdef CONFIG_AUFS_MAGIC_SYSRQ ++static inline void au_sbilist_lock(void) ++{ ++ hlist_bl_lock(&au_sbilist); ++} ++ ++static inline void au_sbilist_unlock(void) ++{ ++ hlist_bl_unlock(&au_sbilist); ++} ++#define AuGFP_SBILIST GFP_ATOMIC ++#else ++AuStubVoid(au_sbilist_lock, void) ++AuStubVoid(au_sbilist_unlock, void) ++#define AuGFP_SBILIST GFP_NOFS ++#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ ++#else ++AuStubVoid(au_sbilist_init, void) ++AuStubVoid(au_sbilist_add, struct super_block *sb) ++AuStubVoid(au_sbilist_del, struct super_block *sb) ++AuStubVoid(au_sbilist_lock, void) ++AuStubVoid(au_sbilist_unlock, void) ++#define AuGFP_SBILIST GFP_NOFS ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void dbgaufs_si_null(struct au_sbinfo *sbinfo) ++{ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++#ifdef CONFIG_DEBUG_FS ++ sbinfo->si_dbgaufs = NULL; ++ sbinfo->si_dbgaufs_plink = NULL; ++ sbinfo->si_dbgaufs_xib = NULL; ++#ifdef CONFIG_AUFS_EXPORT ++ sbinfo->si_dbgaufs_xigen = NULL; ++#endif ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* current->atomic_flags */ ++/* this value should never corrupt the ones defined in linux/sched.h */ ++#define PFA_AUFS 0x10 ++ ++TASK_PFA_TEST(AUFS, test_aufs) /* task_test_aufs */ ++TASK_PFA_SET(AUFS, aufs) /* task_set_aufs */ ++TASK_PFA_CLEAR(AUFS, aufs) /* task_clear_aufs */ ++ ++static inline int si_pid_test(struct super_block *sb) ++{ ++ return !!task_test_aufs(current); ++} ++ ++static inline void si_pid_clr(struct super_block *sb) ++{ ++ AuDebugOn(!task_test_aufs(current)); ++ task_clear_aufs(current); ++} ++ ++static inline void si_pid_set(struct super_block *sb) ++{ ++ AuDebugOn(task_test_aufs(current)); ++ task_set_aufs(current); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock superblock. mainly for entry point functions */ ++#define __si_read_lock(sb) au_rw_read_lock(&au_sbi(sb)->si_rwsem) ++#define __si_write_lock(sb) au_rw_write_lock(&au_sbi(sb)->si_rwsem) ++#define __si_read_trylock(sb) au_rw_read_trylock(&au_sbi(sb)->si_rwsem) ++#define __si_write_trylock(sb) au_rw_write_trylock(&au_sbi(sb)->si_rwsem) ++/* ++#define __si_read_trylock_nested(sb) \ ++ au_rw_read_trylock_nested(&au_sbi(sb)->si_rwsem) ++#define __si_write_trylock_nested(sb) \ ++ au_rw_write_trylock_nested(&au_sbi(sb)->si_rwsem) ++*/ ++ ++#define __si_read_unlock(sb) au_rw_read_unlock(&au_sbi(sb)->si_rwsem) ++#define __si_write_unlock(sb) au_rw_write_unlock(&au_sbi(sb)->si_rwsem) ++#define __si_downgrade_lock(sb) au_rw_dgrade_lock(&au_sbi(sb)->si_rwsem) ++ ++#define SiMustNoWaiters(sb) AuRwMustNoWaiters(&au_sbi(sb)->si_rwsem) ++#define SiMustAnyLock(sb) AuRwMustAnyLock(&au_sbi(sb)->si_rwsem) ++#define SiMustWriteLock(sb) AuRwMustWriteLock(&au_sbi(sb)->si_rwsem) ++ ++static inline void si_noflush_read_lock(struct super_block *sb) ++{ ++ __si_read_lock(sb); ++ si_pid_set(sb); ++} ++ ++static inline int si_noflush_read_trylock(struct super_block *sb) ++{ ++ int locked; ++ ++ locked = __si_read_trylock(sb); ++ if (locked) ++ si_pid_set(sb); ++ return locked; ++} ++ ++static inline void si_noflush_write_lock(struct super_block *sb) ++{ ++ __si_write_lock(sb); ++ si_pid_set(sb); ++} ++ ++static inline int si_noflush_write_trylock(struct super_block *sb) ++{ ++ int locked; ++ ++ locked = __si_write_trylock(sb); ++ if (locked) ++ si_pid_set(sb); ++ return locked; ++} ++ ++#if 0 /* reserved */ ++static inline int si_read_trylock(struct super_block *sb, int flags) ++{ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ return si_noflush_read_trylock(sb); ++} ++#endif ++ ++static inline void si_read_unlock(struct super_block *sb) ++{ ++ si_pid_clr(sb); ++ __si_read_unlock(sb); ++} ++ ++#if 0 /* reserved */ ++static inline int si_write_trylock(struct super_block *sb, int flags) ++{ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ return si_noflush_write_trylock(sb); ++} ++#endif ++ ++static inline void si_write_unlock(struct super_block *sb) ++{ ++ si_pid_clr(sb); ++ __si_write_unlock(sb); ++} ++ ++#if 0 /* reserved */ ++static inline void si_downgrade_lock(struct super_block *sb) ++{ ++ __si_downgrade_lock(sb); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline aufs_bindex_t au_sbbot(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_bbot; ++} ++ ++static inline unsigned int au_mntflags(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_mntflags; ++} ++ ++static inline unsigned int au_sigen(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_generation; ++} ++ ++static inline struct au_branch *au_sbr(struct super_block *sb, ++ aufs_bindex_t bindex) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_branch[0 + bindex]; ++} ++ ++static inline loff_t au_xi_maxent(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_ximaxent; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_SUPER_H__ */ +diff -Naur null/fs/aufs/sysaufs.c linux-5.15.36/fs/aufs/sysaufs.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/sysaufs.c 2022-05-10 16:51:39.876744219 +0300 +@@ -0,0 +1,93 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * sysfs interface and lifetime management ++ * they are necessary regardless sysfs is disabled. ++ */ ++ ++#include ++#include "aufs.h" ++ ++unsigned long sysaufs_si_mask; ++struct kset *sysaufs_kset; ++ ++#define AuSiAttr(_name) { \ ++ .attr = { .name = __stringify(_name), .mode = 0444 }, \ ++ .show = sysaufs_si_##_name, \ ++} ++ ++static struct sysaufs_si_attr sysaufs_si_attr_xi_path = AuSiAttr(xi_path); ++struct attribute *sysaufs_si_attrs[] = { ++ &sysaufs_si_attr_xi_path.attr, ++ NULL, ++}; ++ ++static const struct sysfs_ops au_sbi_ops = { ++ .show = sysaufs_si_show ++}; ++ ++static struct kobj_type au_sbi_ktype = { ++ .release = au_si_free, ++ .sysfs_ops = &au_sbi_ops, ++ .default_attrs = sysaufs_si_attrs ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int sysaufs_si_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ ++ sbinfo->si_kobj.kset = sysaufs_kset; ++ /* cf. sysaufs_name() */ ++ err = kobject_init_and_add ++ (&sbinfo->si_kobj, &au_sbi_ktype, /*&sysaufs_kset->kobj*/NULL, ++ SysaufsSiNamePrefix "%lx", sysaufs_si_id(sbinfo)); ++ ++ return err; ++} ++ ++void sysaufs_fin(void) ++{ ++ sysfs_remove_group(&sysaufs_kset->kobj, sysaufs_attr_group); ++ kset_unregister(sysaufs_kset); ++} ++ ++int __init sysaufs_init(void) ++{ ++ int err; ++ ++ do { ++ get_random_bytes(&sysaufs_si_mask, sizeof(sysaufs_si_mask)); ++ } while (!sysaufs_si_mask); ++ ++ err = -EINVAL; ++ sysaufs_kset = kset_create_and_add(AUFS_NAME, NULL, fs_kobj); ++ if (unlikely(!sysaufs_kset)) ++ goto out; ++ err = PTR_ERR(sysaufs_kset); ++ if (IS_ERR(sysaufs_kset)) ++ goto out; ++ err = sysfs_create_group(&sysaufs_kset->kobj, sysaufs_attr_group); ++ if (unlikely(err)) ++ kset_unregister(sysaufs_kset); ++ ++out: ++ return err; ++} +diff -Naur null/fs/aufs/sysaufs.h linux-5.15.36/fs/aufs/sysaufs.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/sysaufs.h 2022-05-10 16:51:39.876744219 +0300 +@@ -0,0 +1,102 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * sysfs interface and mount lifetime management ++ */ ++ ++#ifndef __SYSAUFS_H__ ++#define __SYSAUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "module.h" ++ ++struct super_block; ++struct au_sbinfo; ++ ++struct sysaufs_si_attr { ++ struct attribute attr; ++ int (*show)(struct seq_file *seq, struct super_block *sb); ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* sysaufs.c */ ++extern unsigned long sysaufs_si_mask; ++extern struct kset *sysaufs_kset; ++extern struct attribute *sysaufs_si_attrs[]; ++int sysaufs_si_init(struct au_sbinfo *sbinfo); ++int __init sysaufs_init(void); ++void sysaufs_fin(void); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* some people doesn't like to show a pointer in kernel */ ++static inline unsigned long sysaufs_si_id(struct au_sbinfo *sbinfo) ++{ ++ return sysaufs_si_mask ^ (unsigned long)sbinfo; ++} ++ ++#define SysaufsSiNamePrefix "si_" ++#define SysaufsSiNameLen (sizeof(SysaufsSiNamePrefix) + 16) ++static inline void sysaufs_name(struct au_sbinfo *sbinfo, char *name) ++{ ++ snprintf(name, SysaufsSiNameLen, SysaufsSiNamePrefix "%lx", ++ sysaufs_si_id(sbinfo)); ++} ++ ++struct au_branch; ++#ifdef CONFIG_SYSFS ++/* sysfs.c */ ++extern struct attribute_group *sysaufs_attr_group; ++ ++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb); ++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, ++ char *buf); ++long au_brinfo_ioctl(struct file *file, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_brinfo_compat_ioctl(struct file *file, unsigned long arg); ++#endif ++ ++void sysaufs_br_init(struct au_branch *br); ++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); ++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); ++ ++#define sysaufs_brs_init() do {} while (0) ++ ++#else ++#define sysaufs_attr_group NULL ++ ++AuStubInt0(sysaufs_si_xi_path, struct seq_file *seq, struct super_block *sb) ++AuStub(ssize_t, sysaufs_si_show, return 0, struct kobject *kobj, ++ struct attribute *attr, char *buf) ++AuStubVoid(sysaufs_br_init, struct au_branch *br) ++AuStubVoid(sysaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(sysaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) ++ ++static inline void sysaufs_brs_init(void) ++{ ++ sysaufs_brs = 0; ++} ++ ++#endif /* CONFIG_SYSFS */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __SYSAUFS_H__ */ +diff -Naur null/fs/aufs/sysfs.c linux-5.15.36/fs/aufs/sysfs.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/sysfs.c 2022-05-10 16:51:39.876744219 +0300 +@@ -0,0 +1,374 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * sysfs interface ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++#ifdef CONFIG_AUFS_FS_MODULE ++/* this entry violates the "one line per file" policy of sysfs */ ++static ssize_t config_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *buf) ++{ ++ ssize_t err; ++ static char *conf = ++/* this file is generated at compiling */ ++#include "conf.str" ++ ; ++ ++ err = snprintf(buf, PAGE_SIZE, conf); ++ if (unlikely(err >= PAGE_SIZE)) ++ err = -EFBIG; ++ return err; ++} ++ ++static struct kobj_attribute au_config_attr = __ATTR_RO(config); ++#endif ++ ++static struct attribute *au_attr[] = { ++#ifdef CONFIG_AUFS_FS_MODULE ++ &au_config_attr.attr, ++#endif ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct attribute_group sysaufs_attr_group_body = { ++ .attrs = au_attr ++}; ++ ++struct attribute_group *sysaufs_attr_group = &sysaufs_attr_group_body; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb) ++{ ++ int err; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (au_opt_test(au_mntflags(sb), XINO)) { ++ err = au_xino_path(seq, au_sbi(sb)->si_xib); ++ seq_putc(seq, '\n'); ++ } ++ return err; ++} ++ ++/* ++ * the lifetime of branch is independent from the entry under sysfs. ++ * sysfs handles the lifetime of the entry, and never call ->show() after it is ++ * unlinked. ++ */ ++static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb, ++ aufs_bindex_t bindex, int idx) ++{ ++ int err; ++ struct path path; ++ struct dentry *root; ++ struct au_branch *br; ++ au_br_perm_str_t perm; ++ ++ AuDbg("b%d\n", bindex); ++ ++ err = 0; ++ root = sb->s_root; ++ di_read_lock_parent(root, !AuLock_IR); ++ br = au_sbr(sb, bindex); ++ ++ switch (idx) { ++ case AuBrSysfs_BR: ++ path.mnt = au_br_mnt(br); ++ path.dentry = au_h_dptr(root, bindex); ++ err = au_seq_path(seq, &path); ++ if (!err) { ++ au_optstr_br_perm(&perm, br->br_perm); ++ seq_printf(seq, "=%s\n", perm.a); ++ } ++ break; ++ case AuBrSysfs_BRID: ++ seq_printf(seq, "%d\n", br->br_id); ++ break; ++ } ++ di_read_unlock(root, !AuLock_IR); ++ if (unlikely(err || seq_has_overflowed(seq))) ++ err = -E2BIG; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct seq_file *au_seq(char *p, ssize_t len) ++{ ++ struct seq_file *seq; ++ ++ seq = kzalloc(sizeof(*seq), GFP_NOFS); ++ if (seq) { ++ /* mutex_init(&seq.lock); */ ++ seq->buf = p; ++ seq->size = len; ++ return seq; /* success */ ++ } ++ ++ seq = ERR_PTR(-ENOMEM); ++ return seq; ++} ++ ++#define SysaufsBr_PREFIX "br" ++#define SysaufsBrid_PREFIX "brid" ++ ++/* todo: file size may exceed PAGE_SIZE */ ++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, ++ char *buf) ++{ ++ ssize_t err; ++ int idx; ++ long l; ++ aufs_bindex_t bbot; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct seq_file *seq; ++ char *name; ++ struct attribute **cattr; ++ ++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); ++ sb = sbinfo->si_sb; ++ ++ /* ++ * prevent a race condition between sysfs and aufs. ++ * for instance, sysfs_file_read() calls sysfs_get_active_two() which ++ * prohibits maintaining the sysfs entries. ++ * hew we acquire read lock after sysfs_get_active_two(). ++ * on the other hand, the remount process may maintain the sysfs/aufs ++ * entries after acquiring write lock. ++ * it can cause a deadlock. ++ * simply we gave up processing read here. ++ */ ++ err = -EBUSY; ++ if (unlikely(!si_noflush_read_trylock(sb))) ++ goto out; ++ ++ seq = au_seq(buf, PAGE_SIZE); ++ err = PTR_ERR(seq); ++ if (IS_ERR(seq)) ++ goto out_unlock; ++ ++ name = (void *)attr->name; ++ cattr = sysaufs_si_attrs; ++ while (*cattr) { ++ if (!strcmp(name, (*cattr)->name)) { ++ err = container_of(*cattr, struct sysaufs_si_attr, attr) ++ ->show(seq, sb); ++ goto out_seq; ++ } ++ cattr++; ++ } ++ ++ if (!strncmp(name, SysaufsBrid_PREFIX, ++ sizeof(SysaufsBrid_PREFIX) - 1)) { ++ idx = AuBrSysfs_BRID; ++ name += sizeof(SysaufsBrid_PREFIX) - 1; ++ } else if (!strncmp(name, SysaufsBr_PREFIX, ++ sizeof(SysaufsBr_PREFIX) - 1)) { ++ idx = AuBrSysfs_BR; ++ name += sizeof(SysaufsBr_PREFIX) - 1; ++ } else ++ BUG(); ++ ++ err = kstrtol(name, 10, &l); ++ if (!err) { ++ bbot = au_sbbot(sb); ++ if (l <= bbot) ++ err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l, idx); ++ else ++ err = -ENOENT; ++ } ++ ++out_seq: ++ if (!err) { ++ err = seq->count; ++ /* sysfs limit */ ++ if (unlikely(err == PAGE_SIZE)) ++ err = -EFBIG; ++ } ++ au_kfree_rcu(seq); ++out_unlock: ++ si_read_unlock(sb); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_brinfo(struct super_block *sb, union aufs_brinfo __user *arg) ++{ ++ int err; ++ int16_t brid; ++ aufs_bindex_t bindex, bbot; ++ size_t sz; ++ char *buf; ++ struct seq_file *seq; ++ struct au_branch *br; ++ ++ si_read_lock(sb, AuLock_FLUSH); ++ bbot = au_sbbot(sb); ++ err = bbot + 1; ++ if (!arg) ++ goto out; ++ ++ err = -ENOMEM; ++ buf = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!buf)) ++ goto out; ++ ++ seq = au_seq(buf, PAGE_SIZE); ++ err = PTR_ERR(seq); ++ if (IS_ERR(seq)) ++ goto out_buf; ++ ++ sz = sizeof(*arg) - offsetof(union aufs_brinfo, path); ++ for (bindex = 0; bindex <= bbot; bindex++, arg++) { ++ /* VERIFY_WRITE */ ++ err = !access_ok(arg, sizeof(*arg)); ++ if (unlikely(err)) ++ break; ++ ++ br = au_sbr(sb, bindex); ++ brid = br->br_id; ++ BUILD_BUG_ON(sizeof(brid) != sizeof(arg->id)); ++ err = __put_user(brid, &arg->id); ++ if (unlikely(err)) ++ break; ++ ++ BUILD_BUG_ON(sizeof(br->br_perm) != sizeof(arg->perm)); ++ err = __put_user(br->br_perm, &arg->perm); ++ if (unlikely(err)) ++ break; ++ ++ err = au_seq_path(seq, &br->br_path); ++ if (unlikely(err)) ++ break; ++ seq_putc(seq, '\0'); ++ if (!seq_has_overflowed(seq)) { ++ err = copy_to_user(arg->path, seq->buf, seq->count); ++ seq->count = 0; ++ if (unlikely(err)) ++ break; ++ } else { ++ err = -E2BIG; ++ goto out_seq; ++ } ++ } ++ if (unlikely(err)) ++ err = -EFAULT; ++ ++out_seq: ++ au_kfree_rcu(seq); ++out_buf: ++ free_page((unsigned long)buf); ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++long au_brinfo_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_brinfo(file->f_path.dentry->d_sb, (void __user *)arg); ++} ++ ++#ifdef CONFIG_COMPAT ++long au_brinfo_compat_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_brinfo(file->f_path.dentry->d_sb, compat_ptr(arg)); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++void sysaufs_br_init(struct au_branch *br) ++{ ++ int i; ++ struct au_brsysfs *br_sysfs; ++ struct attribute *attr; ++ ++ br_sysfs = br->br_sysfs; ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ attr = &br_sysfs->attr; ++ sysfs_attr_init(attr); ++ attr->name = br_sysfs->name; ++ attr->mode = 0444; ++ br_sysfs++; ++ } ++} ++ ++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ struct au_branch *br; ++ struct kobject *kobj; ++ struct au_brsysfs *br_sysfs; ++ int i; ++ aufs_bindex_t bbot; ++ ++ if (!sysaufs_brs) ++ return; ++ ++ kobj = &au_sbi(sb)->si_kobj; ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ br_sysfs = br->br_sysfs; ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ sysfs_remove_file(kobj, &br_sysfs->attr); ++ br_sysfs++; ++ } ++ } ++} ++ ++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err, i; ++ aufs_bindex_t bbot; ++ struct kobject *kobj; ++ struct au_branch *br; ++ struct au_brsysfs *br_sysfs; ++ ++ if (!sysaufs_brs) ++ return; ++ ++ kobj = &au_sbi(sb)->si_kobj; ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ br_sysfs = br->br_sysfs; ++ snprintf(br_sysfs[AuBrSysfs_BR].name, sizeof(br_sysfs->name), ++ SysaufsBr_PREFIX "%d", bindex); ++ snprintf(br_sysfs[AuBrSysfs_BRID].name, sizeof(br_sysfs->name), ++ SysaufsBrid_PREFIX "%d", bindex); ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ err = sysfs_create_file(kobj, &br_sysfs->attr); ++ if (unlikely(err)) ++ pr_warn("failed %s under sysfs(%d)\n", ++ br_sysfs->name, err); ++ br_sysfs++; ++ } ++ } ++} +diff -Naur null/fs/aufs/sysrq.c linux-5.15.36/fs/aufs/sysrq.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/sysrq.c 2022-05-10 16:51:39.877744219 +0300 +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * magic sysrq handler ++ */ ++ ++/* #include */ ++#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void sysrq_sb(struct super_block *sb) ++{ ++ char *plevel; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ struct hlist_bl_head *files; ++ struct hlist_bl_node *pos; ++ struct au_finfo *finfo; ++ struct inode *i; ++ ++ plevel = au_plevel; ++ au_plevel = KERN_WARNING; ++ ++ /* since we define pr_fmt, call printk directly */ ++#define pr(str) printk(KERN_WARNING AUFS_NAME ": " str) ++ ++ sbinfo = au_sbi(sb); ++ printk(KERN_WARNING "si=%lx\n", sysaufs_si_id(sbinfo)); ++ pr("superblock\n"); ++ au_dpri_sb(sb); ++ ++#if 0 /* reserved */ ++ do { ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ ++ err = au_dpages_init(&dpages, GFP_ATOMIC); ++ if (unlikely(err)) ++ break; ++ err = au_dcsub_pages(&dpages, sb->s_root, NULL, NULL); ++ if (!err) ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) ++ au_dpri_dentry(dpage->dentries[j]); ++ } ++ au_dpages_free(&dpages); ++ } while (0); ++#endif ++ ++ pr("isolated inode\n"); ++ spin_lock(&sb->s_inode_list_lock); ++ list_for_each_entry(i, &sb->s_inodes, i_sb_list) { ++ spin_lock(&i->i_lock); ++ if (hlist_empty(&i->i_dentry)) ++ au_dpri_inode(i); ++ spin_unlock(&i->i_lock); ++ } ++ spin_unlock(&sb->s_inode_list_lock); ++ ++ pr("files\n"); ++ files = &au_sbi(sb)->si_files; ++ hlist_bl_lock(files); ++ hlist_bl_for_each_entry(finfo, pos, files, fi_hlist) { ++ umode_t mode; ++ ++ file = finfo->fi_file; ++ mode = file_inode(file)->i_mode; ++ if (!special_file(mode)) ++ au_dpri_file(file); ++ } ++ hlist_bl_unlock(files); ++ pr("done\n"); ++ ++#undef pr ++ au_plevel = plevel; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* module parameter */ ++static char *aufs_sysrq_key = "a"; ++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) ++{ ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_node *pos; ++ ++ lockdep_off(); ++ au_sbilist_lock(); ++ hlist_bl_for_each_entry(sbinfo, pos, &au_sbilist, si_list) ++ sysrq_sb(sbinfo->si_sb); ++ au_sbilist_unlock(); ++ lockdep_on(); ++} ++ ++static struct sysrq_key_op au_sysrq_op = { ++ .handler = au_sysrq, ++ .help_msg = "Aufs", ++ .action_msg = "Aufs", ++ .enable_mask = SYSRQ_ENABLE_DUMP ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int __init au_sysrq_init(void) ++{ ++ int err; ++ char key; ++ ++ err = -1; ++ key = *aufs_sysrq_key; ++ if ('a' <= key && key <= 'z') ++ err = register_sysrq_key(key, &au_sysrq_op); ++ if (unlikely(err)) ++ pr_err("err %d, sysrq=%c\n", err, key); ++ return err; ++} ++ ++void au_sysrq_fin(void) ++{ ++ int err; ++ ++ err = unregister_sysrq_key(*aufs_sysrq_key, &au_sysrq_op); ++ if (unlikely(err)) ++ pr_err("err %d (ignored)\n", err); ++} +diff -Naur null/fs/aufs/vdir.c linux-5.15.36/fs/aufs/vdir.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/vdir.c 2022-05-10 16:51:39.877744219 +0300 +@@ -0,0 +1,896 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * virtual or vertical directory ++ */ ++ ++#include ++#include "aufs.h" ++ ++static unsigned int calc_size(int nlen) ++{ ++ return ALIGN(sizeof(struct au_vdir_de) + nlen, sizeof(ino_t)); ++} ++ ++static int set_deblk_end(union au_vdir_deblk_p *p, ++ union au_vdir_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->deblk - p->deblk) { ++ p->de->de_str.len = 0; ++ /* smp_mb(); */ ++ return 0; ++ } ++ return -1; /* error */ ++} ++ ++/* returns true or false */ ++static int is_deblk_end(union au_vdir_deblk_p *p, ++ union au_vdir_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->deblk - p->deblk) ++ return !p->de->de_str.len; ++ return 1; ++} ++ ++static unsigned char *last_deblk(struct au_vdir *vdir) ++{ ++ return vdir->vd_deblk[vdir->vd_nblk - 1]; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* estimate the appropriate size for name hash table */ ++unsigned int au_rdhash_est(loff_t sz) ++{ ++ unsigned int n; ++ ++ n = UINT_MAX; ++ sz >>= 10; ++ if (sz < n) ++ n = sz; ++ if (sz < AUFS_RDHASH_DEF) ++ n = AUFS_RDHASH_DEF; ++ /* pr_info("n %u\n", n); */ ++ return n; ++} ++ ++/* ++ * the allocated memory has to be freed by ++ * au_nhash_wh_free() or au_nhash_de_free(). ++ */ ++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp) ++{ ++ struct hlist_head *head; ++ unsigned int u; ++ size_t sz; ++ ++ sz = sizeof(*nhash->nh_head) * num_hash; ++ head = kmalloc(sz, gfp); ++ if (head) { ++ nhash->nh_num = num_hash; ++ nhash->nh_head = head; ++ for (u = 0; u < num_hash; u++) ++ INIT_HLIST_HEAD(head++); ++ return 0; /* success */ ++ } ++ ++ return -ENOMEM; ++} ++ ++static void nhash_count(struct hlist_head *head) ++{ ++#if 0 /* debugging */ ++ unsigned long n; ++ struct hlist_node *pos; ++ ++ n = 0; ++ hlist_for_each(pos, head) ++ n++; ++ pr_info("%lu\n", n); ++#endif ++} ++ ++static void au_nhash_wh_do_free(struct hlist_head *head) ++{ ++ struct au_vdir_wh *pos; ++ struct hlist_node *node; ++ ++ hlist_for_each_entry_safe(pos, node, head, wh_hash) ++ au_kfree_rcu(pos); ++} ++ ++static void au_nhash_de_do_free(struct hlist_head *head) ++{ ++ struct au_vdir_dehstr *pos; ++ struct hlist_node *node; ++ ++ hlist_for_each_entry_safe(pos, node, head, hash) ++ au_cache_free_vdir_dehstr(pos); ++} ++ ++static void au_nhash_do_free(struct au_nhash *nhash, ++ void (*free)(struct hlist_head *head)) ++{ ++ unsigned int n; ++ struct hlist_head *head; ++ ++ n = nhash->nh_num; ++ if (!n) ++ return; ++ ++ head = nhash->nh_head; ++ while (n-- > 0) { ++ nhash_count(head); ++ free(head++); ++ } ++ au_kfree_try_rcu(nhash->nh_head); ++} ++ ++void au_nhash_wh_free(struct au_nhash *whlist) ++{ ++ au_nhash_do_free(whlist, au_nhash_wh_do_free); ++} ++ ++static void au_nhash_de_free(struct au_nhash *delist) ++{ ++ au_nhash_do_free(delist, au_nhash_de_do_free); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, ++ int limit) ++{ ++ int num; ++ unsigned int u, n; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ ++ num = 0; ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (u = 0; u < n; u++, head++) ++ hlist_for_each_entry(pos, head, wh_hash) ++ if (pos->wh_bindex == btgt && ++num > limit) ++ return 1; ++ return 0; ++} ++ ++static struct hlist_head *au_name_hash(struct au_nhash *nhash, ++ unsigned char *name, ++ unsigned int len) ++{ ++ unsigned int v; ++ /* const unsigned int magic_bit = 12; */ ++ ++ AuDebugOn(!nhash->nh_num || !nhash->nh_head); ++ ++ v = 0; ++ if (len > 8) ++ len = 8; ++ while (len--) ++ v += *name++; ++ /* v = hash_long(v, magic_bit); */ ++ v %= nhash->nh_num; ++ return nhash->nh_head + v; ++} ++ ++static int au_nhash_test_name(struct au_vdir_destr *str, const char *name, ++ int nlen) ++{ ++ return str->len == nlen && !memcmp(str->name, name, nlen); ++} ++ ++/* returns found or not */ ++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen) ++{ ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct au_vdir_destr *str; ++ ++ head = au_name_hash(whlist, name, nlen); ++ hlist_for_each_entry(pos, head, wh_hash) { ++ str = &pos->wh_str; ++ AuDbg("%.*s\n", str->len, str->name); ++ if (au_nhash_test_name(str, name, nlen)) ++ return 1; ++ } ++ return 0; ++} ++ ++/* returns found(true) or not */ ++static int test_known(struct au_nhash *delist, char *name, int nlen) ++{ ++ struct hlist_head *head; ++ struct au_vdir_dehstr *pos; ++ struct au_vdir_destr *str; ++ ++ head = au_name_hash(delist, name, nlen); ++ hlist_for_each_entry(pos, head, hash) { ++ str = pos->str; ++ AuDbg("%.*s\n", str->len, str->name); ++ if (au_nhash_test_name(str, name, nlen)) ++ return 1; ++ } ++ return 0; ++} ++ ++static void au_shwh_init_wh(struct au_vdir_wh *wh, ino_t ino, ++ unsigned char d_type) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ wh->wh_ino = ino; ++ wh->wh_type = d_type; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, ++ unsigned int d_type, aufs_bindex_t bindex, ++ unsigned char shwh) ++{ ++ int err; ++ struct au_vdir_destr *str; ++ struct au_vdir_wh *wh; ++ ++ AuDbg("%.*s\n", nlen, name); ++ AuDebugOn(!whlist->nh_num || !whlist->nh_head); ++ ++ err = -ENOMEM; ++ wh = kmalloc(sizeof(*wh) + nlen, GFP_NOFS); ++ if (unlikely(!wh)) ++ goto out; ++ ++ err = 0; ++ wh->wh_bindex = bindex; ++ if (shwh) ++ au_shwh_init_wh(wh, ino, d_type); ++ str = &wh->wh_str; ++ str->len = nlen; ++ memcpy(str->name, name, nlen); ++ hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, nlen)); ++ /* smp_mb(); */ ++ ++out: ++ return err; ++} ++ ++static int append_deblk(struct au_vdir *vdir) ++{ ++ int err; ++ unsigned long ul; ++ const unsigned int deblk_sz = vdir->vd_deblk_sz; ++ union au_vdir_deblk_p p, deblk_end; ++ unsigned char **o; ++ ++ err = -ENOMEM; ++ o = au_krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1), ++ GFP_NOFS, /*may_shrink*/0); ++ if (unlikely(!o)) ++ goto out; ++ ++ vdir->vd_deblk = o; ++ p.deblk = kmalloc(deblk_sz, GFP_NOFS); ++ if (p.deblk) { ++ ul = vdir->vd_nblk++; ++ vdir->vd_deblk[ul] = p.deblk; ++ vdir->vd_last.ul = ul; ++ vdir->vd_last.p.deblk = p.deblk; ++ deblk_end.deblk = p.deblk + deblk_sz; ++ err = set_deblk_end(&p, &deblk_end); ++ } ++ ++out: ++ return err; ++} ++ ++static int append_de(struct au_vdir *vdir, char *name, int nlen, ino_t ino, ++ unsigned int d_type, struct au_nhash *delist) ++{ ++ int err; ++ unsigned int sz; ++ const unsigned int deblk_sz = vdir->vd_deblk_sz; ++ union au_vdir_deblk_p p, *room, deblk_end; ++ struct au_vdir_dehstr *dehstr; ++ ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + deblk_sz; ++ room = &vdir->vd_last.p; ++ AuDebugOn(room->deblk < p.deblk || deblk_end.deblk <= room->deblk ++ || !is_deblk_end(room, &deblk_end)); ++ ++ sz = calc_size(nlen); ++ if (unlikely(sz > deblk_end.deblk - room->deblk)) { ++ err = append_deblk(vdir); ++ if (unlikely(err)) ++ goto out; ++ ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + deblk_sz; ++ /* smp_mb(); */ ++ AuDebugOn(room->deblk != p.deblk); ++ } ++ ++ err = -ENOMEM; ++ dehstr = au_cache_alloc_vdir_dehstr(); ++ if (unlikely(!dehstr)) ++ goto out; ++ ++ dehstr->str = &room->de->de_str; ++ hlist_add_head(&dehstr->hash, au_name_hash(delist, name, nlen)); ++ room->de->de_ino = ino; ++ room->de->de_type = d_type; ++ room->de->de_str.len = nlen; ++ memcpy(room->de->de_str.name, name, nlen); ++ ++ err = 0; ++ room->deblk += sz; ++ if (unlikely(set_deblk_end(room, &deblk_end))) ++ err = append_deblk(vdir); ++ /* smp_mb(); */ ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_vdir_free(struct au_vdir *vdir) ++{ ++ unsigned char **deblk; ++ ++ deblk = vdir->vd_deblk; ++ while (vdir->vd_nblk--) ++ au_kfree_try_rcu(*deblk++); ++ au_kfree_try_rcu(vdir->vd_deblk); ++ au_cache_free_vdir(vdir); ++} ++ ++static struct au_vdir *alloc_vdir(struct file *file) ++{ ++ struct au_vdir *vdir; ++ struct super_block *sb; ++ int err; ++ ++ sb = file->f_path.dentry->d_sb; ++ SiMustAnyLock(sb); ++ ++ err = -ENOMEM; ++ vdir = au_cache_alloc_vdir(); ++ if (unlikely(!vdir)) ++ goto out; ++ ++ vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_NOFS); ++ if (unlikely(!vdir->vd_deblk)) ++ goto out_free; ++ ++ vdir->vd_deblk_sz = au_sbi(sb)->si_rdblk; ++ if (!vdir->vd_deblk_sz) { ++ /* estimate the appropriate size for deblk */ ++ vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL); ++ /* pr_info("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */ ++ } ++ vdir->vd_nblk = 0; ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ err = append_deblk(vdir); ++ if (!err) ++ return vdir; /* success */ ++ ++ au_kfree_try_rcu(vdir->vd_deblk); ++ ++out_free: ++ au_cache_free_vdir(vdir); ++out: ++ vdir = ERR_PTR(err); ++ return vdir; ++} ++ ++static int reinit_vdir(struct au_vdir *vdir) ++{ ++ int err; ++ union au_vdir_deblk_p p, deblk_end; ++ ++ while (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--; ++ } ++ p.deblk = vdir->vd_deblk[0]; ++ deblk_end.deblk = p.deblk + vdir->vd_deblk_sz; ++ err = set_deblk_end(&p, &deblk_end); ++ /* keep vd_dblk_sz */ ++ vdir->vd_last.ul = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ /* smp_mb(); */ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuFillVdir_CALLED 1 ++#define AuFillVdir_WHABLE (1 << 1) ++#define AuFillVdir_SHWH (1 << 2) ++#define au_ftest_fillvdir(flags, name) ((flags) & AuFillVdir_##name) ++#define au_fset_fillvdir(flags, name) \ ++ do { (flags) |= AuFillVdir_##name; } while (0) ++#define au_fclr_fillvdir(flags, name) \ ++ do { (flags) &= ~AuFillVdir_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_SHWH ++#undef AuFillVdir_SHWH ++#define AuFillVdir_SHWH 0 ++#endif ++ ++struct fillvdir_arg { ++ struct dir_context ctx; ++ struct file *file; ++ struct au_vdir *vdir; ++ struct au_nhash delist; ++ struct au_nhash whlist; ++ aufs_bindex_t bindex; ++ unsigned int flags; ++ int err; ++}; ++ ++static int fillvdir(struct dir_context *ctx, const char *__name, int nlen, ++ loff_t offset __maybe_unused, u64 h_ino, ++ unsigned int d_type) ++{ ++ struct fillvdir_arg *arg = container_of(ctx, struct fillvdir_arg, ctx); ++ char *name = (void *)__name; ++ struct super_block *sb; ++ ino_t ino; ++ const unsigned char shwh = !!au_ftest_fillvdir(arg->flags, SHWH); ++ ++ arg->err = 0; ++ sb = arg->file->f_path.dentry->d_sb; ++ au_fset_fillvdir(arg->flags, CALLED); ++ /* smp_mb(); */ ++ if (nlen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ if (test_known(&arg->delist, name, nlen) ++ || au_nhash_test_known_wh(&arg->whlist, name, nlen)) ++ goto out; /* already exists or whiteouted */ ++ ++ arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino); ++ if (!arg->err) { ++ if (unlikely(nlen > AUFS_MAX_NAMELEN)) ++ d_type = DT_UNKNOWN; ++ arg->err = append_de(arg->vdir, name, nlen, ino, ++ d_type, &arg->delist); ++ } ++ } else if (au_ftest_fillvdir(arg->flags, WHABLE)) { ++ name += AUFS_WH_PFX_LEN; ++ nlen -= AUFS_WH_PFX_LEN; ++ 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); ++ if (!arg->err) { ++ if (nlen <= AUFS_MAX_NAMELEN + AUFS_WH_PFX_LEN) ++ d_type = DT_UNKNOWN; ++ arg->err = au_nhash_append_wh ++ (&arg->whlist, name, nlen, ino, d_type, ++ arg->bindex, shwh); ++ } ++ } ++ ++out: ++ if (!arg->err) ++ arg->vdir->vd_jiffy = jiffies; ++ /* smp_mb(); */ ++ AuTraceErr(arg->err); ++ return arg->err; ++} ++ ++static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir, ++ struct au_nhash *whlist, struct au_nhash *delist) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ int err; ++ unsigned int nh, u; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct hlist_node *n; ++ char *p, *o; ++ struct au_vdir_destr *destr; ++ ++ AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH)); ++ ++ err = -ENOMEM; ++ o = p = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = 0; ++ nh = whlist->nh_num; ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ p += AUFS_WH_PFX_LEN; ++ for (u = 0; u < nh; u++) { ++ head = whlist->nh_head + u; ++ hlist_for_each_entry_safe(pos, n, head, wh_hash) { ++ destr = &pos->wh_str; ++ memcpy(p, destr->name, destr->len); ++ err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN, ++ pos->wh_ino, pos->wh_type, delist); ++ if (unlikely(err)) ++ break; ++ } ++ } ++ ++ free_page((unsigned long)o); ++ ++out: ++ AuTraceErr(err); ++ return err; ++#else ++ return 0; ++#endif ++} ++ ++static int au_do_read_vdir(struct fillvdir_arg *arg) ++{ ++ int err; ++ unsigned int rdhash; ++ loff_t offset; ++ aufs_bindex_t bbot, bindex, btop; ++ unsigned char shwh; ++ struct file *hf, *file; ++ struct super_block *sb; ++ ++ file = arg->file; ++ sb = file->f_path.dentry->d_sb; ++ SiMustAnyLock(sb); ++ ++ rdhash = au_sbi(sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(file, /*dentry*/NULL)); ++ err = au_nhash_alloc(&arg->delist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_nhash_alloc(&arg->whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out_delist; ++ ++ err = 0; ++ arg->flags = 0; ++ shwh = 0; ++ if (au_opt_test(au_mntflags(sb), SHWH)) { ++ shwh = 1; ++ au_fset_fillvdir(arg->flags, SHWH); ++ } ++ btop = au_fbtop(file); ++ bbot = au_fbbot_dir(file); ++ for (bindex = btop; !err && bindex <= bbot; bindex++) { ++ hf = au_hf_dir(file, bindex); ++ if (!hf) ++ continue; ++ ++ offset = vfsub_llseek(hf, 0, SEEK_SET); ++ err = offset; ++ if (unlikely(offset)) ++ break; ++ ++ arg->bindex = bindex; ++ au_fclr_fillvdir(arg->flags, WHABLE); ++ if (shwh ++ || (bindex != bbot ++ && au_br_whable(au_sbr_perm(sb, bindex)))) ++ au_fset_fillvdir(arg->flags, WHABLE); ++ do { ++ arg->err = 0; ++ au_fclr_fillvdir(arg->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(hf, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && au_ftest_fillvdir(arg->flags, CALLED)); ++ ++ /* ++ * dir_relax() may be good for concurrency, but aufs should not ++ * use it since it will cause a lockdep problem. ++ */ ++ } ++ ++ if (!err && shwh) ++ err = au_handle_shwh(sb, arg->vdir, &arg->whlist, &arg->delist); ++ ++ au_nhash_wh_free(&arg->whlist); ++ ++out_delist: ++ au_nhash_de_free(&arg->delist); ++out: ++ return err; ++} ++ ++static int read_vdir(struct file *file, int may_read) ++{ ++ int err; ++ unsigned long expire; ++ unsigned char do_read; ++ struct fillvdir_arg arg = { ++ .ctx = { ++ .actor = fillvdir ++ } ++ }; ++ struct inode *inode; ++ struct au_vdir *vdir, *allocated; ++ ++ err = 0; ++ inode = file_inode(file); ++ IMustLock(inode); ++ IiMustWriteLock(inode); ++ SiMustAnyLock(inode->i_sb); ++ ++ allocated = NULL; ++ do_read = 0; ++ expire = au_sbi(inode->i_sb)->si_rdcache; ++ vdir = au_ivdir(inode); ++ if (!vdir) { ++ do_read = 1; ++ vdir = alloc_vdir(file); ++ err = PTR_ERR(vdir); ++ if (IS_ERR(vdir)) ++ goto out; ++ err = 0; ++ allocated = vdir; ++ } else if (may_read ++ && (!inode_eq_iversion(inode, vdir->vd_version) ++ || time_after(jiffies, vdir->vd_jiffy + expire))) { ++ do_read = 1; ++ err = reinit_vdir(vdir); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ if (!do_read) ++ return 0; /* success */ ++ ++ arg.file = file; ++ arg.vdir = vdir; ++ err = au_do_read_vdir(&arg); ++ if (!err) { ++ /* file->f_pos = 0; */ /* todo: ctx->pos? */ ++ vdir->vd_version = inode_query_iversion(inode); ++ vdir->vd_last.ul = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ if (allocated) ++ au_set_ivdir(inode, allocated); ++ } else if (allocated) ++ au_vdir_free(allocated); ++ ++out: ++ return err; ++} ++ ++static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src) ++{ ++ int err, rerr; ++ unsigned long ul, n; ++ const unsigned int deblk_sz = src->vd_deblk_sz; ++ ++ AuDebugOn(tgt->vd_nblk != 1); ++ ++ err = -ENOMEM; ++ if (tgt->vd_nblk < src->vd_nblk) { ++ unsigned char **p; ++ ++ p = au_krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk, ++ GFP_NOFS, /*may_shrink*/0); ++ if (unlikely(!p)) ++ goto out; ++ tgt->vd_deblk = p; ++ } ++ ++ if (tgt->vd_deblk_sz != deblk_sz) { ++ unsigned char *p; ++ ++ tgt->vd_deblk_sz = deblk_sz; ++ p = au_krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS, ++ /*may_shrink*/1); ++ if (unlikely(!p)) ++ goto out; ++ tgt->vd_deblk[0] = p; ++ } ++ memcpy(tgt->vd_deblk[0], src->vd_deblk[0], deblk_sz); ++ tgt->vd_version = src->vd_version; ++ tgt->vd_jiffy = src->vd_jiffy; ++ ++ n = src->vd_nblk; ++ for (ul = 1; ul < n; ul++) { ++ tgt->vd_deblk[ul] = kmemdup(src->vd_deblk[ul], deblk_sz, ++ GFP_NOFS); ++ if (unlikely(!tgt->vd_deblk[ul])) ++ goto out; ++ tgt->vd_nblk++; ++ } ++ tgt->vd_nblk = n; ++ tgt->vd_last.ul = tgt->vd_last.ul; ++ tgt->vd_last.p.deblk = tgt->vd_deblk[tgt->vd_last.ul]; ++ tgt->vd_last.p.deblk += src->vd_last.p.deblk ++ - src->vd_deblk[src->vd_last.ul]; ++ /* smp_mb(); */ ++ return 0; /* success */ ++ ++out: ++ rerr = reinit_vdir(tgt); ++ BUG_ON(rerr); ++ return err; ++} ++ ++int au_vdir_init(struct file *file) ++{ ++ int err; ++ struct inode *inode; ++ struct au_vdir *vdir_cache, *allocated; ++ ++ /* test file->f_pos here instead of ctx->pos */ ++ err = read_vdir(file, !file->f_pos); ++ if (unlikely(err)) ++ goto out; ++ ++ allocated = NULL; ++ vdir_cache = au_fvdir_cache(file); ++ if (!vdir_cache) { ++ vdir_cache = alloc_vdir(file); ++ err = PTR_ERR(vdir_cache); ++ if (IS_ERR(vdir_cache)) ++ goto out; ++ allocated = vdir_cache; ++ } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) { ++ /* test file->f_pos here instead of ctx->pos */ ++ err = reinit_vdir(vdir_cache); ++ if (unlikely(err)) ++ goto out; ++ } else ++ return 0; /* success */ ++ ++ inode = file_inode(file); ++ err = copy_vdir(vdir_cache, au_ivdir(inode)); ++ if (!err) { ++ file->f_version = inode_query_iversion(inode); ++ if (allocated) ++ au_set_fvdir_cache(file, allocated); ++ } else if (allocated) ++ au_vdir_free(allocated); ++ ++out: ++ return err; ++} ++ ++static loff_t calc_offset(struct au_vdir *vdir) ++{ ++ loff_t offset; ++ union au_vdir_deblk_p p; ++ ++ p.deblk = vdir->vd_deblk[vdir->vd_last.ul]; ++ offset = vdir->vd_last.p.deblk - p.deblk; ++ offset += vdir->vd_deblk_sz * vdir->vd_last.ul; ++ return offset; ++} ++ ++/* returns true or false */ ++static int seek_vdir(struct file *file, struct dir_context *ctx) ++{ ++ int valid; ++ unsigned int deblk_sz; ++ unsigned long ul, n; ++ loff_t offset; ++ union au_vdir_deblk_p p, deblk_end; ++ struct au_vdir *vdir_cache; ++ ++ valid = 1; ++ vdir_cache = au_fvdir_cache(file); ++ offset = calc_offset(vdir_cache); ++ AuDbg("offset %lld\n", offset); ++ if (ctx->pos == offset) ++ goto out; ++ ++ vdir_cache->vd_last.ul = 0; ++ vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0]; ++ if (!ctx->pos) ++ goto out; ++ ++ valid = 0; ++ deblk_sz = vdir_cache->vd_deblk_sz; ++ ul = div64_u64(ctx->pos, deblk_sz); ++ AuDbg("ul %lu\n", ul); ++ if (ul >= vdir_cache->vd_nblk) ++ goto out; ++ ++ n = vdir_cache->vd_nblk; ++ for (; ul < n; ul++) { ++ p.deblk = vdir_cache->vd_deblk[ul]; ++ deblk_end.deblk = p.deblk + deblk_sz; ++ offset = ul; ++ offset *= deblk_sz; ++ while (!is_deblk_end(&p, &deblk_end) && offset < ctx->pos) { ++ unsigned int l; ++ ++ l = calc_size(p.de->de_str.len); ++ offset += l; ++ p.deblk += l; ++ } ++ if (!is_deblk_end(&p, &deblk_end)) { ++ valid = 1; ++ vdir_cache->vd_last.ul = ul; ++ vdir_cache->vd_last.p = p; ++ break; ++ } ++ } ++ ++out: ++ /* smp_mb(); */ ++ if (!valid) ++ AuDbg("valid %d\n", !valid); ++ return valid; ++} ++ ++int au_vdir_fill_de(struct file *file, struct dir_context *ctx) ++{ ++ unsigned int l, deblk_sz; ++ union au_vdir_deblk_p deblk_end; ++ struct au_vdir *vdir_cache; ++ struct au_vdir_de *de; ++ ++ 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]; ++ deblk_end.deblk += deblk_sz; ++ while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) { ++ de = vdir_cache->vd_last.p.de; ++ AuDbg("%.*s, off%lld, i%lu, dt%d\n", ++ de->de_str.len, de->de_str.name, ctx->pos, ++ (unsigned long)de->de_ino, de->de_type); ++ if (unlikely(!dir_emit(ctx, de->de_str.name, ++ de->de_str.len, de->de_ino, ++ de->de_type))) { ++ /* todo: ignore the error caused by udba? */ ++ /* return err; */ ++ return 0; ++ } ++ ++ l = calc_size(de->de_str.len); ++ vdir_cache->vd_last.p.deblk += l; ++ ctx->pos += l; ++ } ++ if (vdir_cache->vd_last.ul < vdir_cache->vd_nblk - 1) { ++ vdir_cache->vd_last.ul++; ++ vdir_cache->vd_last.p.deblk ++ = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; ++ ctx->pos = deblk_sz * vdir_cache->vd_last.ul; ++ continue; ++ } ++ break; ++ } ++ ++ /* smp_mb(); */ ++ return 0; ++} +diff -Naur null/fs/aufs/vfsub.c linux-5.15.36/fs/aufs/vfsub.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/vfsub.c 2022-05-10 16:51:39.877744219 +0300 +@@ -0,0 +1,918 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * sub-routines for VFS ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++#ifdef CONFIG_AUFS_BR_FUSE ++int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb) ++{ ++ if (!au_test_fuse(h_sb) || !au_userns) ++ return 0; ++ ++ return is_current_mnt_ns(mnt) ? 0 : -EACCES; ++} ++#endif ++ ++int vfsub_sync_filesystem(struct super_block *h_sb) ++{ ++ int err; ++ ++ lockdep_off(); ++ down_read(&h_sb->s_umount); ++ err = sync_filesystem(h_sb); ++ up_read(&h_sb->s_umount); ++ lockdep_on(); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_update_h_iattr(struct path *h_path, int *did) ++{ ++ int err; ++ struct kstat st; ++ struct super_block *h_sb; ++ ++ /* ++ * Always needs h_path->mnt for LSM or FUSE branch. ++ */ ++ AuDebugOn(!h_path->mnt); ++ ++ /* for remote fs, leave work for its getattr or d_revalidate */ ++ /* for bad i_attr fs, handle them in aufs_getattr() */ ++ /* still some fs may acquire i_mutex. we need to skip them */ ++ err = 0; ++ if (!did) ++ did = &err; ++ h_sb = h_path->dentry->d_sb; ++ *did = (!au_test_fs_remote(h_sb) && au_test_fs_refresh_iattr(h_sb)); ++ if (*did) ++ err = vfsub_getattr(h_path, &st); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct file *vfsub_dentry_open(struct path *path, int flags) ++{ ++ return dentry_open(path, flags /* | __FMODE_NONOTIFY */, ++ current_cred()); ++} ++ ++struct file *vfsub_filp_open(const char *path, int oflags, int mode) ++{ ++ struct file *file; ++ ++ lockdep_off(); ++ file = filp_open(path, ++ oflags /* | __FMODE_NONOTIFY */, ++ mode); ++ lockdep_on(); ++ if (IS_ERR(file)) ++ goto out; ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ ++out: ++ return file; ++} ++ ++/* ++ * Ideally this function should call VFS:do_last() in order to keep all its ++ * checkings. But it is very hard for aufs to regenerate several VFS internal ++ * structure such as nameidata. This is a second (or third) best approach. ++ * 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) ++{ ++ 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; ++ ++ IMustLock(dir); ++ AuDebugOn(!dir->i_op->atomic_open); ++ ++ err = au_br_test_oflag(args->open_flag, br); ++ if (unlikely(err)) ++ goto out; ++ ++ 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); ++ 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 (file->f_mode & FMODE_CREATED) ++ fsnotify_create(dir, dentry); ++ if (!(file->f_mode & FMODE_OPENED)) { ++ au_lcnt_dec(&br->br_nfiles); ++ goto out; ++ } ++ ++ /* 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; ++} ++ ++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path) ++{ ++ int err; ++ ++ err = kern_path(name, flags, path); ++ if (!err && d_is_positive(path->dentry)) ++ vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++struct dentry *vfsub_lookup_one_len_unlocked(const char *name, ++ struct path *ppath, int len) ++{ ++ struct path path; ++ ++ path.dentry = lookup_one_len_unlocked(name, ppath->dentry, len); ++ if (IS_ERR(path.dentry)) ++ goto out; ++ if (d_is_positive(path.dentry)) { ++ path.mnt = ppath->mnt; ++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ ++ } ++ ++out: ++ AuTraceErrPtr(path.dentry); ++ return path.dentry; ++} ++ ++struct dentry *vfsub_lookup_one_len(const char *name, struct path *ppath, ++ int len) ++{ ++ struct path path; ++ ++ /* VFS checks it too, but by WARN_ON_ONCE() */ ++ IMustLock(d_inode(ppath->dentry)); ++ ++ path.dentry = lookup_one_len(name, ppath->dentry, len); ++ if (IS_ERR(path.dentry)) ++ goto out; ++ if (d_is_positive(path.dentry)) { ++ path.mnt = ppath->mnt; ++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ ++ } ++ ++out: ++ AuTraceErrPtr(path.dentry); ++ return path.dentry; ++} ++ ++void vfsub_call_lkup_one(void *args) ++{ ++ struct vfsub_lkup_one_args *a = args; ++ *a->errp = vfsub_lkup_one(a->name, a->ppath); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2) ++{ ++ struct dentry *d; ++ ++ lockdep_off(); ++ d = lock_rename(d1, d2); ++ lockdep_on(); ++ au_hn_suspend(hdir1); ++ if (hdir1 != hdir2) ++ au_hn_suspend(hdir2); ++ ++ return d; ++} ++ ++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2) ++{ ++ au_hn_resume(hdir1); ++ if (hdir1 != hdir2) ++ au_hn_resume(hdir2); ++ lockdep_off(); ++ unlock_rename(d1, d2); ++ lockdep_on(); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_create(struct inode *dir, struct path *path, int mode, bool want_excl) ++{ ++ int err; ++ struct dentry *d; ++ struct user_namespace *userns; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mknod(path, d, mode, 0); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ userns = mnt_user_ns(path->mnt); ++ ++ lockdep_off(); ++ err = vfs_create(userns, dir, path->dentry, mode, want_excl); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_symlink(struct inode *dir, struct path *path, const char *symname) ++{ ++ int err; ++ struct dentry *d; ++ struct user_namespace *userns; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_symlink(path, d, symname); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ userns = mnt_user_ns(path->mnt); ++ ++ lockdep_off(); ++ err = vfs_symlink(userns, dir, path->dentry, symname); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev) ++{ ++ int err; ++ struct dentry *d; ++ struct user_namespace *userns; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mknod(path, d, mode, new_encode_dev(dev)); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ userns = mnt_user_ns(path->mnt); ++ ++ lockdep_off(); ++ err = vfs_mknod(userns, dir, path->dentry, mode, dev); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++static int au_test_nlink(struct inode *inode) ++{ ++ const unsigned int link_max = UINT_MAX >> 1; /* rough margin */ ++ ++ if (!au_test_fs_no_limit_nlink(inode->i_sb) ++ || inode->i_nlink < link_max) ++ return 0; ++ return -EMLINK; ++} ++ ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path, ++ struct inode **delegated_inode) ++{ ++ int err; ++ struct dentry *d; ++ struct user_namespace *userns; ++ ++ IMustLock(dir); ++ ++ err = au_test_nlink(d_inode(src_dentry)); ++ if (unlikely(err)) ++ return err; ++ ++ /* we don't call may_linkat() */ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_link(src_dentry, path, d); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ userns = mnt_user_ns(path->mnt); ++ ++ lockdep_off(); ++ err = vfs_link(src_dentry, userns, dir, path->dentry, delegated_inode); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ /* fuse has different memory inode for the same inumber */ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ tmp.dentry = src_dentry; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct path *path, ++ struct inode **delegated_inode, unsigned int flags) ++{ ++ int err; ++ struct renamedata rd; ++ struct path tmp = { ++ .mnt = path->mnt ++ }; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ IMustLock(src_dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ tmp.dentry = src_dentry->d_parent; ++ err = security_path_rename(&tmp, src_dentry, path, d, /*flags*/0); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ rd.old_mnt_userns = mnt_user_ns(path->mnt); ++ rd.old_dir = src_dir; ++ rd.old_dentry = src_dentry; ++ rd.new_mnt_userns = rd.old_mnt_userns; ++ rd.new_dir = dir; ++ rd.new_dentry = path->dentry; ++ rd.delegated_inode = delegated_inode; ++ rd.flags = flags; ++ lockdep_off(); ++ err = vfs_rename(&rd); ++ lockdep_on(); ++ if (!err) { ++ int did; ++ ++ tmp.dentry = d->d_parent; ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = src_dentry; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ tmp.dentry = src_dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_mkdir(struct inode *dir, struct path *path, int mode) ++{ ++ int err; ++ struct dentry *d; ++ struct user_namespace *userns; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mkdir(path, d, mode); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ userns = mnt_user_ns(path->mnt); ++ ++ lockdep_off(); ++ err = vfs_mkdir(userns, dir, path->dentry, mode); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_rmdir(struct inode *dir, struct path *path) ++{ ++ int err; ++ struct dentry *d; ++ struct user_namespace *userns; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_rmdir(path, d); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ userns = mnt_user_ns(path->mnt); ++ ++ lockdep_off(); ++ err = vfs_rmdir(userns, dir, path->dentry); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = { ++ .dentry = path->dentry->d_parent, ++ .mnt = path->mnt ++ }; ++ ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: support mmap_sem? */ ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ lockdep_off(); ++ err = vfs_read(file, ubuf, count, ppos); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ lockdep_off(); ++ err = kernel_read(file, kbuf, count, ppos); ++ lockdep_on(); ++ AuTraceErr(err); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ lockdep_off(); ++ err = vfs_write(file, ubuf, count, ppos); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ ++ lockdep_off(); ++ err = kernel_write(file, kbuf, count, ppos); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++int vfsub_flush(struct file *file, fl_owner_t id) ++{ ++ int err; ++ ++ err = 0; ++ if (file->f_op->flush) { ++ if (!au_test_nfs(file->f_path.dentry->d_sb)) ++ err = file->f_op->flush(file, id); ++ else { ++ lockdep_off(); ++ err = file->f_op->flush(file, id); ++ lockdep_on(); ++ } ++ if (!err) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); ++ /*ignore*/ ++ } ++ return err; ++} ++ ++int vfsub_iterate_dir(struct file *file, struct dir_context *ctx) ++{ ++ int err; ++ ++ AuDbg("%pD, ctx{%ps, %llu}\n", file, ctx->actor, ctx->pos); ++ ++ lockdep_off(); ++ err = iterate_dir(file, ctx); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ ++ return err; ++} ++ ++long vfsub_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) ++{ ++ long err; ++ ++ lockdep_off(); ++ err = do_splice_to(in, ppos, pipe, len, flags); ++ lockdep_on(); ++ file_accessed(in); ++ if (err >= 0) ++ vfsub_update_h_iattr(&in->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags) ++{ ++ long err; ++ ++ lockdep_off(); ++ err = do_splice_from(pipe, out, ppos, len, flags); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&out->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++int vfsub_fsync(struct file *file, struct path *path, int datasync) ++{ ++ int err; ++ ++ /* file can be NULL */ ++ lockdep_off(); ++ err = vfs_fsync(file, datasync); ++ lockdep_on(); ++ if (!err) { ++ if (!path) { ++ AuDebugOn(!file); ++ path = &file->f_path; ++ } ++ vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ ++ } ++ return err; ++} ++ ++/* cf. open.c:do_sys_truncate() and do_sys_ftruncate() */ ++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, ++ struct file *h_file) ++{ ++ int err; ++ struct inode *h_inode; ++ struct super_block *h_sb; ++ struct user_namespace *h_userns; ++ ++ if (!h_file) { ++ err = vfsub_truncate(h_path, length); ++ goto out; ++ } ++ ++ h_inode = d_inode(h_path->dentry); ++ h_sb = h_inode->i_sb; ++ lockdep_off(); ++ sb_start_write(h_sb); ++ lockdep_on(); ++ err = security_path_truncate(h_path); ++ if (!err) { ++ h_userns = mnt_user_ns(h_path->mnt); ++ lockdep_off(); ++ err = do_truncate(h_userns, h_path->dentry, length, attr, ++ h_file); ++ lockdep_on(); ++ } ++ lockdep_off(); ++ sb_end_write(h_sb); ++ lockdep_on(); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_vfsub_mkdir_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++ int mode; ++}; ++ ++static void au_call_vfsub_mkdir(void *args) ++{ ++ struct au_vfsub_mkdir_args *a = args; ++ *a->errp = vfsub_mkdir(a->dir, a->path, a->mode); ++} ++ ++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode) ++{ ++ int err, do_sio, wkq_err; ++ struct user_namespace *userns; ++ ++ userns = mnt_user_ns(path->mnt); ++ do_sio = au_test_h_perm_sio(userns, dir, MAY_EXEC | MAY_WRITE); ++ if (!do_sio) { ++ lockdep_off(); ++ err = vfsub_mkdir(dir, path, mode); ++ lockdep_on(); ++ } else { ++ struct au_vfsub_mkdir_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path, ++ .mode = mode ++ }; ++ wkq_err = au_wkq_wait(au_call_vfsub_mkdir, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++ ++struct au_vfsub_rmdir_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++}; ++ ++static void au_call_vfsub_rmdir(void *args) ++{ ++ struct au_vfsub_rmdir_args *a = args; ++ *a->errp = vfsub_rmdir(a->dir, a->path); ++} ++ ++int vfsub_sio_rmdir(struct inode *dir, struct path *path) ++{ ++ int err, do_sio, wkq_err; ++ struct user_namespace *userns; ++ ++ userns = mnt_user_ns(path->mnt); ++ do_sio = au_test_h_perm_sio(userns, dir, MAY_EXEC | MAY_WRITE); ++ if (!do_sio) { ++ lockdep_off(); ++ err = vfsub_rmdir(dir, path); ++ lockdep_on(); ++ } else { ++ struct au_vfsub_rmdir_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path ++ }; ++ wkq_err = au_wkq_wait(au_call_vfsub_rmdir, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct notify_change_args { ++ int *errp; ++ struct path *path; ++ struct iattr *ia; ++ struct inode **delegated_inode; ++}; ++ ++static void call_notify_change(void *args) ++{ ++ struct notify_change_args *a = args; ++ struct inode *h_inode; ++ struct user_namespace *userns; ++ ++ h_inode = d_inode(a->path->dentry); ++ IMustLock(h_inode); ++ ++ *a->errp = -EPERM; ++ if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) { ++ userns = mnt_user_ns(a->path->mnt); ++ lockdep_off(); ++ *a->errp = notify_change(userns, a->path->dentry, a->ia, ++ a->delegated_inode); ++ lockdep_on(); ++ if (!*a->errp) ++ vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/ ++ } ++ AuTraceErr(*a->errp); ++} ++ ++int vfsub_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode) ++{ ++ int err; ++ struct notify_change_args args = { ++ .errp = &err, ++ .path = path, ++ .ia = ia, ++ .delegated_inode = delegated_inode ++ }; ++ ++ call_notify_change(&args); ++ ++ return err; ++} ++ ++int vfsub_sio_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode) ++{ ++ int err, wkq_err; ++ struct notify_change_args args = { ++ .errp = &err, ++ .path = path, ++ .ia = ia, ++ .delegated_inode = delegated_inode ++ }; ++ ++ wkq_err = au_wkq_wait(call_notify_change, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct unlink_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++ struct inode **delegated_inode; ++}; ++ ++static void call_unlink(void *args) ++{ ++ struct unlink_args *a = args; ++ struct dentry *d = a->path->dentry; ++ struct inode *h_inode; ++ struct user_namespace *userns; ++ const int stop_sillyrename = (au_test_nfs(d->d_sb) ++ && au_dcount(d) == 1); ++ ++ IMustLock(a->dir); ++ ++ a->path->dentry = d->d_parent; ++ *a->errp = security_path_unlink(a->path, d); ++ a->path->dentry = d; ++ if (unlikely(*a->errp)) ++ return; ++ ++ if (!stop_sillyrename) ++ dget(d); ++ h_inode = NULL; ++ if (d_is_positive(d)) { ++ h_inode = d_inode(d); ++ ihold(h_inode); ++ } ++ ++ userns = mnt_user_ns(a->path->mnt); ++ lockdep_off(); ++ *a->errp = vfs_unlink(userns, a->dir, d, a->delegated_inode); ++ lockdep_on(); ++ if (!*a->errp) { ++ struct path tmp = { ++ .dentry = d->d_parent, ++ .mnt = a->path->mnt ++ }; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ ++ } ++ ++ if (!stop_sillyrename) ++ dput(d); ++ if (h_inode) ++ iput(h_inode); ++ ++ AuTraceErr(*a->errp); ++} ++ ++/* ++ * @dir: must be locked. ++ * @dentry: target dentry. ++ */ ++int vfsub_unlink(struct inode *dir, struct path *path, ++ struct inode **delegated_inode, int force) ++{ ++ int err; ++ struct unlink_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path, ++ .delegated_inode = delegated_inode ++ }; ++ ++ if (!force) ++ call_unlink(&args); ++ else { ++ int wkq_err; ++ ++ wkq_err = au_wkq_wait(call_unlink, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} +diff -Naur null/fs/aufs/vfsub.h linux-5.15.36/fs/aufs/vfsub.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/vfsub.h 2022-05-10 16:51:39.877744219 +0300 +@@ -0,0 +1,358 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * sub-routines for VFS ++ */ ++ ++#ifndef __AUFS_VFSUB_H__ ++#define __AUFS_VFSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include "debug.h" ++ ++/* copied from linux/fs/internal.h */ ++/* todo: BAD approach!! */ ++extern void __mnt_drop_write(struct vfsmount *); ++extern struct file *alloc_empty_file(int, const struct cred *); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for lower inode */ ++/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */ ++/* reduce? gave up. */ ++enum { ++ AuLsc_I_Begin = I_MUTEX_PARENT2, /* 5 */ ++ AuLsc_I_PARENT, /* lower inode, parent first */ ++ AuLsc_I_PARENT2, /* copyup dirs */ ++ AuLsc_I_PARENT3, /* copyup wh */ ++ AuLsc_I_CHILD, ++ AuLsc_I_CHILD2, ++ AuLsc_I_End ++}; ++ ++/* to debug easier, do not make them inlined functions */ ++#define MtxMustLock(mtx) AuDebugOn(!mutex_is_locked(mtx)) ++#define IMustLock(i) AuDebugOn(!inode_is_locked(i)) ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void vfsub_drop_nlink(struct inode *inode) ++{ ++ AuDebugOn(!inode->i_nlink); ++ drop_nlink(inode); ++} ++ ++static inline void vfsub_dead_dir(struct inode *inode) ++{ ++ AuDebugOn(!S_ISDIR(inode->i_mode)); ++ inode->i_flags |= S_DEAD; ++ clear_nlink(inode); ++} ++ ++static inline int vfsub_native_ro(struct inode *inode) ++{ ++ return sb_rdonly(inode->i_sb) ++ || IS_RDONLY(inode) ++ /* || IS_APPEND(inode) */ ++ || IS_IMMUTABLE(inode); ++} ++ ++#ifdef CONFIG_AUFS_BR_FUSE ++int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb); ++#else ++AuStubInt0(vfsub_test_mntns, struct vfsmount *mnt, struct super_block *h_sb); ++#endif ++ ++int vfsub_sync_filesystem(struct super_block *h_sb); ++ ++/* ---------------------------------------------------------------------- */ ++ ++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; ++ struct au_branch *br; ++}; ++int vfsub_atomic_open(struct inode *dir, struct dentry *dentry, ++ 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, ++ struct path *ppath, int len); ++struct dentry *vfsub_lookup_one_len(const char *name, struct path *ppath, ++ int len); ++ ++struct vfsub_lkup_one_args { ++ struct dentry **errp; ++ struct qstr *name; ++ struct path *ppath; ++}; ++ ++static inline struct dentry *vfsub_lkup_one(struct qstr *name, ++ struct path *ppath) ++{ ++ return vfsub_lookup_one_len(name->name, ppath, name->len); ++} ++ ++void vfsub_call_lkup_one(void *args); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int vfsub_mnt_want_write(struct vfsmount *mnt) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = mnt_want_write(mnt); ++ lockdep_on(); ++ return err; ++} ++ ++static inline void vfsub_mnt_drop_write(struct vfsmount *mnt) ++{ ++ lockdep_off(); ++ mnt_drop_write(mnt); ++ lockdep_on(); ++} ++ ++#if 0 /* reserved */ ++static inline void vfsub_mnt_drop_write_file(struct file *file) ++{ ++ lockdep_off(); ++ mnt_drop_write_file(file); ++ lockdep_on(); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_hinode; ++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2); ++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2); ++ ++int vfsub_create(struct inode *dir, struct path *path, int mode, ++ bool want_excl); ++int vfsub_symlink(struct inode *dir, struct path *path, ++ const char *symname); ++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev); ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, ++ struct path *path, struct inode **delegated_inode); ++int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry, ++ struct inode *hdir, struct path *path, ++ struct inode **delegated_inode, unsigned int flags); ++int vfsub_mkdir(struct inode *dir, struct path *path, int mode); ++int vfsub_rmdir(struct inode *dir, struct path *path); ++ ++/* ---------------------------------------------------------------------- */ ++ ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos); ++int vfsub_flush(struct file *file, fl_owner_t id); ++int vfsub_iterate_dir(struct file *file, struct dir_context *ctx); ++ ++static inline loff_t vfsub_f_size_read(struct file *file) ++{ ++ return i_size_read(file_inode(file)); ++} ++ ++static inline unsigned int vfsub_file_flags(struct file *file) ++{ ++ unsigned int flags; ++ ++ spin_lock(&file->f_lock); ++ flags = file->f_flags; ++ spin_unlock(&file->f_lock); ++ ++ return flags; ++} ++ ++static inline int vfsub_file_execed(struct file *file) ++{ ++ /* todo: direct access f_flags */ ++ return !!(vfsub_file_flags(file) & __FMODE_EXEC); ++} ++ ++#if 0 /* reserved */ ++static inline void vfsub_file_accessed(struct file *h_file) ++{ ++ file_accessed(h_file); ++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); /*ignore*/ ++} ++#endif ++ ++#if 0 /* reserved */ ++static inline void vfsub_touch_atime(struct vfsmount *h_mnt, ++ struct dentry *h_dentry) ++{ ++ struct path h_path = { ++ .dentry = h_dentry, ++ .mnt = h_mnt ++ }; ++ touch_atime(&h_path); ++ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/ ++} ++#endif ++ ++static inline int vfsub_update_time(struct inode *h_inode, ++ struct timespec64 *ts, int flags) ++{ ++ return inode_update_time(h_inode, ts, flags); ++ /* no vfsub_update_h_iattr() since we don't have struct path */ ++} ++ ++#ifdef CONFIG_FS_POSIX_ACL ++static inline int vfsub_acl_chmod(struct user_namespace *h_userns, ++ struct inode *h_inode, umode_t h_mode) ++{ ++ int err; ++ ++ err = posix_acl_chmod(h_userns, h_inode, h_mode); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ return err; ++} ++#else ++AuStubInt0(vfsub_acl_chmod, struct user_namespace *h_userns, ++ struct inode *h_inode, umode_t h_mode); ++#endif ++ ++long vfsub_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags); ++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags); ++ ++static inline long vfsub_truncate(struct path *path, loff_t length) ++{ ++ long err; ++ ++ lockdep_off(); ++ err = vfs_truncate(path, length); ++ lockdep_on(); ++ return err; ++} ++ ++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, ++ struct file *h_file); ++int vfsub_fsync(struct file *file, struct path *path, int datasync); ++ ++/* ++ * re-use branch fs's ioctl(FICLONE) while aufs itself doesn't support such ++ * ioctl. ++ */ ++static inline loff_t vfsub_clone_file_range(struct file *src, struct file *dst, ++ loff_t len) ++{ ++ loff_t err; ++ ++ lockdep_off(); ++ err = vfs_clone_file_range(src, 0, dst, 0, len, /*remap_flags*/0); ++ lockdep_on(); ++ ++ return err; ++} ++ ++/* copy_file_range(2) is a systemcall */ ++static inline ssize_t vfsub_copy_file_range(struct file *src, loff_t src_pos, ++ struct file *dst, loff_t dst_pos, ++ size_t len, unsigned int flags) ++{ ++ ssize_t ssz; ++ ++ lockdep_off(); ++ ssz = vfs_copy_file_range(src, src_pos, dst, dst_pos, len, flags); ++ lockdep_on(); ++ ++ return ssz; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin) ++{ ++ loff_t err; ++ ++ lockdep_off(); ++ err = vfs_llseek(file, offset, origin); ++ lockdep_on(); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode); ++int vfsub_sio_rmdir(struct inode *dir, struct path *path); ++int vfsub_sio_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode); ++int vfsub_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode); ++int vfsub_unlink(struct inode *dir, struct path *path, ++ struct inode **delegated_inode, int force); ++ ++static inline int vfsub_getattr(const struct path *path, struct kstat *st) ++{ ++ return vfs_getattr(path, st, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int vfsub_setxattr(struct user_namespace *userns, ++ struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = vfs_setxattr(userns, dentry, name, value, size, flags); ++ lockdep_on(); ++ ++ return err; ++} ++ ++static inline int vfsub_removexattr(struct user_namespace *userns, ++ struct dentry *dentry, const char *name) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = vfs_removexattr(userns, dentry, name); ++ lockdep_on(); ++ ++ return err; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_VFSUB_H__ */ +diff -Naur null/fs/aufs/wbr_policy.c linux-5.15.36/fs/aufs/wbr_policy.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/wbr_policy.c 2022-05-10 16:51:39.877744219 +0300 +@@ -0,0 +1,830 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * policies for selecting one among multiple writable branches ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* subset of cpup_attr() */ ++static noinline_for_stack ++int au_cpdown_attr(struct path *h_path, struct dentry *h_src) ++{ ++ int err, sbits; ++ struct iattr ia; ++ struct inode *h_isrc; ++ ++ h_isrc = d_inode(h_src); ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID; ++ ia.ia_mode = h_isrc->i_mode; ++ ia.ia_uid = h_isrc->i_uid; ++ ia.ia_gid = h_isrc->i_gid; ++ sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(d_inode(h_path->dentry), h_isrc->i_flags); ++ /* no delegation since it is just created */ ++ err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL); ++ ++ /* is this nfs only? */ ++ if (!err && sbits && au_test_nfs(h_path->dentry->d_sb)) { ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL); ++ } ++ ++ return err; ++} ++ ++#define AuCpdown_PARENT_OPQ 1 ++#define AuCpdown_WHED (1 << 1) ++#define AuCpdown_MADE_DIR (1 << 2) ++#define AuCpdown_DIROPQ (1 << 3) ++#define au_ftest_cpdown(flags, name) ((flags) & AuCpdown_##name) ++#define au_fset_cpdown(flags, name) \ ++ do { (flags) |= AuCpdown_##name; } while (0) ++#define au_fclr_cpdown(flags, name) \ ++ do { (flags) &= ~AuCpdown_##name; } while (0) ++ ++static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst, ++ unsigned int *flags) ++{ ++ int err; ++ struct dentry *opq_dentry; ++ ++ opq_dentry = au_diropq_create(dentry, bdst); ++ err = PTR_ERR(opq_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out; ++ dput(opq_dentry); ++ au_fset_cpdown(*flags, DIROPQ); ++ ++out: ++ return err; ++} ++ ++static int au_cpdown_dir_wh(struct dentry *dentry, struct dentry *h_parent, ++ struct inode *dir, aufs_bindex_t bdst) ++{ ++ int err; ++ struct path h_path; ++ struct au_branch *br; ++ ++ br = au_sbr(dentry->d_sb, bdst); ++ h_path.dentry = au_wh_lkup(h_parent, &dentry->d_name, br); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ err = 0; ++ if (d_is_positive(h_path.dentry)) { ++ h_path.mnt = au_br_mnt(br); ++ err = au_wh_unlink_dentry(au_h_iptr(dir, bdst), &h_path, ++ dentry); ++ } ++ dput(h_path.dentry); ++ ++out: ++ return err; ++} ++ ++static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg) ++{ ++ int err, rerr; ++ aufs_bindex_t bopq, btop; ++ struct path h_path; ++ struct dentry *parent; ++ struct inode *h_dir, *h_inode, *inode, *dir; ++ unsigned int *flags = arg; ++ ++ btop = au_dbtop(dentry); ++ /* dentry is di-locked */ ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ h_dir = d_inode(h_parent); ++ AuDebugOn(h_dir != au_h_iptr(dir, bdst)); ++ IMustLock(h_dir); ++ ++ err = au_lkup_neg(dentry, bdst, /*wh*/0); ++ if (unlikely(err < 0)) ++ 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, 0755); ++ if (unlikely(err)) ++ goto out_put; ++ au_fset_cpdown(*flags, MADE_DIR); ++ ++ bopq = au_dbdiropq(dentry); ++ au_fclr_cpdown(*flags, WHED); ++ au_fclr_cpdown(*flags, DIROPQ); ++ if (au_dbwh(dentry) == bdst) ++ au_fset_cpdown(*flags, WHED); ++ if (!au_ftest_cpdown(*flags, PARENT_OPQ) && bopq <= bdst) ++ au_fset_cpdown(*flags, PARENT_OPQ); ++ h_inode = d_inode(h_path.dentry); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ if (au_ftest_cpdown(*flags, WHED)) { ++ err = au_cpdown_dir_opq(dentry, bdst, flags); ++ if (unlikely(err)) { ++ inode_unlock(h_inode); ++ goto out_dir; ++ } ++ } ++ ++ err = au_cpdown_attr(&h_path, au_h_dptr(dentry, btop)); ++ inode_unlock(h_inode); ++ if (unlikely(err)) ++ goto out_opq; ++ ++ if (au_ftest_cpdown(*flags, WHED)) { ++ err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst); ++ if (unlikely(err)) ++ goto out_opq; ++ } ++ ++ inode = d_inode(dentry); ++ if (au_ibbot(inode) < bdst) ++ au_set_ibbot(inode, bdst); ++ au_set_h_iptr(inode, bdst, au_igrab(h_inode), ++ au_hi_flags(inode, /*isdir*/1)); ++ au_fhsm_wrote(dentry->d_sb, bdst, /*force*/0); ++ goto out; /* success */ ++ ++ /* revert */ ++out_opq: ++ if (au_ftest_cpdown(*flags, DIROPQ)) { ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(dentry, bdst); ++ inode_unlock(h_inode); ++ if (unlikely(rerr)) { ++ AuIOErr("failed removing diropq for %pd b%d (%d)\n", ++ dentry, bdst, rerr); ++ err = -EIO; ++ goto out; ++ } ++ } ++out_dir: ++ if (au_ftest_cpdown(*flags, MADE_DIR)) { ++ rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path); ++ if (unlikely(rerr)) { ++ AuIOErr("failed removing %pd b%d (%d)\n", ++ dentry, bdst, rerr); ++ err = -EIO; ++ } ++ } ++out_put: ++ au_set_h_dptr(dentry, bdst, NULL); ++ if (au_dbbot(dentry) == bdst) ++ au_update_dbbot(dentry); ++out: ++ dput(parent); ++ return err; ++} ++ ++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ int err; ++ unsigned int flags; ++ ++ flags = 0; ++ err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &flags); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies for create */ ++ ++int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err, i, j, ndentry; ++ aufs_bindex_t bopq; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries, *parent, *d; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ parent = dget_parent(dentry); ++ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0); ++ if (unlikely(err)) ++ goto out_free; ++ ++ err = bindex; ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ d = dentries[j]; ++ di_read_lock_parent2(d, !AuLock_IR); ++ bopq = au_dbdiropq(d); ++ di_read_unlock(d, !AuLock_IR); ++ if (bopq >= 0 && bopq < err) ++ err = bopq; ++ } ++ } ++ ++out_free: ++ dput(parent); ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ for (; bindex >= 0; bindex--) ++ if (!au_br_rdonly(au_sbr(sb, bindex))) ++ return bindex; ++ return -EROFS; ++} ++ ++/* top down parent */ ++static int au_wbr_create_tdp(struct dentry *dentry, ++ unsigned int flags __maybe_unused) ++{ ++ int err; ++ aufs_bindex_t btop, bindex; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ err = btop; ++ if (!au_br_rdonly(au_sbr(sb, btop))) ++ goto out; ++ ++ err = -EROFS; ++ parent = dget_parent(dentry); ++ for (bindex = au_dbtop(parent); bindex < btop; bindex++) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = bindex; ++ break; ++ } ++ } ++ dput(parent); ++ ++ /* bottom up here */ ++ if (unlikely(err < 0)) { ++ err = au_wbr_bu(sb, btop - 1); ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ } ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* an exception for the policy other than tdp */ ++static int au_wbr_create_exp(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bwh, bdiropq; ++ struct dentry *parent; ++ ++ err = -1; ++ bwh = au_dbwh(dentry); ++ parent = dget_parent(dentry); ++ bdiropq = au_dbdiropq(parent); ++ if (bwh >= 0) { ++ if (bdiropq >= 0) ++ err = min(bdiropq, bwh); ++ else ++ err = bwh; ++ AuDbg("%d\n", err); ++ } else if (bdiropq >= 0) { ++ err = bdiropq; ++ AuDbg("%d\n", err); ++ } ++ dput(parent); ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++ if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err))) ++ err = -1; ++ ++ AuDbg("%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* round robin */ ++static int au_wbr_create_init_rr(struct super_block *sb) ++{ ++ int err; ++ ++ err = au_wbr_bu(sb, au_sbbot(sb)); ++ atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */ ++ /* smp_mb(); */ ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_rr(struct dentry *dentry, unsigned int flags) ++{ ++ int err, nbr; ++ unsigned int u; ++ aufs_bindex_t bindex, bbot; ++ struct super_block *sb; ++ atomic_t *next; ++ ++ err = au_wbr_create_exp(dentry); ++ if (err >= 0) ++ goto out; ++ ++ sb = dentry->d_sb; ++ next = &au_sbi(sb)->si_wbr_rr_next; ++ bbot = au_sbbot(sb); ++ nbr = bbot + 1; ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ if (!au_ftest_wbr(flags, DIR)) { ++ err = atomic_dec_return(next) + 1; ++ /* modulo for 0 is meaningless */ ++ if (unlikely(!err)) ++ err = atomic_dec_return(next) + 1; ++ } else ++ err = atomic_read(next); ++ AuDbg("%d\n", err); ++ u = err; ++ err = u % nbr; ++ AuDbg("%d\n", err); ++ if (!au_br_rdonly(au_sbr(sb, err))) ++ break; ++ err = -EROFS; ++ } ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out: ++ AuDbg("%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* most free space */ ++static void au_mfs(struct dentry *dentry, struct dentry *parent) ++{ ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_wbr_mfs *mfs; ++ struct dentry *h_parent; ++ aufs_bindex_t bindex, bbot; ++ int err; ++ unsigned long long b, bavail; ++ struct path h_path; ++ /* reduce the stack usage */ ++ struct kstatfs *st; ++ ++ st = kmalloc(sizeof(*st), GFP_NOFS); ++ if (unlikely(!st)) { ++ AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM); ++ return; ++ } ++ ++ bavail = 0; ++ sb = dentry->d_sb; ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ MtxMustLock(&mfs->mfs_lock); ++ mfs->mfs_bindex = -EROFS; ++ mfs->mfsrr_bytes = 0; ++ if (!parent) { ++ bindex = 0; ++ bbot = au_sbbot(sb); ++ } else { ++ bindex = au_dbtop(parent); ++ bbot = au_dbtaildir(parent); ++ } ++ ++ for (; bindex <= bbot; bindex++) { ++ if (parent) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ } ++ br = au_sbr(sb, bindex); ++ if (au_br_rdonly(br)) ++ continue; ++ ++ /* sb->s_root for NFS is unreliable */ ++ h_path.mnt = au_br_mnt(br); ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, st); ++ if (unlikely(err)) { ++ AuWarn1("failed statfs, b%d, %d\n", bindex, err); ++ continue; ++ } ++ ++ /* when the available size is equal, select the lower one */ ++ BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail) ++ || sizeof(b) < sizeof(st->f_bsize)); ++ b = st->f_bavail * st->f_bsize; ++ br->br_wbr->wbr_bytes = b; ++ if (b >= bavail) { ++ bavail = b; ++ mfs->mfs_bindex = bindex; ++ mfs->mfs_jiffy = jiffies; ++ } ++ } ++ ++ mfs->mfsrr_bytes = bavail; ++ AuDbg("b%d\n", mfs->mfs_bindex); ++ au_kfree_rcu(st); ++} ++ ++static int au_wbr_create_mfs(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ struct dentry *parent; ++ struct super_block *sb; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_exp(dentry); ++ if (err >= 0) ++ goto out; ++ ++ sb = dentry->d_sb; ++ parent = NULL; ++ if (au_ftest_wbr(flags, PARENT)) ++ parent = dget_parent(dentry); ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) ++ || mfs->mfs_bindex < 0 ++ || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex))) ++ au_mfs(dentry, parent); ++ mutex_unlock(&mfs->mfs_lock); ++ err = mfs->mfs_bindex; ++ dput(parent); ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_init_mfs(struct super_block *sb) ++{ ++ struct au_wbr_mfs *mfs; ++ ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_init(&mfs->mfs_lock); ++ mfs->mfs_jiffy = 0; ++ mfs->mfs_bindex = -EROFS; ++ ++ return 0; ++} ++ ++static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused) ++{ ++ mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* top down regardless parent, and then mfs */ ++static int au_wbr_create_tdmfs(struct dentry *dentry, ++ unsigned int flags __maybe_unused) ++{ ++ int err; ++ aufs_bindex_t bwh, btail, bindex, bfound, bmfs; ++ unsigned long long watermark; ++ struct super_block *sb; ++ struct au_wbr_mfs *mfs; ++ struct au_branch *br; ++ struct dentry *parent; ++ ++ sb = dentry->d_sb; ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) ++ || mfs->mfs_bindex < 0) ++ au_mfs(dentry, /*parent*/NULL); ++ watermark = mfs->mfsrr_watermark; ++ bmfs = mfs->mfs_bindex; ++ mutex_unlock(&mfs->mfs_lock); ++ ++ /* another style of au_wbr_create_exp() */ ++ bwh = au_dbwh(dentry); ++ parent = dget_parent(dentry); ++ btail = au_dbtaildir(parent); ++ if (bwh >= 0 && bwh < btail) ++ btail = bwh; ++ ++ err = au_wbr_nonopq(dentry, btail); ++ if (unlikely(err < 0)) ++ goto out; ++ btail = err; ++ bfound = -1; ++ for (bindex = 0; bindex <= btail; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_rdonly(br)) ++ continue; ++ if (br->br_wbr->wbr_bytes > watermark) { ++ bfound = bindex; ++ break; ++ } ++ } ++ err = bfound; ++ if (err < 0) ++ err = bmfs; ++ ++out: ++ dput(parent); ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* most free space and then round robin */ ++static int au_wbr_create_mfsrr(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_mfs(dentry, flags); ++ if (err >= 0) { ++ mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (mfs->mfsrr_bytes < mfs->mfsrr_watermark) ++ err = au_wbr_create_rr(dentry, flags); ++ mutex_unlock(&mfs->mfs_lock); ++ } ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_init_mfsrr(struct super_block *sb) ++{ ++ int err; ++ ++ au_wbr_create_init_mfs(sb); /* ignore */ ++ err = au_wbr_create_init_rr(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* top down parent and most free space */ ++static int au_wbr_create_pmfs(struct dentry *dentry, unsigned int flags) ++{ ++ int err, e2; ++ unsigned long long b; ++ aufs_bindex_t bindex, btop, bbot; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent; ++ struct au_branch *br; ++ ++ err = au_wbr_create_tdp(dentry, flags); ++ if (unlikely(err < 0)) ++ goto out; ++ parent = dget_parent(dentry); ++ btop = au_dbtop(parent); ++ bbot = au_dbtaildir(parent); ++ if (btop == bbot) ++ goto out_parent; /* success */ ++ ++ e2 = au_wbr_create_mfs(dentry, flags); ++ if (e2 < 0) ++ goto out_parent; /* success */ ++ ++ /* when the available size is equal, select upper one */ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, err); ++ b = br->br_wbr->wbr_bytes; ++ AuDbg("b%d, %llu\n", err, b); ++ ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ ++ br = au_sbr(sb, bindex); ++ if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) { ++ b = br->br_wbr->wbr_bytes; ++ err = bindex; ++ AuDbg("b%d, %llu\n", err, b); ++ } ++ } ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out_parent: ++ dput(parent); ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * - top down parent ++ * - most free space with parent ++ * - most free space round-robin regardless parent ++ */ ++static int au_wbr_create_pmfsrr(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ unsigned long long watermark; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_pmfs(dentry, flags | AuWbr_PARENT); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, err); ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ watermark = mfs->mfsrr_watermark; ++ mutex_unlock(&mfs->mfs_lock); ++ if (br->br_wbr->wbr_bytes < watermark) ++ /* regardless the parent dir */ ++ err = au_wbr_create_mfsrr(dentry, flags); ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies for copyup */ ++ ++/* top down parent */ ++static int au_wbr_copyup_tdp(struct dentry *dentry) ++{ ++ return au_wbr_create_tdp(dentry, /*flags, anything is ok*/0); ++} ++ ++/* bottom up parent */ ++static int au_wbr_copyup_bup(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bindex, btop; ++ struct dentry *parent, *h_parent; ++ struct super_block *sb; ++ ++ err = -EROFS; ++ sb = dentry->d_sb; ++ parent = dget_parent(dentry); ++ btop = au_dbtop(parent); ++ for (bindex = au_dbtop(dentry); bindex >= btop; bindex--) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = bindex; ++ break; ++ } ++ } ++ dput(parent); ++ ++ /* bottom up here */ ++ if (unlikely(err < 0)) ++ err = au_wbr_bu(sb, btop - 1); ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* bottom up */ ++int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t btop) ++{ ++ int err; ++ ++ err = au_wbr_bu(dentry->d_sb, btop); ++ AuDbg("b%d\n", err); ++ if (err > btop) ++ err = au_wbr_nonopq(dentry, err); ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_copyup_bu(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t btop; ++ ++ btop = au_dbtop(dentry); ++ err = au_wbr_do_copyup_bu(dentry, btop); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_wbr_copyup_operations au_wbr_copyup_ops[] = { ++ [AuWbrCopyup_TDP] = { ++ .copyup = au_wbr_copyup_tdp ++ }, ++ [AuWbrCopyup_BUP] = { ++ .copyup = au_wbr_copyup_bup ++ }, ++ [AuWbrCopyup_BU] = { ++ .copyup = au_wbr_copyup_bu ++ } ++}; ++ ++struct au_wbr_create_operations au_wbr_create_ops[] = { ++ [AuWbrCreate_TDP] = { ++ .create = au_wbr_create_tdp ++ }, ++ [AuWbrCreate_RR] = { ++ .create = au_wbr_create_rr, ++ .init = au_wbr_create_init_rr ++ }, ++ [AuWbrCreate_MFS] = { ++ .create = au_wbr_create_mfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSV] = { ++ .create = au_wbr_create_mfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSRR] = { ++ .create = au_wbr_create_mfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSRRV] = { ++ .create = au_wbr_create_mfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_TDMFS] = { ++ .create = au_wbr_create_tdmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_TDMFSV] = { ++ .create = au_wbr_create_tdmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFS] = { ++ .create = au_wbr_create_pmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSV] = { ++ .create = au_wbr_create_pmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSRR] = { ++ .create = au_wbr_create_pmfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSRRV] = { ++ .create = au_wbr_create_pmfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ } ++}; +diff -Naur null/fs/aufs/whout.c linux-5.15.36/fs/aufs/whout.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/whout.c 2022-05-10 16:51:39.878744219 +0300 +@@ -0,0 +1,1072 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * whiteout for logical deletion and opaque directory ++ */ ++ ++#include "aufs.h" ++ ++#define WH_MASK 0444 ++ ++/* ++ * If a directory contains this file, then it is opaque. We start with the ++ * .wh. flag so that it is blocked by lookup. ++ */ ++static struct qstr diropq_name = QSTR_INIT(AUFS_WH_DIROPQ, ++ sizeof(AUFS_WH_DIROPQ) - 1); ++ ++/* ++ * generate whiteout name, which is NOT terminated by NULL. ++ * @name: original d_name.name ++ * @len: original d_name.len ++ * @wh: whiteout qstr ++ * returns zero when succeeds, otherwise error. ++ * succeeded value as wh->name should be freed by kfree(). ++ */ ++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name) ++{ ++ char *p; ++ ++ if (unlikely(name->len > PATH_MAX - AUFS_WH_PFX_LEN)) ++ return -ENAMETOOLONG; ++ ++ wh->len = name->len + AUFS_WH_PFX_LEN; ++ p = kmalloc(wh->len, GFP_NOFS); ++ wh->name = p; ++ if (p) { ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ memcpy(p + AUFS_WH_PFX_LEN, name->name, name->len); ++ /* smp_mb(); */ ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if the @wh_name exists under @h_ppath. ++ * @try_sio specifies the necessary of super-io. ++ */ ++int au_wh_test(struct user_namespace *h_userns, struct path *h_ppath, ++ struct qstr *wh_name, int try_sio) ++{ ++ int err; ++ struct dentry *wh_dentry; ++ ++ if (!try_sio) ++ wh_dentry = vfsub_lkup_one(wh_name, h_ppath); ++ else ++ wh_dentry = au_sio_lkup_one(h_userns, wh_name, h_ppath); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) { ++ if (err == -ENAMETOOLONG) ++ err = 0; ++ goto out; ++ } ++ ++ err = 0; ++ if (d_is_negative(wh_dentry)) ++ goto out_wh; /* success */ ++ ++ err = 1; ++ if (d_is_reg(wh_dentry)) ++ goto out_wh; /* success */ ++ ++ err = -EIO; ++ AuIOErr("%pd Invalid whiteout entry type 0%o.\n", ++ wh_dentry, d_inode(wh_dentry)->i_mode); ++ ++out_wh: ++ dput(wh_dentry); ++out: ++ return err; ++} ++ ++/* ++ * test if the @h_path->dentry sets opaque or not. ++ */ ++int au_diropq_test(struct user_namespace *h_userns, struct path *h_path) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ h_dir = d_inode(h_path->dentry); ++ err = au_wh_test(h_userns, h_path, &diropq_name, ++ au_test_h_perm_sio(h_userns, h_dir, MAY_EXEC)); ++ return err; ++} ++ ++/* ++ * returns a negative dentry whose name is unique and temporary. ++ */ ++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, ++ struct qstr *prefix) ++{ ++ struct dentry *dentry; ++ int i; ++ char defname[NAME_MAX - AUFS_MAX_NAMELEN + DNAME_INLINE_LEN + 1], ++ *name, *p; ++ /* strict atomic_t is unnecessary here */ ++ static unsigned short cnt; ++ struct qstr qs; ++ struct path h_ppath; ++ struct user_namespace *h_userns; ++ ++ BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN); ++ ++ name = defname; ++ qs.len = sizeof(defname) - DNAME_INLINE_LEN + prefix->len - 1; ++ if (unlikely(prefix->len > DNAME_INLINE_LEN)) { ++ dentry = ERR_PTR(-ENAMETOOLONG); ++ if (unlikely(qs.len > NAME_MAX)) ++ goto out; ++ dentry = ERR_PTR(-ENOMEM); ++ name = kmalloc(qs.len + 1, GFP_NOFS); ++ if (unlikely(!name)) ++ goto out; ++ } ++ ++ /* doubly whiteout-ed */ ++ memcpy(name, AUFS_WH_PFX AUFS_WH_PFX, AUFS_WH_PFX_LEN * 2); ++ p = name + AUFS_WH_PFX_LEN * 2; ++ memcpy(p, prefix->name, prefix->len); ++ p += prefix->len; ++ *p++ = '.'; ++ AuDebugOn(name + qs.len + 1 - p <= AUFS_WH_TMP_LEN); ++ ++ h_ppath.dentry = h_parent; ++ h_ppath.mnt = au_br_mnt(br); ++ h_userns = au_br_userns(br); ++ qs.name = name; ++ for (i = 0; i < 3; i++) { ++ sprintf(p, "%.*x", AUFS_WH_TMP_LEN, cnt++); ++ dentry = au_sio_lkup_one(h_userns, &qs, &h_ppath); ++ if (IS_ERR(dentry) || d_is_negative(dentry)) ++ goto out_name; ++ dput(dentry); ++ } ++ /* pr_warn("could not get random name\n"); */ ++ dentry = ERR_PTR(-EEXIST); ++ AuDbg("%.*s\n", AuLNPair(&qs)); ++ BUG(); ++ ++out_name: ++ if (name != defname) ++ au_kfree_try_rcu(name); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ++ * rename the @h_dentry on @br to the whiteouted temporary name. ++ */ ++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br) ++{ ++ int err; ++ struct path h_path = { ++ .mnt = au_br_mnt(br) ++ }; ++ struct inode *h_dir, *delegated; ++ struct dentry *h_parent; ++ ++ h_parent = h_dentry->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ h_path.dentry = au_whtmp_lkup(h_parent, br, &h_dentry->d_name); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ /* under the same dir, no need to lock_rename() */ ++ delegated = NULL; ++ err = vfsub_rename(h_dir, h_dentry, h_dir, &h_path, &delegated, ++ /*flags*/0); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ dput(h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * functions for removing a whiteout ++ */ ++ ++static int do_unlink_wh(struct inode *h_dir, struct path *h_path) ++{ ++ int err, force; ++ struct inode *delegated; ++ ++ /* ++ * forces superio when the dir has a sticky bit. ++ * this may be a violation of unix fs semantics. ++ */ ++ force = (h_dir->i_mode & S_ISVTX) ++ && !uid_eq(current_fsuid(), d_inode(h_path->dentry)->i_uid); ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, h_path, &delegated, force); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ return err; ++} ++ ++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, ++ struct dentry *dentry) ++{ ++ int err; ++ ++ err = do_unlink_wh(h_dir, h_path); ++ if (!err && dentry) ++ au_set_dbwh(dentry, -1); ++ ++ return err; ++} ++ ++static int unlink_wh_name(struct path *h_ppath, struct qstr *wh) ++{ ++ int err; ++ struct path h_path; ++ ++ err = 0; ++ h_path.dentry = vfsub_lkup_one(wh, h_ppath); ++ if (IS_ERR(h_path.dentry)) ++ err = PTR_ERR(h_path.dentry); ++ else { ++ if (d_is_reg(h_path.dentry)) { ++ h_path.mnt = h_ppath->mnt; ++ err = do_unlink_wh(d_inode(h_ppath->dentry), &h_path); ++ } ++ dput(h_path.dentry); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * initialize/clean whiteout for a branch ++ */ ++ ++static void au_wh_clean(struct inode *h_dir, struct path *whpath, ++ const int isdir) ++{ ++ int err; ++ struct inode *delegated; ++ ++ if (d_is_negative(whpath->dentry)) ++ return; ++ ++ if (isdir) ++ err = vfsub_rmdir(h_dir, whpath); ++ else { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, whpath, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } ++ if (unlikely(err)) ++ pr_warn("failed removing %pd (%d), ignored.\n", ++ whpath->dentry, err); ++} ++ ++static int test_linkable(struct dentry *h_root) ++{ ++ struct inode *h_dir = d_inode(h_root); ++ ++ if (h_dir->i_op->link) ++ return 0; ++ ++ pr_err("%pd (%s) doesn't support link(2), use noplink and rw+nolwh\n", ++ h_root, au_sbtype(h_root->d_sb)); ++ return -ENOSYS; /* the branch doesn't have its ->link() */ ++} ++ ++/* todo: should this mkdir be done in /sbin/mount.aufs helper? */ ++static int au_whdir(struct inode *h_dir, struct path *path) ++{ ++ int err; ++ ++ err = -EEXIST; ++ if (d_is_negative(path->dentry)) { ++ int mode = 0700; ++ ++ if (au_test_nfs(path->dentry->d_sb)) ++ mode |= 0111; ++ err = vfsub_mkdir(h_dir, path, mode); ++ } else if (d_is_dir(path->dentry)) ++ err = 0; ++ else ++ pr_err("unknown %pd exists\n", path->dentry); ++ ++ return err; ++} ++ ++struct au_wh_base { ++ const struct qstr *name; ++ struct dentry *dentry; ++}; ++ ++static void au_wh_init_ro(struct inode *h_dir, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/0); ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++} ++ ++/* ++ * returns tri-state, ++ * minus: error, caller should print the message ++ * 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, ++ int do_plink, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ h_dir = d_inode(h_root); ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/0); ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ if (do_plink) { ++ err = test_linkable(h_root); ++ if (unlikely(err)) { ++ err = 1; ++ goto out; ++ } ++ ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); ++ } else ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * for the moment, aufs supports the branch filesystem which does not support ++ * link(2). testing on FAT which does not support i_op->setattr() fully either, ++ * copyup failed. finally, such filesystem will not be used as the writable ++ * branch. ++ * ++ * returns tri-state, see above. ++ */ ++static int au_wh_init_rw(struct dentry *h_root, struct au_wbr *wbr, ++ int do_plink, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ WbrWhMustWriteLock(wbr); ++ ++ err = test_linkable(h_root); ++ if (unlikely(err)) { ++ err = 1; ++ goto out; ++ } ++ ++ /* ++ * todo: should this create be done in /sbin/mount.aufs helper? ++ */ ++ err = -EEXIST; ++ h_dir = d_inode(h_root); ++ if (d_is_negative(base[AuBrWh_BASE].dentry)) { ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ err = vfsub_create(h_dir, h_path, WH_MASK, /*want_excl*/true); ++ } else if (d_is_reg(base[AuBrWh_BASE].dentry)) ++ err = 0; ++ else ++ pr_err("unknown %pd2 exists\n", base[AuBrWh_BASE].dentry); ++ if (unlikely(err)) ++ goto out; ++ ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ if (do_plink) { ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); ++ } else ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ wbr->wbr_whbase = dget(base[AuBrWh_BASE].dentry); ++ ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * initialize the whiteout base file/dir for @br. ++ */ ++int au_wh_init(struct au_branch *br, struct super_block *sb) ++{ ++ int err, i; ++ const unsigned char do_plink ++ = !!au_opt_test(au_mntflags(sb), PLINK); ++ struct inode *h_dir; ++ struct path path = br->br_path; ++ struct dentry *h_root = path.dentry; ++ struct au_wbr *wbr = br->br_wbr; ++ static const struct qstr base_name[] = { ++ [AuBrWh_BASE] = QSTR_INIT(AUFS_BASE_NAME, ++ sizeof(AUFS_BASE_NAME) - 1), ++ [AuBrWh_PLINK] = QSTR_INIT(AUFS_PLINKDIR_NAME, ++ sizeof(AUFS_PLINKDIR_NAME) - 1), ++ [AuBrWh_ORPH] = QSTR_INIT(AUFS_ORPHDIR_NAME, ++ sizeof(AUFS_ORPHDIR_NAME) - 1) ++ }; ++ struct au_wh_base base[] = { ++ [AuBrWh_BASE] = { ++ .name = base_name + AuBrWh_BASE, ++ .dentry = NULL ++ }, ++ [AuBrWh_PLINK] = { ++ .name = base_name + AuBrWh_PLINK, ++ .dentry = NULL ++ }, ++ [AuBrWh_ORPH] = { ++ .name = base_name + AuBrWh_ORPH, ++ .dentry = NULL ++ } ++ }; ++ ++ if (wbr) ++ WbrWhMustWriteLock(wbr); ++ ++ for (i = 0; i < AuBrWh_Last; i++) { ++ /* doubly whiteouted */ ++ struct dentry *d; ++ ++ d = au_wh_lkup(h_root, (void *)base[i].name, br); ++ err = PTR_ERR(d); ++ if (IS_ERR(d)) ++ goto out; ++ ++ base[i].dentry = d; ++ AuDebugOn(wbr ++ && wbr->wbr_wh[i] ++ && wbr->wbr_wh[i] != base[i].dentry); ++ } ++ ++ if (wbr) ++ for (i = 0; i < AuBrWh_Last; i++) { ++ dput(wbr->wbr_wh[i]); ++ wbr->wbr_wh[i] = NULL; ++ } ++ ++ err = 0; ++ if (!au_br_writable(br->br_perm)) { ++ h_dir = d_inode(h_root); ++ au_wh_init_ro(h_dir, base, &path); ++ } else if (!au_br_wh_linkable(br->br_perm)) { ++ err = au_wh_init_rw_nolink(h_root, wbr, do_plink, base, &path); ++ if (err > 0) ++ goto out; ++ else if (err) ++ goto out_err; ++ } else { ++ err = au_wh_init_rw(h_root, wbr, do_plink, base, &path); ++ if (err > 0) ++ goto out; ++ else if (err) ++ goto out_err; ++ } ++ goto out; /* success */ ++ ++out_err: ++ pr_err("an error(%d) on the writable branch %pd(%s)\n", ++ err, h_root, au_sbtype(h_root->d_sb)); ++out: ++ for (i = 0; i < AuBrWh_Last; i++) ++ dput(base[i].dentry); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * whiteouts are all hard-linked usually. ++ * when its link count reaches a ceiling, we create a new whiteout base ++ * asynchronously. ++ */ ++ ++struct reinit_br_wh { ++ struct super_block *sb; ++ struct au_branch *br; ++}; ++ ++static void reinit_br_wh(void *arg) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct path h_path; ++ struct reinit_br_wh *a = arg; ++ struct au_wbr *wbr; ++ struct inode *dir, *delegated; ++ struct dentry *h_root; ++ struct au_hinode *hdir; ++ ++ err = 0; ++ wbr = a->br->br_wbr; ++ /* big aufs lock */ ++ si_noflush_write_lock(a->sb); ++ if (!au_br_writable(a->br->br_perm)) ++ goto out; ++ bindex = au_br_index(a->sb, a->br->br_id); ++ if (unlikely(bindex < 0)) ++ goto out; ++ ++ di_read_lock_parent(a->sb->s_root, AuLock_IR); ++ dir = d_inode(a->sb->s_root); ++ hdir = au_hi(dir, bindex); ++ h_root = au_h_dptr(a->sb->s_root, bindex); ++ AuDebugOn(h_root != au_br_dentry(a->br)); ++ ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ wbr_wh_write_lock(wbr); ++ err = au_h_verify(wbr->wbr_whbase, au_opt_udba(a->sb), hdir->hi_inode, ++ h_root, a->br); ++ if (!err) { ++ h_path.dentry = wbr->wbr_whbase; ++ h_path.mnt = au_br_mnt(a->br); ++ delegated = NULL; ++ err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, ++ /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } else { ++ pr_warn("%pd is moved, ignored\n", wbr->wbr_whbase); ++ err = 0; ++ } ++ dput(wbr->wbr_whbase); ++ wbr->wbr_whbase = NULL; ++ if (!err) ++ err = au_wh_init(a->br, a->sb); ++ wbr_wh_write_unlock(wbr); ++ au_hn_inode_unlock(hdir); ++ di_read_unlock(a->sb->s_root, AuLock_IR); ++ if (!err) ++ au_fhsm_wrote(a->sb, bindex, /*force*/0); ++ ++out: ++ if (wbr) ++ atomic_dec(&wbr->wbr_wh_running); ++ au_lcnt_dec(&a->br->br_count); ++ si_write_unlock(a->sb); ++ au_nwt_done(&au_sbi(a->sb)->si_nowait); ++ au_kfree_rcu(a); ++ if (unlikely(err)) ++ AuIOErr("err %d\n", err); ++} ++ ++static void kick_reinit_br_wh(struct super_block *sb, struct au_branch *br) ++{ ++ int do_dec, wkq_err; ++ struct reinit_br_wh *arg; ++ ++ do_dec = 1; ++ if (atomic_inc_return(&br->br_wbr->wbr_wh_running) != 1) ++ goto out; ++ ++ /* ignore ENOMEM */ ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (arg) { ++ /* ++ * dec(wh_running), kfree(arg) and dec(br_count) ++ * in reinit function ++ */ ++ arg->sb = sb; ++ arg->br = 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_lcnt_dec(&br->br_count); ++ au_kfree_rcu(arg); ++ } ++ do_dec = 0; ++ } ++ ++out: ++ if (do_dec) ++ atomic_dec(&br->br_wbr->wbr_wh_running); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create the whiteout @wh. ++ */ ++static int link_or_create_wh(struct super_block *sb, aufs_bindex_t bindex, ++ struct dentry *wh) ++{ ++ int err; ++ struct path h_path = { ++ .dentry = wh ++ }; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *h_parent; ++ struct inode *h_dir, *delegated; ++ ++ h_parent = wh->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ br = au_sbr(sb, bindex); ++ h_path.mnt = au_br_mnt(br); ++ wbr = br->br_wbr; ++ wbr_wh_read_lock(wbr); ++ if (wbr->wbr_whbase) { ++ delegated = NULL; ++ err = vfsub_link(wbr->wbr_whbase, h_dir, &h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ if (!err || err != -EMLINK) ++ goto out; ++ ++ /* link count full. re-initialize br_whbase. */ ++ kick_reinit_br_wh(sb, br); ++ } ++ ++ /* return this error in this context */ ++ err = vfsub_create(h_dir, &h_path, WH_MASK, /*want_excl*/true); ++ if (!err) ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ ++out: ++ wbr_wh_read_unlock(wbr); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create or remove the diropq. ++ */ ++static struct dentry *do_diropq(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags) ++{ ++ struct dentry *opq_dentry; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct path h_path; ++ int err; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bindex); ++ h_path.dentry = au_h_dptr(dentry, bindex); ++ h_path.mnt = au_br_mnt(br); ++ opq_dentry = vfsub_lkup_one(&diropq_name, &h_path); ++ if (IS_ERR(opq_dentry)) ++ goto out; ++ ++ if (au_ftest_diropq(flags, CREATE)) { ++ err = link_or_create_wh(sb, bindex, opq_dentry); ++ if (!err) { ++ au_set_dbdiropq(dentry, bindex); ++ goto out; /* success */ ++ } ++ } else { ++ h_path.dentry = opq_dentry; ++ err = do_unlink_wh(au_h_iptr(d_inode(dentry), bindex), &h_path); ++ if (!err) ++ au_set_dbdiropq(dentry, -1); ++ } ++ dput(opq_dentry); ++ opq_dentry = ERR_PTR(err); ++ ++out: ++ return opq_dentry; ++} ++ ++struct do_diropq_args { ++ struct dentry **errp; ++ struct dentry *dentry; ++ aufs_bindex_t bindex; ++ unsigned int flags; ++}; ++ ++static void call_do_diropq(void *args) ++{ ++ struct do_diropq_args *a = args; ++ *a->errp = do_diropq(a->dentry, a->bindex, a->flags); ++} ++ ++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags) ++{ ++ struct dentry *diropq, *h_dentry; ++ struct user_namespace *h_userns; ++ ++ h_userns = au_sbr_userns(dentry->d_sb, bindex); ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!au_test_h_perm_sio(h_userns, d_inode(h_dentry), ++ MAY_EXEC | MAY_WRITE)) ++ diropq = do_diropq(dentry, bindex, flags); ++ else { ++ int wkq_err; ++ struct do_diropq_args args = { ++ .errp = &diropq, ++ .dentry = dentry, ++ .bindex = bindex, ++ .flags = flags ++ }; ++ ++ wkq_err = au_wkq_wait(call_do_diropq, &args); ++ if (unlikely(wkq_err)) ++ diropq = ERR_PTR(wkq_err); ++ } ++ ++ return diropq; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * lookup whiteout dentry. ++ * @h_parent: lower parent dentry which must exist and be locked ++ * @base_name: name of dentry which will be whiteouted ++ * returns dentry for whiteout. ++ */ ++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, ++ struct au_branch *br) ++{ ++ int err; ++ struct qstr wh_name; ++ struct dentry *wh_dentry; ++ struct path h_path; ++ ++ err = au_wh_name_alloc(&wh_name, base_name); ++ wh_dentry = ERR_PTR(err); ++ if (!err) { ++ h_path.dentry = h_parent; ++ h_path.mnt = au_br_mnt(br); ++ wh_dentry = vfsub_lkup_one(&wh_name, &h_path); ++ au_kfree_try_rcu(wh_name.name); ++ } ++ return wh_dentry; ++} ++ ++/* ++ * link/create a whiteout for @dentry on @bindex. ++ */ ++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent) ++{ ++ struct dentry *wh_dentry; ++ struct super_block *sb; ++ int err; ++ ++ sb = dentry->d_sb; ++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, au_sbr(sb, bindex)); ++ if (!IS_ERR(wh_dentry) && d_is_negative(wh_dentry)) { ++ err = link_or_create_wh(sb, bindex, wh_dentry); ++ if (!err) { ++ au_set_dbwh(dentry, bindex); ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ } else { ++ dput(wh_dentry); ++ wh_dentry = ERR_PTR(err); ++ } ++ } ++ ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Delete all whiteouts in this directory on branch bindex. */ ++static int del_wh_children(struct path *h_path, struct au_nhash *whlist, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ unsigned long ul, n; ++ struct qstr wh_name; ++ char *p; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct au_vdir_destr *str; ++ ++ err = -ENOMEM; ++ p = (void *)__get_free_page(GFP_NOFS); ++ wh_name.name = p; ++ if (unlikely(!wh_name.name)) ++ goto out; ++ ++ err = 0; ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ p += AUFS_WH_PFX_LEN; ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (ul = 0; !err && ul < n; ul++, head++) { ++ hlist_for_each_entry(pos, head, wh_hash) { ++ if (pos->wh_bindex != bindex) ++ continue; ++ ++ str = &pos->wh_str; ++ if (str->len + AUFS_WH_PFX_LEN <= PATH_MAX) { ++ memcpy(p, str->name, str->len); ++ wh_name.len = AUFS_WH_PFX_LEN + str->len; ++ err = unlink_wh_name(h_path, &wh_name); ++ if (!err) ++ continue; ++ break; ++ } ++ AuIOErr("whiteout name too long %.*s\n", ++ str->len, str->name); ++ err = -EIO; ++ break; ++ } ++ } ++ free_page((unsigned long)wh_name.name); ++ ++out: ++ return err; ++} ++ ++struct del_wh_children_args { ++ int *errp; ++ struct path *h_path; ++ struct au_nhash *whlist; ++ aufs_bindex_t bindex; ++}; ++ ++static void call_del_wh_children(void *args) ++{ ++ struct del_wh_children_args *a = args; ++ *a->errp = del_wh_children(a->h_path, a->whlist, a->bindex); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp) ++{ ++ struct au_whtmp_rmdir *whtmp; ++ int err; ++ unsigned int rdhash; ++ ++ SiMustAnyLock(sb); ++ ++ whtmp = kzalloc(sizeof(*whtmp), gfp); ++ if (unlikely(!whtmp)) { ++ whtmp = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ /* no estimation for dir size */ ++ rdhash = au_sbi(sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = AUFS_RDHASH_DEF; ++ err = au_nhash_alloc(&whtmp->whlist, rdhash, gfp); ++ if (unlikely(err)) { ++ au_kfree_rcu(whtmp); ++ whtmp = ERR_PTR(err); ++ } ++ ++out: ++ return whtmp; ++} ++ ++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp) ++{ ++ if (whtmp->br) ++ au_lcnt_dec(&whtmp->br->br_count); ++ dput(whtmp->wh_dentry); ++ iput(whtmp->dir); ++ au_nhash_wh_free(&whtmp->whlist); ++ au_kfree_rcu(whtmp); ++} ++ ++/* ++ * rmdir the whiteouted temporary named dir @h_dentry. ++ * @whlist: whiteouted children. ++ */ ++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_nhash *whlist) ++{ ++ int err; ++ unsigned int h_nlink; ++ struct path wh_path; ++ struct inode *wh_inode, *h_dir; ++ struct au_branch *br; ++ struct user_namespace *h_userns; ++ ++ h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */ ++ IMustLock(h_dir); ++ ++ br = au_sbr(dir->i_sb, bindex); ++ wh_path.dentry = wh_dentry; ++ wh_path.mnt = au_br_mnt(br); ++ h_userns = au_br_userns(br); ++ wh_inode = d_inode(wh_dentry); ++ inode_lock_nested(wh_inode, AuLsc_I_CHILD); ++ ++ /* ++ * someone else might change some whiteouts while we were sleeping. ++ * it means this whlist may have an obsoleted entry. ++ */ ++ if (!au_test_h_perm_sio(h_userns, wh_inode, MAY_EXEC | MAY_WRITE)) ++ err = del_wh_children(&wh_path, whlist, bindex); ++ else { ++ int wkq_err; ++ struct del_wh_children_args args = { ++ .errp = &err, ++ .h_path = &wh_path, ++ .whlist = whlist, ++ .bindex = bindex ++ }; ++ ++ wkq_err = au_wkq_wait(call_del_wh_children, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ inode_unlock(wh_inode); ++ ++ if (!err) { ++ h_nlink = h_dir->i_nlink; ++ err = vfsub_rmdir(h_dir, &wh_path); ++ /* some fs doesn't change the parent nlink in some cases */ ++ h_nlink -= h_dir->i_nlink; ++ } ++ ++ if (!err) { ++ if (au_ibtop(dir) == bindex) { ++ /* todo: dir->i_mutex is necessary */ ++ au_cpup_attr_timesizes(dir); ++ if (h_nlink) ++ vfsub_drop_nlink(dir); ++ } ++ return 0; /* success */ ++ } ++ ++ pr_warn("failed removing %pd(%d), ignored\n", wh_dentry, err); ++ return err; ++} ++ ++static void call_rmdir_whtmp(void *args) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct au_whtmp_rmdir *a = args; ++ struct super_block *sb; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ struct au_hinode *hdir; ++ ++ /* rmdir by nfsd may cause deadlock with this i_mutex */ ++ /* inode_lock(a->dir); */ ++ err = -EROFS; ++ sb = a->dir->i_sb; ++ si_read_lock(sb, !AuLock_FLUSH); ++ if (!au_br_writable(a->br->br_perm)) ++ goto out; ++ bindex = au_br_index(sb, a->br->br_id); ++ if (unlikely(bindex < 0)) ++ goto out; ++ ++ err = -EIO; ++ ii_write_lock_parent(a->dir); ++ h_parent = dget_parent(a->wh_dentry); ++ h_dir = d_inode(h_parent); ++ hdir = au_hi(a->dir, bindex); ++ err = vfsub_mnt_want_write(au_br_mnt(a->br)); ++ if (unlikely(err)) ++ goto out_mnt; ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ err = au_h_verify(a->wh_dentry, au_opt_udba(sb), h_dir, h_parent, ++ a->br); ++ if (!err) ++ err = au_whtmp_rmdir(a->dir, bindex, a->wh_dentry, &a->whlist); ++ au_hn_inode_unlock(hdir); ++ vfsub_mnt_drop_write(au_br_mnt(a->br)); ++ ++out_mnt: ++ dput(h_parent); ++ ii_write_unlock(a->dir); ++out: ++ /* inode_unlock(a->dir); */ ++ au_whtmp_rmdir_free(a); ++ si_read_unlock(sb); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ if (unlikely(err)) ++ AuIOErr("err %d\n", err); ++} ++ ++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args) ++{ ++ int wkq_err; ++ struct super_block *sb; ++ ++ IMustLock(dir); ++ ++ /* all post-process will be done in do_rmdir_whtmp(). */ ++ sb = dir->i_sb; ++ args->dir = au_igrab(dir); ++ args->br = au_sbr(sb, bindex); ++ 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)) { ++ pr_warn("rmdir error %pd (%d), ignored\n", wh_dentry, wkq_err); ++ au_whtmp_rmdir_free(args); ++ } ++} +diff -Naur null/fs/aufs/whout.h linux-5.15.36/fs/aufs/whout.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/whout.h 2022-05-10 16:51:39.878744219 +0300 +@@ -0,0 +1,87 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * whiteout for logical deletion and opaque directory ++ */ ++ ++#ifndef __AUFS_WHOUT_H__ ++#define __AUFS_WHOUT_H__ ++ ++#ifdef __KERNEL__ ++ ++#include "dir.h" ++ ++/* whout.c */ ++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name); ++int au_wh_test(struct user_namespace *h_userns, struct path *h_ppath, ++ struct qstr *wh_name, int try_sio); ++int au_diropq_test(struct user_namespace *h_userns, struct path *h_path); ++struct au_branch; ++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, ++ struct qstr *prefix); ++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br); ++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, ++ struct dentry *dentry); ++int au_wh_init(struct au_branch *br, struct super_block *sb); ++ ++/* diropq flags */ ++#define AuDiropq_CREATE 1 ++#define au_ftest_diropq(flags, name) ((flags) & AuDiropq_##name) ++#define au_fset_diropq(flags, name) \ ++ do { (flags) |= AuDiropq_##name; } while (0) ++#define au_fclr_diropq(flags, name) \ ++ do { (flags) &= ~AuDiropq_##name; } while (0) ++ ++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags); ++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, ++ struct au_branch *br); ++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent); ++ ++/* real rmdir for the whiteout-ed dir */ ++struct au_whtmp_rmdir { ++ struct inode *dir; ++ struct au_branch *br; ++ struct dentry *wh_dentry; ++ struct au_nhash whlist; ++}; ++ ++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp); ++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp); ++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_nhash *whlist); ++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct dentry *au_diropq_create(struct dentry *dentry, ++ aufs_bindex_t bindex) ++{ ++ return au_diropq_sio(dentry, bindex, AuDiropq_CREATE); ++} ++ ++static inline int au_diropq_remove(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ return PTR_ERR(au_diropq_sio(dentry, bindex, !AuDiropq_CREATE)); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_WHOUT_H__ */ +diff -Naur null/fs/aufs/wkq.c linux-5.15.36/fs/aufs/wkq.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/wkq.c 2022-05-10 16:51:39.878744219 +0300 +@@ -0,0 +1,372 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * workqueue for asynchronous/super-io operations ++ * todo: try new credential scheme ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* internal workqueue named AUFS_WKQ_NAME */ ++ ++static struct workqueue_struct *au_wkq; ++ ++struct au_wkinfo { ++ struct work_struct wk; ++ struct kobject *kobj; ++ ++ unsigned int flags; /* see wkq.h */ ++ ++ au_wkq_func_t func; ++ void *args; ++ ++#ifdef CONFIG_LOCKDEP ++ int dont_check; ++ struct held_lock **hlock; ++#endif ++ ++ struct completion *comp; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * Aufs passes some operations to the workqueue such as the internal copyup. ++ * This scheme looks rather unnatural for LOCKDEP debugging feature, since the ++ * job run by workqueue depends upon the locks acquired in the other task. ++ * Delegating a small operation to the workqueue, aufs passes its lockdep ++ * information too. And the job in the workqueue restores the info in order to ++ * pretend as if it acquired those locks. This is just to make LOCKDEP work ++ * correctly and expectedly. ++ */ ++ ++#ifndef CONFIG_LOCKDEP ++AuStubInt0(au_wkq_lockdep_alloc, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_free, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_pre, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_post, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_init, struct au_wkinfo *wkinfo); ++#else ++static void au_wkq_lockdep_init(struct au_wkinfo *wkinfo) ++{ ++ wkinfo->hlock = NULL; ++ wkinfo->dont_check = 0; ++} ++ ++/* ++ * 1: matched ++ * 0: unmatched ++ */ ++static int au_wkq_lockdep_test(struct lock_class_key *key, const char *name) ++{ ++ static DEFINE_SPINLOCK(spin); ++ static struct { ++ char *name; ++ struct lock_class_key *key; ++ } a[] = { ++ { .name = "&sbinfo->si_rwsem" }, ++ { .name = "&finfo->fi_rwsem" }, ++ { .name = "&dinfo->di_rwsem" }, ++ { .name = "&iinfo->ii_rwsem" } ++ }; ++ static int set; ++ int i; ++ ++ /* lockless read from 'set.' see below */ ++ if (set == ARRAY_SIZE(a)) { ++ for (i = 0; i < ARRAY_SIZE(a); i++) ++ if (a[i].key == key) ++ goto match; ++ goto unmatch; ++ } ++ ++ spin_lock(&spin); ++ if (set) ++ for (i = 0; i < ARRAY_SIZE(a); i++) ++ if (a[i].key == key) { ++ spin_unlock(&spin); ++ goto match; ++ } ++ for (i = 0; i < ARRAY_SIZE(a); i++) { ++ if (a[i].key) { ++ if (unlikely(a[i].key == key)) { /* rare but possible */ ++ spin_unlock(&spin); ++ goto match; ++ } else ++ continue; ++ } ++ if (strstr(a[i].name, name)) { ++ /* ++ * the order of these three lines is important for the ++ * lockless read above. ++ */ ++ a[i].key = key; ++ spin_unlock(&spin); ++ set++; ++ /* AuDbg("%d, %s\n", set, name); */ ++ goto match; ++ } ++ } ++ spin_unlock(&spin); ++ goto unmatch; ++ ++match: ++ return 1; ++unmatch: ++ return 0; ++} ++ ++static int au_wkq_lockdep_alloc(struct au_wkinfo *wkinfo) ++{ ++ int err, n; ++ struct task_struct *curr; ++ struct held_lock **hl, *held_locks, *p; ++ ++ err = 0; ++ curr = current; ++ wkinfo->dont_check = lockdep_recursing(curr); ++ if (wkinfo->dont_check) ++ goto out; ++ n = curr->lockdep_depth; ++ if (!n) ++ goto out; ++ ++ err = -ENOMEM; ++ wkinfo->hlock = kmalloc_array(n + 1, sizeof(*wkinfo->hlock), GFP_NOFS); ++ if (unlikely(!wkinfo->hlock)) ++ goto out; ++ ++ err = 0; ++#if 0 /* left for debugging */ ++ if (0 && au_debug_test()) ++ lockdep_print_held_locks(curr); ++#endif ++ held_locks = curr->held_locks; ++ hl = wkinfo->hlock; ++ while (n--) { ++ p = held_locks++; ++ if (au_wkq_lockdep_test(p->instance->key, p->instance->name)) ++ *hl++ = p; ++ } ++ *hl = NULL; ++ ++out: ++ return err; ++} ++ ++static void au_wkq_lockdep_free(struct au_wkinfo *wkinfo) ++{ ++ au_kfree_try_rcu(wkinfo->hlock); ++} ++ ++static void au_wkq_lockdep_pre(struct au_wkinfo *wkinfo) ++{ ++ struct held_lock *p, **hl = wkinfo->hlock; ++ int subclass; ++ ++ if (wkinfo->dont_check) ++ lockdep_off(); ++ if (!hl) ++ return; ++ while ((p = *hl++)) { /* assignment */ ++ subclass = lockdep_hlock_class(p)->subclass; ++ /* AuDbg("%s, %d\n", p->instance->name, subclass); */ ++ if (p->read) ++ rwsem_acquire_read(p->instance, subclass, 0, ++ /*p->acquire_ip*/_RET_IP_); ++ else ++ rwsem_acquire(p->instance, subclass, 0, ++ /*p->acquire_ip*/_RET_IP_); ++ } ++} ++ ++static void au_wkq_lockdep_post(struct au_wkinfo *wkinfo) ++{ ++ struct held_lock *p, **hl = wkinfo->hlock; ++ ++ if (wkinfo->dont_check) ++ lockdep_on(); ++ if (!hl) ++ return; ++ while ((p = *hl++)) /* assignment */ ++ rwsem_release(p->instance, /*p->acquire_ip*/_RET_IP_); ++} ++#endif ++ ++static void wkq_func(struct work_struct *wk) ++{ ++ struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk); ++ ++ AuDebugOn(!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)); ++ AuDebugOn(rlimit(RLIMIT_FSIZE) != RLIM_INFINITY); ++ ++ au_wkq_lockdep_pre(wkinfo); ++ wkinfo->func(wkinfo->args); ++ au_wkq_lockdep_post(wkinfo); ++ if (au_ftest_wkq(wkinfo->flags, WAIT)) ++ complete(wkinfo->comp); ++ else { ++ kobject_put(wkinfo->kobj); ++ module_put(THIS_MODULE); /* todo: ?? */ ++ au_kfree_rcu(wkinfo); ++ } ++} ++ ++/* ++ * Since struct completion is large, try allocating it dynamically. ++ */ ++#define AuWkqCompDeclare(name) struct completion *comp = NULL ++ ++static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) ++{ ++ *comp = kmalloc(sizeof(**comp), GFP_NOFS); ++ if (*comp) { ++ init_completion(*comp); ++ wkinfo->comp = *comp; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++static void au_wkq_comp_free(struct completion *comp) ++{ ++ au_kfree_rcu(comp); ++} ++ ++static void au_wkq_run(struct au_wkinfo *wkinfo) ++{ ++ 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," ++ " or async xino write?\n"); ++ AuDebugOn(au_ftest_wkq(wkinfo->flags, WAIT)); ++ } ++ } else ++ au_dbg_verify_kthread(); ++ ++ if (au_ftest_wkq(wkinfo->flags, WAIT)) { ++ INIT_WORK_ONSTACK(&wkinfo->wk, wkq_func); ++ queue_work(au_wkq, &wkinfo->wk); ++ } else { ++ INIT_WORK(&wkinfo->wk, wkq_func); ++ schedule_work(&wkinfo->wk); ++ } ++} ++ ++/* ++ * Be careful. It is easy to make deadlock happen. ++ * processA: lock, wkq and wait ++ * processB: wkq and wait, lock in wkq ++ * --> deadlock ++ */ ++int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args) ++{ ++ int err; ++ AuWkqCompDeclare(comp); ++ struct au_wkinfo wkinfo = { ++ .flags = flags, ++ .func = func, ++ .args = args ++ }; ++ ++ err = au_wkq_comp_alloc(&wkinfo, &comp); ++ if (unlikely(err)) ++ goto out; ++ err = au_wkq_lockdep_alloc(&wkinfo); ++ if (unlikely(err)) ++ goto out_comp; ++ if (!err) { ++ au_wkq_run(&wkinfo); ++ /* no timeout, no interrupt */ ++ wait_for_completion(wkinfo.comp); ++ } ++ au_wkq_lockdep_free(&wkinfo); ++ ++out_comp: ++ au_wkq_comp_free(comp); ++out: ++ destroy_work_on_stack(&wkinfo.wk); ++ return err; ++} ++ ++/* ++ * Note: dget/dput() in func for aufs dentries are not supported. It will be a ++ * problem in a concurrent umounting. ++ */ ++int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, ++ unsigned int flags) ++{ ++ int err; ++ struct au_wkinfo *wkinfo; ++ ++ atomic_inc(&au_sbi(sb)->si_nowait.nw_len); ++ ++ /* ++ * wkq_func() must free this wkinfo. ++ * it highly depends upon the implementation of workqueue. ++ */ ++ err = 0; ++ wkinfo = kmalloc(sizeof(*wkinfo), GFP_NOFS); ++ if (wkinfo) { ++ wkinfo->kobj = &au_sbi(sb)->si_kobj; ++ wkinfo->flags = flags & ~AuWkq_WAIT; ++ wkinfo->func = func; ++ wkinfo->args = args; ++ wkinfo->comp = NULL; ++ au_wkq_lockdep_init(wkinfo); ++ kobject_get(wkinfo->kobj); ++ __module_get(THIS_MODULE); /* todo: ?? */ ++ ++ au_wkq_run(wkinfo); ++ } else { ++ err = -ENOMEM; ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_nwt_init(struct au_nowait_tasks *nwt) ++{ ++ atomic_set(&nwt->nw_len, 0); ++ /* smp_mb(); */ /* atomic_set */ ++ init_waitqueue_head(&nwt->nw_wq); ++} ++ ++void au_wkq_fin(void) ++{ ++ destroy_workqueue(au_wkq); ++} ++ ++int __init au_wkq_init(void) ++{ ++ int err; ++ ++ err = 0; ++ au_wkq = alloc_workqueue(AUFS_WKQ_NAME, 0, WQ_DFL_ACTIVE); ++ if (IS_ERR(au_wkq)) ++ err = PTR_ERR(au_wkq); ++ else if (!au_wkq) ++ err = -ENOMEM; ++ ++ return err; ++} +diff -Naur null/fs/aufs/wkq.h linux-5.15.36/fs/aufs/wkq.h +--- /dev/null ++++ linux-5.15.36/fs/aufs/wkq.h 2022-05-10 16:51:39.878744219 +0300 +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * workqueue for asynchronous/super-io operations ++ * todo: try new credentials management scheme ++ */ ++ ++#ifndef __AUFS_WKQ_H__ ++#define __AUFS_WKQ_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct super_block; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * in the next operation, wait for the 'nowait' tasks in system-wide workqueue ++ */ ++struct au_nowait_tasks { ++ atomic_t nw_len; ++ wait_queue_head_t nw_wq; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++typedef void (*au_wkq_func_t)(void *args); ++ ++/* wkq flags */ ++#define AuWkq_WAIT 1 ++#define AuWkq_NEST (1 << 1) ++#define au_ftest_wkq(flags, name) ((flags) & AuWkq_##name) ++#define au_fset_wkq(flags, name) \ ++ do { (flags) |= AuWkq_##name; } while (0) ++#define au_fclr_wkq(flags, name) \ ++ do { (flags) &= ~AuWkq_##name; } while (0) ++ ++/* 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, ++ unsigned int flags); ++void au_nwt_init(struct au_nowait_tasks *nwt); ++int __init au_wkq_init(void); ++void au_wkq_fin(void); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int au_wkq_test(void) ++{ ++ return current->flags & PF_WQ_WORKER; ++} ++ ++static inline int au_wkq_wait(au_wkq_func_t func, void *args) ++{ ++ return au_wkq_do_wait(AuWkq_WAIT, func, args); ++} ++ ++static inline void au_nwt_done(struct au_nowait_tasks *nwt) ++{ ++ if (atomic_dec_and_test(&nwt->nw_len)) ++ wake_up_all(&nwt->nw_wq); ++} ++ ++static inline int au_nwt_flush(struct au_nowait_tasks *nwt) ++{ ++ wait_event(nwt->nw_wq, !atomic_read(&nwt->nw_len)); ++ return 0; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_WKQ_H__ */ +diff -Naur null/fs/aufs/xattr.c linux-5.15.36/fs/aufs/xattr.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/xattr.c 2022-05-10 16:51:39.878744219 +0300 +@@ -0,0 +1,368 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2014-2021 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 . ++ */ ++ ++/* ++ * handling xattr functions ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++static int au_xattr_ignore(int err, char *name, unsigned int ignore_flags) ++{ ++ if (!ignore_flags) ++ goto out; ++ switch (err) { ++ case -ENOMEM: ++ case -EDQUOT: ++ goto out; ++ } ++ ++ if ((ignore_flags & AuBrAttr_ICEX) == AuBrAttr_ICEX) { ++ err = 0; ++ goto out; ++ } ++ ++#define cmp(brattr, prefix) do { \ ++ if (!strncmp(name, XATTR_##prefix##_PREFIX, \ ++ XATTR_##prefix##_PREFIX_LEN)) { \ ++ if (ignore_flags & AuBrAttr_ICEX_##brattr) \ ++ err = 0; \ ++ goto out; \ ++ } \ ++ } while (0) ++ ++ cmp(SEC, SECURITY); ++ cmp(SYS, SYSTEM); ++ cmp(TR, TRUSTED); ++ cmp(USR, USER); ++#undef cmp ++ ++ if (ignore_flags & AuBrAttr_ICEX_OTH) ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static const int au_xattr_out_of_list = AuBrAttr_ICEX_OTH << 1; ++ ++static int au_do_cpup_xattr(struct path *h_dst, struct path *h_src, ++ char *name, char **buf, unsigned int ignore_flags, ++ unsigned int verbose) ++{ ++ int err; ++ ssize_t ssz; ++ struct inode *h_idst; ++ struct dentry *h_dst_dentry, *h_src_dentry; ++ struct user_namespace *h_dst_userns, *h_src_userns; ++ ++ h_src_userns = mnt_user_ns(h_src->mnt); ++ h_src_dentry = h_src->dentry; ++ ssz = vfs_getxattr_alloc(h_src_userns, h_src_dentry, name, buf, 0, ++ GFP_NOFS); ++ err = ssz; ++ if (unlikely(err <= 0)) { ++ if (err == -ENODATA ++ || (err == -EOPNOTSUPP ++ && ((ignore_flags & au_xattr_out_of_list) ++ || (au_test_nfs_noacl(d_inode(h_src_dentry)) ++ && (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) ++ || !strcmp(name, ++ XATTR_NAME_POSIX_ACL_DEFAULT)))) ++ )) ++ err = 0; ++ if (err && (verbose || au_debug_test())) ++ pr_err("%s, err %d\n", name, err); ++ goto out; ++ } ++ ++ /* unlock it temporary */ ++ h_dst_userns = mnt_user_ns(h_dst->mnt); ++ h_dst_dentry = h_dst->dentry; ++ h_idst = d_inode(h_dst_dentry); ++ inode_unlock(h_idst); ++ err = vfsub_setxattr(h_dst_userns, h_dst_dentry, name, *buf, ssz, ++ /*flags*/0); ++ inode_lock_nested(h_idst, AuLsc_I_CHILD2); ++ if (unlikely(err)) { ++ if (verbose || au_debug_test()) ++ pr_err("%s, err %d\n", name, err); ++ err = au_xattr_ignore(err, name, ignore_flags); ++ } ++ ++out: ++ return err; ++} ++ ++int au_cpup_xattr(struct path *h_dst, struct path *h_src, int ignore_flags, ++ unsigned int verbose) ++{ ++ int err, unlocked, acl_access, acl_default; ++ ssize_t ssz; ++ struct dentry *h_dst_dentry, *h_src_dentry; ++ struct inode *h_isrc, *h_idst; ++ char *value, *p, *o, *e; ++ ++ /* try stopping to update the source inode while we are referencing */ ++ /* there should not be the parent-child relationship between them */ ++ h_dst_dentry = h_dst->dentry; ++ h_idst = d_inode(h_dst_dentry); ++ h_src_dentry = h_src->dentry; ++ h_isrc = d_inode(h_src_dentry); ++ inode_unlock(h_idst); ++ inode_lock_shared_nested(h_isrc, AuLsc_I_CHILD); ++ inode_lock_nested(h_idst, AuLsc_I_CHILD2); ++ unlocked = 0; ++ ++ /* some filesystems don't list POSIX ACL, for example tmpfs */ ++ ssz = vfs_listxattr(h_src_dentry, NULL, 0); ++ err = ssz; ++ if (unlikely(err < 0)) { ++ AuTraceErr(err); ++ if (err == -ENODATA ++ || err == -EOPNOTSUPP) ++ err = 0; /* ignore */ ++ goto out; ++ } ++ ++ err = 0; ++ p = NULL; ++ o = NULL; ++ if (ssz) { ++ err = -ENOMEM; ++ p = kmalloc(ssz, GFP_NOFS); ++ o = p; ++ if (unlikely(!p)) ++ goto out; ++ err = vfs_listxattr(h_src_dentry, p, ssz); ++ } ++ inode_unlock_shared(h_isrc); ++ unlocked = 1; ++ AuDbg("err %d, ssz %zd\n", err, ssz); ++ if (unlikely(err < 0)) ++ goto out_free; ++ ++ err = 0; ++ e = p + ssz; ++ value = NULL; ++ acl_access = 0; ++ acl_default = 0; ++ while (!err && p < e) { ++ acl_access |= !strncmp(p, XATTR_NAME_POSIX_ACL_ACCESS, ++ sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1); ++ acl_default |= !strncmp(p, XATTR_NAME_POSIX_ACL_DEFAULT, ++ sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) ++ - 1); ++ err = au_do_cpup_xattr(h_dst, h_src, p, &value, ignore_flags, ++ verbose); ++ p += strlen(p) + 1; ++ } ++ AuTraceErr(err); ++ ignore_flags |= au_xattr_out_of_list; ++ if (!err && !acl_access) { ++ err = au_do_cpup_xattr(h_dst, h_src, ++ XATTR_NAME_POSIX_ACL_ACCESS, &value, ++ ignore_flags, verbose); ++ AuTraceErr(err); ++ } ++ if (!err && !acl_default) { ++ err = au_do_cpup_xattr(h_dst, h_src, ++ XATTR_NAME_POSIX_ACL_DEFAULT, &value, ++ ignore_flags, verbose); ++ AuTraceErr(err); ++ } ++ ++ au_kfree_try_rcu(value); ++ ++out_free: ++ au_kfree_try_rcu(o); ++out: ++ if (!unlocked) ++ inode_unlock_shared(h_isrc); ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_smack_reentering(struct super_block *sb) ++{ ++#if IS_ENABLED(CONFIG_SECURITY_SMACK) || IS_ENABLED(CONFIG_SECURITY_SELINUX) ++ /* ++ * as a part of lookup, smack_d_instantiate() is called, and it calls ++ * i_op->getxattr(). ouch. ++ */ ++ return si_pid_test(sb); ++#else ++ return 0; ++#endif ++} ++ ++enum { ++ AU_XATTR_LIST, ++ AU_XATTR_GET ++}; ++ ++struct au_lgxattr { ++ int type; ++ union { ++ struct { ++ char *list; ++ size_t size; ++ } list; ++ struct { ++ const char *name; ++ void *value; ++ size_t size; ++ } get; ++ } u; ++}; ++ ++static ssize_t au_lgxattr(struct dentry *dentry, struct inode *inode, ++ struct au_lgxattr *arg) ++{ ++ ssize_t err; ++ int reenter; ++ struct path h_path; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ reenter = au_smack_reentering(sb); ++ if (!reenter) { ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ } ++ err = au_h_path_getattr(dentry, inode, /*force*/1, &h_path, reenter); ++ if (unlikely(err)) ++ goto out_si; ++ if (unlikely(!h_path.dentry)) ++ /* illegally overlapped or something */ ++ goto out_di; /* pretending success */ ++ ++ /* always topmost entry only */ ++ switch (arg->type) { ++ case AU_XATTR_LIST: ++ err = vfs_listxattr(h_path.dentry, ++ arg->u.list.list, arg->u.list.size); ++ break; ++ case AU_XATTR_GET: ++ AuDebugOn(d_is_negative(h_path.dentry)); ++ err = vfs_getxattr(mnt_user_ns(h_path.mnt), h_path.dentry, ++ arg->u.get.name, arg->u.get.value, ++ arg->u.get.size); ++ break; ++ } ++ ++out_di: ++ if (!reenter) ++ di_read_unlock(dentry, AuLock_IR); ++out_si: ++ if (!reenter) ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size) ++{ ++ struct au_lgxattr arg = { ++ .type = AU_XATTR_LIST, ++ .u.list = { ++ .list = list, ++ .size = size ++ }, ++ }; ++ ++ return au_lgxattr(dentry, /*inode*/NULL, &arg); ++} ++ ++static ssize_t au_getxattr(struct dentry *dentry, struct inode *inode, ++ const char *name, void *value, size_t size) ++{ ++ struct au_lgxattr arg = { ++ .type = AU_XATTR_GET, ++ .u.get = { ++ .name = name, ++ .value = value, ++ .size = size ++ }, ++ }; ++ ++ return au_lgxattr(dentry, inode, &arg); ++} ++ ++static int au_setxattr(struct dentry *dentry, struct inode *inode, ++ const char *name, const void *value, size_t size, ++ int flags) ++{ ++ struct au_sxattr arg = { ++ .type = AU_XATTR_SET, ++ .u.set = { ++ .name = name, ++ .value = value, ++ .size = size, ++ .flags = flags ++ }, ++ }; ++ ++ return au_sxattr(dentry, inode, &arg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_xattr_get(const struct xattr_handler *handler, ++ struct dentry *dentry, struct inode *inode, ++ const char *name, void *buffer, size_t size) ++{ ++ return au_getxattr(dentry, inode, name, buffer, size); ++} ++ ++static int au_xattr_set(const struct xattr_handler *handler, ++ struct user_namespace *userns, ++ struct dentry *dentry, struct inode *inode, ++ const char *name, const void *value, size_t size, ++ int flags) ++{ ++ return au_setxattr(dentry, inode, name, value, size, flags); ++} ++ ++static const struct xattr_handler au_xattr_handler = { ++ .name = "", ++ .prefix = "", ++ .get = au_xattr_get, ++ .set = au_xattr_set ++}; ++ ++static const struct xattr_handler *au_xattr_handlers[] = { ++#ifdef CONFIG_FS_POSIX_ACL ++ &posix_acl_access_xattr_handler, ++ &posix_acl_default_xattr_handler, ++#endif ++ &au_xattr_handler, /* must be last */ ++ NULL ++}; ++ ++void au_xattr_init(struct super_block *sb) ++{ ++ sb->s_xattr = au_xattr_handlers; ++} +diff -Naur null/fs/aufs/xino.c linux-5.15.36/fs/aufs/xino.c +--- /dev/null ++++ linux-5.15.36/fs/aufs/xino.c 2022-05-10 16:51:39.879744219 +0300 +@@ -0,0 +1,1926 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++/* ++ * 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 aufs_bindex_t sbr_find_shared(struct super_block *sb, aufs_bindex_t btop, ++ aufs_bindex_t bbot, ++ struct super_block *h_sb) ++{ ++ /* 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; ++} ++ ++/* ++ * 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; ++ ++ 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 bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * stop unnecessary notify events at creating xino files ++ */ ++ ++aufs_bindex_t au_xi_root(struct super_block *sb, struct dentry *dentry) ++{ ++ aufs_bindex_t bfound, bindex, bbot; ++ struct dentry *parent; ++ struct au_branch *br; ++ ++ 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; ++ } ++ } ++ ++ AuDbg("bfound b%d\n", bfound); ++ return bfound; ++} ++ ++struct au_xino_lock_dir { ++ struct au_hinode *hdir; ++ struct dentry *parent; ++ struct inode *dir; ++}; ++ ++static struct dentry *au_dget_parent_lock(struct dentry *dentry, ++ unsigned int lsc) ++{ ++ struct dentry *parent; ++ struct inode *dir; ++ ++ 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); ++ ++out: ++#endif ++ return parent; ++} ++ ++static void au_xino_lock_dir(struct super_block *sb, struct path *xipath, ++ struct au_xino_lock_dir *ldir) ++{ ++ aufs_bindex_t bindex; ++ ++ 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) ++{ ++ if (ldir->hdir) ++ au_hn_inode_unlock(ldir->hdir); ++ else { ++ inode_unlock(ldir->dir); ++ dput(ldir->parent); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create and set a new xino file ++ */ ++struct file *au_xino_create(struct super_block *sb, char *fpath, int silent, ++ int wbrtop) ++{ ++ struct file *file; ++ struct dentry *h_parent, *d; ++ struct inode *h_dir, *inode; ++ int err; ++ static DEFINE_MUTEX(mtx); ++ ++ /* ++ * 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. ++ */ ++ if (!wbrtop) ++ mutex_lock(&mtx); ++ file = vfsub_filp_open(fpath, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE ++ /* | __FMODE_NONOTIFY */, ++ 0666); ++ if (IS_ERR(file)) { ++ if (!wbrtop) ++ mutex_unlock(&mtx); ++ if (!silent) ++ pr_err("open %s(%ld)\n", fpath, PTR_ERR(file)); ++ return file; ++ } ++ ++ /* keep file count */ ++ err = 0; ++ d = file->f_path.dentry; ++ h_parent = au_dget_parent_lock(d, AuLsc_I_PARENT); ++ if (!wbrtop) ++ mutex_unlock(&mtx); ++ /* mnt_want_write() is unnecessary here */ ++ h_dir = d_inode(h_parent); ++ inode = file_inode(file); ++ /* no delegation since it is just created */ ++ if (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; ++ } ++ ++ err = -EINVAL; ++ if (unlikely(sb && 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 */ ++ ++out: ++ fput(file); ++ file = ERR_PTR(err); ++ return file; ++} ++ ++/* ++ * create a new xinofile at the same place/path as @base. ++ */ ++struct file *au_xino_create2(struct super_block *sb, struct path *base, ++ struct file *copy_src) ++{ ++ struct file *file; ++ struct dentry *dentry; ++ struct inode *dir, *delegated; ++ struct qstr *name; ++ struct path ppath, path; ++ int err, do_unlock; ++ struct au_xino_lock_dir ldir; ++ ++ do_unlock = 1; ++ au_xino_lock_dir(sb, base, &ldir); ++ dentry = base->dentry; ++ ppath.dentry = dentry->d_parent; /* dir inode is locked */ ++ ppath.mnt = base->mnt; ++ dir = d_inode(ppath.dentry); ++ IMustLock(dir); ++ ++ name = &dentry->d_name; ++ path.dentry = vfsub_lookup_one_len(name->name, &ppath, name->len); ++ if (IS_ERR(path.dentry)) { ++ file = (void *)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(mnt_user_ns(base->mnt), dir, path.dentry, 0666, NULL); ++ if (unlikely(err)) { ++ file = ERR_PTR(err); ++ pr_err("%pd create err %d\n", dentry, err); ++ goto out_dput; ++ } ++ ++ path.mnt = base->mnt; ++ file = vfsub_dentry_open(&path, ++ O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE ++ /* | __FMODE_NONOTIFY */); ++ if (IS_ERR(file)) { ++ pr_err("%pd open err %ld\n", dentry, PTR_ERR(file)); ++ goto out_dput; ++ } ++ ++ 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", dentry, err); ++ goto out_fput; ++ } ++ ++ if (copy_src) { ++ /* 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", dentry, err); ++ goto out_fput; ++ } ++ } ++ goto out_dput; /* success */ ++ ++out_fput: ++ fput(file); ++ file = ERR_PTR(err); ++out_dput: ++ dput(path.dentry); ++out: ++ if (do_unlock) ++ au_xino_unlock_dir(&ldir); ++ return file; ++} ++ ++struct file *au_xino_file1(struct au_xino *xi) ++{ ++ struct file *file; ++ unsigned int u, nfile; ++ ++ 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) ++{ ++ int err; ++ struct file *f; ++ void *p; ++ ++ if (file) ++ get_file(file); ++ ++ err = 0; ++ f = NULL; ++ if (idx < xi->xi_nfile) { ++ f = xi->xi_file[idx]; ++ if (f) ++ fput(f); ++ } else { ++ 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; ++} ++ ++/* ++ * 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) ++{ ++ 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 { ++ 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; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * truncate xino files ++ */ ++static int au_xino_do_trunc(struct super_block *sb, aufs_bindex_t bindex, ++ int idx, struct kstatfs *st) ++{ ++ int err; ++ blkcnt_t blocks; ++ 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 au_xino *xi; ++ ++ err = -ENOMEM; ++ st = kmalloc(sizeof(*st), GFP_NOFS); ++ if (unlikely(!st)) ++ goto out; ++ ++ err = -EINVAL; ++ bbot = au_sbbot(sb); ++ if (unlikely(bindex < 0 || bbot < bindex)) ++ goto out_st; ++ ++ err = 0; ++ 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: ++ au_kfree_rcu(st); ++out: ++ return err; ++} ++ ++struct xino_do_trunc_args { ++ struct super_block *sb; ++ struct au_branch *br; ++ int idx; ++}; ++ ++static void xino_do_trunc(void *_args) ++{ ++ struct xino_do_trunc_args *args = _args; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct inode *dir; ++ 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, idx); ++ ii_read_unlock(dir); ++ if (unlikely(err)) ++ pr_warn("err b%d, (%d)\n", bindex, err); ++ 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); ++ 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 -1; ++ ++ /* truncation border */ ++ 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; ++ } ++ ++ 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; ++ ++ idx = xino_trunc_test(sb, br); ++ if (idx < 0) ++ return; ++ ++ if (atomic_inc_return(&br->br_xino->xi_truncating) > 1) ++ goto out; ++ ++ /* lock and kfree() will be called in trunc_xino() */ ++ args = kmalloc(sizeof(*args), GFP_NOFS); ++ if (unlikely(!args)) { ++ AuErr1("no memory\n"); ++ goto out; ++ } ++ ++ 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_lcnt_dec(&br->br_count); ++ au_kfree_rcu(args); ++ ++out: ++ 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(struct file *file, struct au_xi_calc *calc, ++ ino_t ino); ++ ++static void au_xino_call_do_new_async(void *args) ++{ ++ 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(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 */ ++ ++ sbinfo = au_sbi(sb); ++ sz = xino_fread(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); ++ } ++ return err; ++} ++ ++static int au_xino_do_write(struct file *file, struct au_xi_calc *calc, ++ ino_t ino) ++{ ++ ssize_t sz; ++ ++ sz = xino_fwrite(file, &ino, sizeof(ino), &calc->pos); ++ if (sz == sizeof(ino)) ++ return 0; /* success */ ++ ++ AuIOErr("write failed (%zd)\n", sz); ++ return -EIO; ++} ++ ++/* ++ * write @ino to the xinofile for the specified branch{@sb, @bindex} ++ * at the position of @h_ino. ++ * even if @ino is zero, it is written to the xinofile and means no entry. ++ * if the size of the xino file on a specific filesystem exceeds the watermark, ++ * try truncating it. ++ */ ++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t ino) ++{ ++ 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; ++ ++ 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); ++ 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(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(struct file *file, void *buf, size_t size, ++ loff_t *pos); ++ ++/* todo: unnecessary to support mmap_sem since kernel-space? */ ++ssize_t xino_fread(struct file *file, void *kbuf, size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ int i; ++ const int prevent_endless = 10; ++ ++ i = 0; ++ do { ++ err = vfsub_read_k(file, kbuf, size, pos); ++ if (err == -EINTR ++ && !au_wkq_test() ++ && fatal_signal_pending(current)) { ++ err = xino_fread_wkq(file, kbuf, size, pos); ++ BUG_ON(err == -EINTR); ++ } ++ } while (i++ < prevent_endless ++ && (err == -EAGAIN || err == -EINTR)); ++ ++#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; ++ 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->file, a->buf, a->size, a->pos); ++} ++ ++static ssize_t xino_fread_wkq(struct file *file, void *buf, size_t size, ++ loff_t *pos) ++{ ++ ssize_t err; ++ int wkq_err; ++ struct xino_fread_args args = { ++ .errp = &err, ++ .file = file, ++ .buf = buf, ++ .size = size, ++ .pos = pos ++ }; ++ ++ wkq_err = au_wkq_wait(call_xino_fread, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ ++static ssize_t xino_fwrite_wkq(struct file *file, void *buf, size_t size, ++ loff_t *pos); ++ ++static ssize_t do_xino_fwrite(struct file *file, void *kbuf, size_t size, ++ loff_t *pos) ++{ ++ ssize_t err; ++ int i; ++ const int prevent_endless = 10; ++ ++ i = 0; ++ do { ++ err = vfsub_write_k(file, kbuf, size, pos); ++ if (err == -EINTR ++ && !au_wkq_test() ++ && fatal_signal_pending(current)) { ++ err = xino_fwrite_wkq(file, kbuf, size, pos); ++ BUG_ON(err == -EINTR); ++ } ++ } while (i++ < prevent_endless ++ && (err == -EAGAIN || err == -EINTR)); ++ ++#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; ++ 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->file, a->buf, a->size, a->pos); ++} ++ ++static ssize_t xino_fwrite_wkq(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, ++ .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(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(file, buf, size, pos); ++ lockdep_on(); ++ } else { ++ lockdep_off(); ++ err = xino_fwrite_wkq(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) ++{ ++ ino_t ino; ++ ++ AuDebugOn(bit < 0 || page_bits <= bit); ++ ino = AUFS_FIRST_INO + pindex * page_bits + bit; ++ return ino; ++} ++ ++static void xib_calc_bit(ino_t ino, unsigned long *pindex, int *bit) ++{ ++ AuDebugOn(ino < AUFS_FIRST_INO); ++ ino -= AUFS_FIRST_INO; ++ *pindex = ino / page_bits; ++ *bit = ino % page_bits; ++} ++ ++static int xib_pindex(struct super_block *sb, unsigned long pindex) ++{ ++ int err; ++ loff_t pos; ++ ssize_t sz; ++ struct au_sbinfo *sbinfo; ++ struct file *xib; ++ unsigned long *p; ++ ++ sbinfo = au_sbi(sb); ++ MtxMustLock(&sbinfo->si_xib_mtx); ++ AuDebugOn(pindex > ULONG_MAX / PAGE_SIZE ++ || !au_opt_test(sbinfo->si_mntflags, XINO)); ++ ++ if (pindex == sbinfo->si_xib_last_pindex) ++ return 0; ++ ++ xib = sbinfo->si_xib; ++ p = sbinfo->si_xib_buf; ++ pos = sbinfo->si_xib_last_pindex; ++ pos *= PAGE_SIZE; ++ sz = xino_fwrite(xib, p, PAGE_SIZE, &pos); ++ if (unlikely(sz != PAGE_SIZE)) ++ goto out; ++ ++ pos = pindex; ++ pos *= PAGE_SIZE; ++ if (vfsub_f_size_read(xib) >= pos + PAGE_SIZE) ++ sz = xino_fread(xib, p, PAGE_SIZE, &pos); ++ else { ++ memset(p, 0, PAGE_SIZE); ++ sz = xino_fwrite(xib, p, PAGE_SIZE, &pos); ++ } ++ if (sz == PAGE_SIZE) { ++ sbinfo->si_xib_last_pindex = pindex; ++ return 0; /* success */ ++ } ++ ++out: ++ AuIOErr1("write failed (%zd)\n", sz); ++ err = sz; ++ if (sz >= 0) ++ err = -EIO; ++ return err; ++} ++ ++static void au_xib_clear_bit(struct inode *inode) ++{ ++ int err, bit; ++ unsigned long pindex; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ AuDebugOn(inode->i_nlink); ++ ++ sb = inode->i_sb; ++ xib_calc_bit(inode->i_ino, &pindex, &bit); ++ AuDebugOn(page_bits <= bit); ++ sbinfo = au_sbi(sb); ++ mutex_lock(&sbinfo->si_xib_mtx); ++ err = xib_pindex(sb, pindex); ++ if (!err) { ++ clear_bit(bit, sbinfo->si_xib_buf); ++ sbinfo->si_xib_next_bit = bit; ++ } ++ mutex_unlock(&sbinfo->si_xib_mtx); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * truncate a xino bitmap file ++ */ ++ ++/* todo: slow */ ++static int do_xib_restore(struct super_block *sb, struct file *file, void *page) ++{ ++ int err, bit; ++ ssize_t sz; ++ unsigned long pindex; ++ loff_t pos, pend; ++ struct au_sbinfo *sbinfo; ++ ino_t *ino; ++ unsigned long *p; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ MtxMustLock(&sbinfo->si_xib_mtx); ++ p = sbinfo->si_xib_buf; ++ pend = vfsub_f_size_read(file); ++ pos = 0; ++ while (pos < pend) { ++ sz = xino_fread(file, page, PAGE_SIZE, &pos); ++ err = sz; ++ if (unlikely(sz <= 0)) ++ goto out; ++ ++ err = 0; ++ for (ino = page; sz > 0; ino++, sz -= sizeof(ino)) { ++ if (unlikely(*ino < AUFS_FIRST_INO)) ++ continue; ++ ++ xib_calc_bit(*ino, &pindex, &bit); ++ AuDebugOn(page_bits <= bit); ++ err = xib_pindex(sb, pindex); ++ if (!err) ++ set_bit(bit, p); ++ else ++ goto out; ++ } ++ } ++ ++out: ++ return err; ++} ++ ++static int xib_restore(struct super_block *sb) ++{ ++ 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); ++ if (unlikely(!page)) ++ goto out; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; 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: ++ return err; ++} ++ ++int au_xib_trunc(struct super_block *sb) ++{ ++ int err; ++ ssize_t sz; ++ loff_t pos; ++ struct au_sbinfo *sbinfo; ++ unsigned long *p; ++ struct file *file; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ if (!au_opt_test(sbinfo->si_mntflags, XINO)) ++ goto out; ++ ++ file = sbinfo->si_xib; ++ if (vfsub_f_size_read(file) <= PAGE_SIZE) ++ goto out; ++ ++ file = au_xino_create2(sb, &sbinfo->si_xib->f_path, NULL); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = file; ++ ++ p = sbinfo->si_xib_buf; ++ memset(p, 0, PAGE_SIZE); ++ pos = 0; ++ sz = xino_fwrite(sbinfo->si_xib, p, PAGE_SIZE, &pos); ++ if (unlikely(sz != PAGE_SIZE)) { ++ err = sz; ++ AuIOErr("err %d\n", err); ++ if (sz >= 0) ++ err = -EIO; ++ goto out; ++ } ++ ++ mutex_lock(&sbinfo->si_xib_mtx); ++ /* mnt_want_write() is unnecessary here */ ++ err = xib_restore(sb); ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++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); ++ /* kmemleak reported au_kfree_rcu() doesn't free it */ ++ kfree(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 ++ */ ++ ++/* xino bitmap */ ++static void xino_clear_xib(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ if (sbinfo->si_xib) ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = NULL; ++ if (sbinfo->si_xib_buf) ++ free_page((unsigned long)sbinfo->si_xib_buf); ++ sbinfo->si_xib_buf = NULL; ++} ++ ++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(sb, path, sbinfo->si_xib); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ if (sbinfo->si_xib) ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = 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) ++ sbinfo->si_xib_buf = (void *)get_zeroed_page(GFP_NOFS); ++ if (unlikely(!sbinfo->si_xib_buf)) ++ goto out_unset; ++ ++ sbinfo->si_xib_last_pindex = 0; ++ sbinfo->si_xib_next_bit = 0; ++ if (vfsub_f_size_read(file) < PAGE_SIZE) { ++ pos = 0; ++ err = xino_fwrite(file, sbinfo->si_xib_buf, PAGE_SIZE, &pos); ++ if (unlikely(err != PAGE_SIZE)) ++ goto out_free; ++ } ++ err = 0; ++ goto out; /* success */ ++ ++out_free: ++ if (sbinfo->si_xib_buf) ++ free_page((unsigned long)sbinfo->si_xib_buf); ++ sbinfo->si_xib_buf = NULL; ++ if (err >= 0) ++ err = -EIO; ++out_unset: ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = NULL; ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* xino for each branch */ ++static void xino_clear_br(struct super_block *sb) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ 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; ++ ++ 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; ++ } ++} ++ ++struct au_xino_do_set_br { ++ 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; ++ 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(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; ++ ++ SiMustWriteLock(sb); ++ ++ bbot = au_sbbot(sb); ++ inode = d_inode(sb->s_root); ++ 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)) ++ break; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_xino_clr(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ 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 *xiopt, int remount) ++{ ++ int err, skip; ++ struct dentry *dentry, *parent, *cur_dentry, *cur_parent; ++ struct qstr *dname, *cur_name; ++ struct file *cur_xino; ++ struct au_sbinfo *sbinfo; ++ struct path *path, *cur_path; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ path = &xiopt->file->f_path; ++ dentry = path->dentry; ++ parent = dget_parent(dentry); ++ if (remount) { ++ skip = 0; ++ cur_xino = sbinfo->si_xib; ++ if (cur_xino) { ++ 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); ++ } ++ if (skip) ++ goto out; ++ } ++ ++ au_opt_set(sbinfo->si_mntflags, XINO); ++ err = au_xino_set_xib(sb, path); ++ /* si_x{read,write} are set */ ++ if (!err) ++ 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 setting xino(%d).\n", err); ++ au_xino_clr(sb); ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ++ * create a xinofile at the default place/path. ++ */ ++struct file *au_xino_def(struct super_block *sb) ++{ ++ struct file *file; ++ char *page, *p; ++ struct au_branch *br; ++ struct super_block *h_sb; ++ struct path path; ++ aufs_bindex_t bbot, bindex, bwr; ++ ++ br = NULL; ++ bbot = au_sbbot(sb); ++ bwr = -1; ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm) ++ && !au_test_fs_bad_xino(au_br_sb(br))) { ++ bwr = bindex; ++ break; ++ } ++ } ++ ++ if (bwr >= 0) { ++ file = ERR_PTR(-ENOMEM); ++ page = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!page)) ++ goto out; ++ path.mnt = au_br_mnt(br); ++ path.dentry = au_h_dptr(sb->s_root, bwr); ++ p = d_path(&path, page, PATH_MAX - sizeof(AUFS_XINO_FNAME)); ++ file = (void *)p; ++ if (!IS_ERR(p)) { ++ strcat(p, "/" AUFS_XINO_FNAME); ++ AuDbg("%s\n", p); ++ file = au_xino_create(sb, p, /*silent*/0, /*wbrtop*/1); ++ } ++ free_page((unsigned long)page); ++ } else { ++ file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0, ++ /*wbrtop*/0); ++ if (IS_ERR(file)) ++ goto out; ++ h_sb = file->f_path.dentry->d_sb; ++ if (unlikely(au_test_fs_bad_xino(h_sb))) { ++ pr_err("xino doesn't support %s(%s)\n", ++ AUFS_XINO_DEFPATH, au_sbtype(h_sb)); ++ fput(file); ++ file = ERR_PTR(-EINVAL); ++ } ++ } ++ ++out: ++ return 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 ++ }; ++ ++ 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)) ++ au_xino_put(br); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * 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; ++} ++ ++/* 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; ++ 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); ++ } ++ ++ iinfo = au_ii(inode); ++ bindex = iinfo->ii_btop; ++ if (bindex < 0) ++ return; ++ ++ 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(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 *xi, ino_t h_ino) ++{ ++ int found, total, i; ++ ++ found = -1; ++ total = xi->xi_nondir.total; ++ for (i = 0; i < total; i++) { ++ if (xi->xi_nondir.array[i] != h_ino) ++ continue; ++ found = i; ++ break; ++ } ++ ++ return found; ++} ++ ++static int au_xinondir_expand(struct au_xino *xi) ++{ ++ int err, sz; ++ ino_t *p; ++ ++ BUILD_BUG_ON(KMALLOC_MAX_SIZE > INT_MAX); ++ ++ err = -ENOMEM; ++ sz = xi->xi_nondir.total * sizeof(ino_t); ++ if (unlikely(sz > KMALLOC_MAX_SIZE / 2)) ++ goto out; ++ p = au_kzrealloc(xi->xi_nondir.array, sz, sz << 1, GFP_ATOMIC, ++ /*may_shrink*/0); ++ if (p) { ++ xi->xi_nondir.array = p; ++ xi->xi_nondir.total <<= 1; ++ AuDbg("xi_nondir.total %d\n", xi->xi_nondir.total); ++ err = 0; ++ } ++ ++out: ++ 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 *xi; ++ ++ err = 0; ++ *idx = -1; ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ goto out; /* no xino */ ++ ++ xi = au_sbr(sb, bindex)->br_xino; ++ ++again: ++ spin_lock(&xi->xi_nondir.spin); ++ found = au_xinondir_find(xi, h_ino); ++ if (found == -1) { ++ empty = au_xinondir_find(xi, /*h_ino*/0); ++ if (empty == -1) { ++ empty = xi->xi_nondir.total; ++ err = au_xinondir_expand(xi); ++ if (unlikely(err)) ++ goto out_unlock; ++ } ++ xi->xi_nondir.array[empty] = h_ino; ++ *idx = empty; ++ } else { ++ 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(&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 -Naur null/include/uapi/linux/aufs_type.h linux-5.15.36/include/uapi/linux/aufs_type.h +--- /dev/null ++++ linux-5.15.36/include/uapi/linux/aufs_type.h 2022-05-10 16:51:39.879744219 +0300 +@@ -0,0 +1,452 @@ ++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++/* ++ * Copyright (C) 2005-2021 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 . ++ */ ++ ++#ifndef __AUFS_TYPE_H__ ++#define __AUFS_TYPE_H__ ++ ++#define AUFS_NAME "aufs" ++ ++#ifdef __KERNEL__ ++/* ++ * define it before including all other headers. ++ * sched.h may use pr_* macros before defining "current", so define the ++ * no-current version first, and re-define later. ++ */ ++#define pr_fmt(fmt) AUFS_NAME " %s:%d: " fmt, __func__, __LINE__ ++#include ++#undef pr_fmt ++#define pr_fmt(fmt) \ ++ AUFS_NAME " %s:%d:%.*s[%d]: " fmt, __func__, __LINE__, \ ++ (int)sizeof(current->comm), current->comm, current->pid ++#include ++#else ++#include ++#include ++#include ++#endif /* __KERNEL__ */ ++ ++#define AUFS_VERSION "5.15.36-20220509" ++ ++/* todo? move this to linux-2.6.19/include/magic.h */ ++#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef __KERNEL__ ++#ifdef CONFIG_AUFS_BRANCH_MAX_127 ++typedef int8_t aufs_bindex_t; ++#define AUFS_BRANCH_MAX 127 ++#else ++typedef int16_t aufs_bindex_t; ++#ifdef CONFIG_AUFS_BRANCH_MAX_511 ++#define AUFS_BRANCH_MAX 511 ++#elif defined(CONFIG_AUFS_BRANCH_MAX_1023) ++#define AUFS_BRANCH_MAX 1023 ++#elif defined(CONFIG_AUFS_BRANCH_MAX_32767) ++#define AUFS_BRANCH_MAX 32767 ++#endif ++#endif ++ ++#ifndef AUFS_BRANCH_MAX ++#error unknown CONFIG_AUFS_BRANCH_MAX value ++#endif ++#endif /* __KERNEL__ */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AUFS_FSTYPE AUFS_NAME ++ ++#define AUFS_ROOT_INO 2 ++#define AUFS_FIRST_INO 11 ++ ++#define AUFS_WH_PFX ".wh." ++#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1) ++#define AUFS_WH_TMP_LEN 4 ++/* a limit for rmdir/rename a dir and copyup */ ++#define AUFS_MAX_NAMELEN (NAME_MAX \ ++ - AUFS_WH_PFX_LEN * 2 /* doubly whiteouted */\ ++ - 1 /* dot */\ ++ - AUFS_WH_TMP_LEN) /* hex */ ++#define AUFS_XINO_FNAME "." AUFS_NAME ".xino" ++#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME ++#define AUFS_XINO_DEF_SEC 30 /* seconds */ ++#define AUFS_XINO_DEF_TRUNC 45 /* percentage */ ++#define AUFS_DIRWH_DEF 3 ++#define AUFS_RDCACHE_DEF 10 /* seconds */ ++#define AUFS_RDCACHE_MAX 3600 /* seconds */ ++#define AUFS_RDBLK_DEF 512 /* bytes */ ++#define AUFS_RDHASH_DEF 32 ++#define AUFS_WKQ_NAME AUFS_NAME "d" ++#define AUFS_MFS_DEF_SEC 30 /* seconds */ ++#define AUFS_MFS_MAX_SEC 3600 /* seconds */ ++#define AUFS_FHSM_CACHE_DEF_SEC 30 /* seconds */ ++#define AUFS_PLINK_WARN 50 /* number of plinks in a single bucket */ ++ ++/* pseudo-link maintenace under /proc */ ++#define AUFS_PLINK_MAINT_NAME "plink_maint" ++#define AUFS_PLINK_MAINT_DIR "fs/" AUFS_NAME ++#define AUFS_PLINK_MAINT_PATH AUFS_PLINK_MAINT_DIR "/" AUFS_PLINK_MAINT_NAME ++ ++/* dirren, renamed dir */ ++#define AUFS_DR_INFO_PFX AUFS_WH_PFX ".dr." ++#define AUFS_DR_BRHINO_NAME AUFS_WH_PFX "hino" ++/* whiteouted doubly */ ++#define AUFS_WH_DR_INFO_PFX AUFS_WH_PFX AUFS_DR_INFO_PFX ++#define AUFS_WH_DR_BRHINO AUFS_WH_PFX AUFS_DR_BRHINO_NAME ++ ++#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */ ++#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME ++ ++#define AUFS_BASE_NAME AUFS_WH_PFX AUFS_NAME ++#define AUFS_PLINKDIR_NAME AUFS_WH_PFX "plnk" ++#define AUFS_ORPHDIR_NAME AUFS_WH_PFX "orph" ++ ++/* doubly whiteouted */ ++#define AUFS_WH_BASE AUFS_WH_PFX AUFS_BASE_NAME ++#define AUFS_WH_PLINKDIR AUFS_WH_PFX AUFS_PLINKDIR_NAME ++#define AUFS_WH_ORPHDIR AUFS_WH_PFX AUFS_ORPHDIR_NAME ++ ++/* branch permissions and attributes */ ++#define AUFS_BRPERM_RW "rw" ++#define AUFS_BRPERM_RO "ro" ++#define AUFS_BRPERM_RR "rr" ++#define AUFS_BRATTR_COO_REG "coo_reg" ++#define AUFS_BRATTR_COO_ALL "coo_all" ++#define AUFS_BRATTR_FHSM "fhsm" ++#define AUFS_BRATTR_UNPIN "unpin" ++#define AUFS_BRATTR_ICEX "icex" ++#define AUFS_BRATTR_ICEX_SEC "icexsec" ++#define AUFS_BRATTR_ICEX_SYS "icexsys" ++#define AUFS_BRATTR_ICEX_TR "icextr" ++#define AUFS_BRATTR_ICEX_USR "icexusr" ++#define AUFS_BRATTR_ICEX_OTH "icexoth" ++#define AUFS_BRRATTR_WH "wh" ++#define AUFS_BRWATTR_NLWH "nolwh" ++#define AUFS_BRWATTR_MOO "moo" ++ ++#define AuBrPerm_RW 1 /* writable, hardlinkable wh */ ++#define AuBrPerm_RO (1 << 1) /* readonly */ ++#define AuBrPerm_RR (1 << 2) /* natively readonly */ ++#define AuBrPerm_Mask (AuBrPerm_RW | AuBrPerm_RO | AuBrPerm_RR) ++ ++#define AuBrAttr_COO_REG (1 << 3) /* copy-up on open */ ++#define AuBrAttr_COO_ALL (1 << 4) ++#define AuBrAttr_COO_Mask (AuBrAttr_COO_REG | AuBrAttr_COO_ALL) ++ ++#define AuBrAttr_FHSM (1 << 5) /* file-based hsm */ ++#define AuBrAttr_UNPIN (1 << 6) /* rename-able top dir of ++ branch. meaningless since ++ linux-3.18-rc1 */ ++ ++/* ignore error in copying XATTR */ ++#define AuBrAttr_ICEX_SEC (1 << 7) ++#define AuBrAttr_ICEX_SYS (1 << 8) ++#define AuBrAttr_ICEX_TR (1 << 9) ++#define AuBrAttr_ICEX_USR (1 << 10) ++#define AuBrAttr_ICEX_OTH (1 << 11) ++#define AuBrAttr_ICEX (AuBrAttr_ICEX_SEC \ ++ | AuBrAttr_ICEX_SYS \ ++ | AuBrAttr_ICEX_TR \ ++ | AuBrAttr_ICEX_USR \ ++ | AuBrAttr_ICEX_OTH) ++ ++#define AuBrRAttr_WH (1 << 12) /* whiteout-able */ ++#define AuBrRAttr_Mask AuBrRAttr_WH ++ ++#define AuBrWAttr_NoLinkWH (1 << 13) /* un-hardlinkable whiteouts */ ++#define AuBrWAttr_MOO (1 << 14) /* move-up on open */ ++#define AuBrWAttr_Mask (AuBrWAttr_NoLinkWH | AuBrWAttr_MOO) ++ ++#define AuBrAttr_CMOO_Mask (AuBrAttr_COO_Mask | AuBrWAttr_MOO) ++ ++/* #warning test userspace */ ++#ifdef __KERNEL__ ++#ifndef CONFIG_AUFS_FHSM ++#undef AuBrAttr_FHSM ++#define AuBrAttr_FHSM 0 ++#endif ++#ifndef CONFIG_AUFS_XATTR ++#undef AuBrAttr_ICEX ++#define AuBrAttr_ICEX 0 ++#undef AuBrAttr_ICEX_SEC ++#define AuBrAttr_ICEX_SEC 0 ++#undef AuBrAttr_ICEX_SYS ++#define AuBrAttr_ICEX_SYS 0 ++#undef AuBrAttr_ICEX_TR ++#define AuBrAttr_ICEX_TR 0 ++#undef AuBrAttr_ICEX_USR ++#define AuBrAttr_ICEX_USR 0 ++#undef AuBrAttr_ICEX_OTH ++#define AuBrAttr_ICEX_OTH 0 ++#endif ++#endif ++ ++/* the longest combination */ ++/* AUFS_BRATTR_ICEX and AUFS_BRATTR_ICEX_TR don't affect here */ ++#define AuBrPermStrSz sizeof(AUFS_BRPERM_RW \ ++ "+" AUFS_BRATTR_COO_REG \ ++ "+" AUFS_BRATTR_FHSM \ ++ "+" AUFS_BRATTR_UNPIN \ ++ "+" AUFS_BRATTR_ICEX_SEC \ ++ "+" AUFS_BRATTR_ICEX_SYS \ ++ "+" AUFS_BRATTR_ICEX_USR \ ++ "+" AUFS_BRATTR_ICEX_OTH \ ++ "+" AUFS_BRWATTR_NLWH) ++ ++typedef struct { ++ char a[AuBrPermStrSz]; ++} au_br_perm_str_t; ++ ++static inline int au_br_writable(int brperm) ++{ ++ return brperm & AuBrPerm_RW; ++} ++ ++static inline int au_br_whable(int brperm) ++{ ++ return brperm & (AuBrPerm_RW | AuBrRAttr_WH); ++} ++ ++static inline int au_br_wh_linkable(int brperm) ++{ ++ return !(brperm & AuBrWAttr_NoLinkWH); ++} ++ ++static inline int au_br_cmoo(int brperm) ++{ ++ return brperm & AuBrAttr_CMOO_Mask; ++} ++ ++static inline int au_br_fhsm(int brperm) ++{ ++ return brperm & AuBrAttr_FHSM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ioctl */ ++enum { ++ /* readdir in userspace */ ++ AuCtl_RDU, ++ AuCtl_RDU_INO, ++ ++ AuCtl_WBR_FD, /* pathconf wrapper */ ++ AuCtl_IBUSY, /* busy inode */ ++ AuCtl_MVDOWN, /* move-down */ ++ AuCtl_BR, /* info about branches */ ++ AuCtl_FHSM_FD /* connection for fhsm */ ++}; ++ ++/* borrowed from linux/include/linux/kernel.h */ ++#ifndef ALIGN ++#ifdef _GNU_SOURCE ++#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) ++#else ++#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) ++#endif ++#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) ++#endif ++ ++/* borrowed from linux/include/linux/compiler-gcc3.h */ ++#ifndef __aligned ++#define __aligned(x) __attribute__((aligned(x))) ++#endif ++ ++#ifdef __KERNEL__ ++#ifndef __packed ++#define __packed __attribute__((packed)) ++#endif ++#endif ++ ++struct au_rdu_cookie { ++ uint64_t h_pos; ++ int16_t bindex; ++ uint8_t flags; ++ uint8_t pad; ++ uint32_t generation; ++} __aligned(8); ++ ++struct au_rdu_ent { ++ uint64_t ino; ++ int16_t bindex; ++ uint8_t type; ++ uint8_t nlen; ++ uint8_t wh; ++ char name[]; ++} __aligned(8); ++ ++static inline int au_rdu_len(int nlen) ++{ ++ /* include the terminating NULL */ ++ return ALIGN(sizeof(struct au_rdu_ent) + nlen + 1, ++ sizeof(uint64_t)); ++} ++ ++union au_rdu_ent_ul { ++ struct au_rdu_ent __user *e; ++ uint64_t ul; ++}; ++ ++enum { ++ AufsCtlRduV_SZ, ++ AufsCtlRduV_End ++}; ++ ++struct aufs_rdu { ++ /* input */ ++ union { ++ uint64_t sz; /* AuCtl_RDU */ ++ uint64_t nent; /* AuCtl_RDU_INO */ ++ }; ++ union au_rdu_ent_ul ent; ++ uint16_t verify[AufsCtlRduV_End]; ++ ++ /* input/output */ ++ uint32_t blk; ++ ++ /* output */ ++ union au_rdu_ent_ul tail; ++ /* number of entries which were added in a single call */ ++ uint64_t rent; ++ uint8_t full; ++ uint8_t shwh; ++ ++ struct au_rdu_cookie cookie; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dirren. the branch is identified by the filename who contains this */ ++struct au_drinfo { ++ uint64_t ino; ++ union { ++ uint8_t oldnamelen; ++ uint64_t _padding; ++ }; ++ uint8_t oldname[]; ++} __aligned(8); ++ ++struct au_drinfo_fdata { ++ uint32_t magic; ++ struct au_drinfo drinfo; ++} __aligned(8); ++ ++#define AUFS_DRINFO_MAGIC_V1 ('a' << 24 | 'd' << 16 | 'r' << 8 | 0x01) ++/* future */ ++#define AUFS_DRINFO_MAGIC_V2 ('a' << 24 | 'd' << 16 | 'r' << 8 | 0x02) ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_wbr_fd { ++ uint32_t oflags; ++ int16_t brid; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_ibusy { ++ uint64_t ino, h_ino; ++ int16_t bindex; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* error code for move-down */ ++/* the actual message strings are implemented in aufs-util.git */ ++enum { ++ EAU_MVDOWN_OPAQUE = 1, ++ EAU_MVDOWN_WHITEOUT, ++ EAU_MVDOWN_UPPER, ++ EAU_MVDOWN_BOTTOM, ++ EAU_MVDOWN_NOUPPER, ++ EAU_MVDOWN_NOLOWERBR, ++ EAU_Last ++}; ++ ++/* flags for move-down */ ++#define AUFS_MVDOWN_DMSG 1 ++#define AUFS_MVDOWN_OWLOWER (1 << 1) /* overwrite lower */ ++#define AUFS_MVDOWN_KUPPER (1 << 2) /* keep upper */ ++#define AUFS_MVDOWN_ROLOWER (1 << 3) /* do even if lower is RO */ ++#define AUFS_MVDOWN_ROLOWER_R (1 << 4) /* did on lower RO */ ++#define AUFS_MVDOWN_ROUPPER (1 << 5) /* do even if upper is RO */ ++#define AUFS_MVDOWN_ROUPPER_R (1 << 6) /* did on upper RO */ ++#define AUFS_MVDOWN_BRID_UPPER (1 << 7) /* upper brid */ ++#define AUFS_MVDOWN_BRID_LOWER (1 << 8) /* lower brid */ ++#define AUFS_MVDOWN_FHSM_LOWER (1 << 9) /* find fhsm attr for lower */ ++#define AUFS_MVDOWN_STFS (1 << 10) /* req. stfs */ ++#define AUFS_MVDOWN_STFS_FAILED (1 << 11) /* output: stfs is unusable */ ++#define AUFS_MVDOWN_BOTTOM (1 << 12) /* output: no more lowers */ ++ ++/* index for move-down */ ++enum { ++ AUFS_MVDOWN_UPPER, ++ AUFS_MVDOWN_LOWER, ++ AUFS_MVDOWN_NARRAY ++}; ++ ++/* ++ * additional info of move-down ++ * number of free blocks and inodes. ++ * subset of struct kstatfs, but smaller and always 64bit. ++ */ ++struct aufs_stfs { ++ uint64_t f_blocks; ++ uint64_t f_bavail; ++ uint64_t f_files; ++ uint64_t f_ffree; ++}; ++ ++struct aufs_stbr { ++ int16_t brid; /* optional input */ ++ int16_t bindex; /* output */ ++ struct aufs_stfs stfs; /* output when AUFS_MVDOWN_STFS set */ ++} __aligned(8); ++ ++struct aufs_mvdown { ++ uint32_t flags; /* input/output */ ++ struct aufs_stbr stbr[AUFS_MVDOWN_NARRAY]; /* input/output */ ++ int8_t au_errno; /* output */ ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++union aufs_brinfo { ++ /* PATH_MAX may differ between kernel-space and user-space */ ++ char _spacer[4096]; ++ struct { ++ int16_t id; ++ int perm; ++ char path[]; ++ }; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuCtlType 'A' ++#define AUFS_CTL_RDU _IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu) ++#define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu) ++#define AUFS_CTL_WBR_FD _IOW(AuCtlType, AuCtl_WBR_FD, \ ++ struct aufs_wbr_fd) ++#define AUFS_CTL_IBUSY _IOWR(AuCtlType, AuCtl_IBUSY, struct aufs_ibusy) ++#define AUFS_CTL_MVDOWN _IOWR(AuCtlType, AuCtl_MVDOWN, \ ++ struct aufs_mvdown) ++#define AUFS_CTL_BRINFO _IOW(AuCtlType, AuCtl_BR, union aufs_brinfo) ++#define AUFS_CTL_FHSM_FD _IOW(AuCtlType, AuCtl_FHSM_FD, int) ++ ++#endif /* __AUFS_TYPE_H__ */ diff --git a/kernel/kernel/files/patches/aufs5/tmpfs-idr.patch b/kernel/kernel/files/patches/aufs5/tmpfs-idr.patch new file mode 100644 index 00000000..be89bbee --- /dev/null +++ b/kernel/kernel/files/patches/aufs5/tmpfs-idr.patch @@ -0,0 +1,221 @@ +SPDX-License-Identifier: GPL-2.0 + +diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h +index 166158b6e917..0e9606171432 100644 +--- a/include/linux/shmem_fs.h ++++ b/include/linux/shmem_fs.h +@@ -28,10 +28,13 @@ struct shmem_inode_info { + }; + + struct shmem_sb_info { ++ struct mutex idr_lock; ++ bool idr_nouse; ++ struct idr idr; /* manages inode-number */ + unsigned long max_blocks; /* How many blocks are allowed */ + struct percpu_counter used_blocks; /* How many are allocated */ +- unsigned long max_inodes; /* How many inodes are allowed */ +- unsigned long free_inodes; /* How many are left for allocation */ ++ int max_inodes; /* How many inodes are allowed */ ++ int free_inodes; /* How many are left for allocation */ + raw_spinlock_t stat_lock; /* Serialize shmem_sb_info changes */ + umode_t mode; /* Mount mode for root directory */ + unsigned char huge; /* Whether to try for hugepages */ +diff --git a/mm/shmem.c b/mm/shmem.c +index 1609a8daba26..b3e5f52a5aa2 100644 +--- a/mm/shmem.c ++++ b/mm/shmem.c +@@ -108,7 +108,7 @@ struct shmem_falloc { + + struct shmem_options { + unsigned long long blocks; +- unsigned long long inodes; ++ int inodes; + struct mempolicy *mpol; + kuid_t uid; + kgid_t gid; +@@ -128,11 +128,14 @@ static unsigned long shmem_default_max_blocks(void) + return totalram_pages() / 2; + } + +-static unsigned long shmem_default_max_inodes(void) ++static int shmem_default_max_inodes(void) + { + unsigned long nr_pages = totalram_pages(); ++ unsigned long ul; + +- return min(nr_pages - totalhigh_pages(), nr_pages / 2); ++ ul = INT_MAX; ++ ul = min3(ul, nr_pages - totalhigh_pages(), nr_pages / 2); ++ return ul; + } + #endif + +@@ -1165,6 +1168,11 @@ static void shmem_evict_inode(struct inode *inode) + + simple_xattrs_free(&info->xattrs); + WARN_ON(inode->i_blocks); ++ if (!sbinfo->idr_nouse && inode->i_ino) { ++ mutex_lock(&sbinfo->idr_lock); ++ idr_remove(&sbinfo->idr, inode->i_ino); ++ mutex_unlock(&sbinfo->idr_lock); ++ } + shmem_free_inode(inode->i_sb); + clear_inode(inode); + } +@@ -2336,6 +2344,25 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode + break; + } + ++ if (!sbinfo->idr_nouse) { ++ /* inum 0 and 1 are unused */ ++ mutex_lock(&sbinfo->idr_lock); ++ ino = idr_alloc(&sbinfo->idr, inode, 2, INT_MAX, ++ GFP_NOFS); ++ if (ino > 0) { ++ inode->i_ino = ino; ++ mutex_unlock(&sbinfo->idr_lock); ++ __insert_inode_hash(inode, inode->i_ino); ++ } else { ++ inode->i_ino = 0; ++ mutex_unlock(&sbinfo->idr_lock); ++ iput(inode); ++ /* shmem_free_inode() will be called */ ++ inode = NULL; ++ } ++ } else ++ inode->i_ino = ino; ++ + lockdep_annotate_inode_mutex_key(inode); + } else + shmem_free_inode(sb); +@@ -3250,8 +3277,7 @@ static struct dentry *shmem_get_parent(struct dentry *child) + static int shmem_match(struct inode *ino, void *vfh) + { + __u32 *fh = vfh; +- __u64 inum = fh[2]; +- inum = (inum << 32) | fh[1]; ++ __u64 inum = fh[1]; + return ino->i_ino == inum && fh[0] == ino->i_generation; + } + +@@ -3271,14 +3297,11 @@ static struct dentry *shmem_fh_to_dentry(struct super_block *sb, + struct dentry *dentry = NULL; + u64 inum; + +- if (fh_len < 3) ++ if (fh_len < 2) + return NULL; + +- inum = fid->raw[2]; +- inum = (inum << 32) | fid->raw[1]; +- +- inode = ilookup5(sb, (unsigned long)(inum + fid->raw[0]), +- shmem_match, fid->raw); ++ inum = fid->raw[1]; ++ inode = ilookup5(sb, inum, shmem_match, fid->raw); + if (inode) { + dentry = shmem_find_alias(inode); + iput(inode); +@@ -3290,30 +3313,15 @@ static struct dentry *shmem_fh_to_dentry(struct super_block *sb, + static int shmem_encode_fh(struct inode *inode, __u32 *fh, int *len, + struct inode *parent) + { +- if (*len < 3) { +- *len = 3; ++ if (*len < 2) { ++ *len = 2; + return FILEID_INVALID; + } + +- if (inode_unhashed(inode)) { +- /* Unfortunately insert_inode_hash is not idempotent, +- * so as we hash inodes here rather than at creation +- * time, we need a lock to ensure we only try +- * to do it once +- */ +- static DEFINE_SPINLOCK(lock); +- spin_lock(&lock); +- if (inode_unhashed(inode)) +- __insert_inode_hash(inode, +- inode->i_ino + inode->i_generation); +- spin_unlock(&lock); +- } +- + fh[0] = inode->i_generation; + fh[1] = inode->i_ino; +- fh[2] = ((__u64)inode->i_ino) >> 32; + +- *len = 3; ++ *len = 2; + return 1; + } + +@@ -3392,7 +3400,7 @@ static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param) + break; + case Opt_nr_inodes: + ctx->inodes = memparse(param->string, &rest); +- if (*rest) ++ if (*rest || ctx->inodes < 2) + goto bad_value; + ctx->seen |= SHMEM_SEEN_INODES; + break; +@@ -3502,7 +3510,7 @@ static int shmem_reconfigure(struct fs_context *fc) + { + struct shmem_options *ctx = fc->fs_private; + struct shmem_sb_info *sbinfo = SHMEM_SB(fc->root->d_sb); +- unsigned long inodes; ++ int inodes; + struct mempolicy *mpol = NULL; + const char *err; + +@@ -3571,7 +3579,7 @@ static int shmem_show_options(struct seq_file *seq, struct dentry *root) + seq_printf(seq, ",size=%luk", + sbinfo->max_blocks << (PAGE_SHIFT - 10)); + if (sbinfo->max_inodes != shmem_default_max_inodes()) +- seq_printf(seq, ",nr_inodes=%lu", sbinfo->max_inodes); ++ seq_printf(seq, ",nr_inodes=%d", sbinfo->max_inodes); + if (sbinfo->mode != (0777 | S_ISVTX)) + seq_printf(seq, ",mode=%03ho", sbinfo->mode); + if (!uid_eq(sbinfo->uid, GLOBAL_ROOT_UID)) +@@ -3618,6 +3626,8 @@ static void shmem_put_super(struct super_block *sb) + { + struct shmem_sb_info *sbinfo = SHMEM_SB(sb); + ++ if (!sbinfo->idr_nouse) ++ idr_destroy(&sbinfo->idr); + free_percpu(sbinfo->ino_batch); + percpu_counter_destroy(&sbinfo->used_blocks); + mpol_put(sbinfo->mpol); +@@ -3660,6 +3670,8 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc) + #else + sb->s_flags |= SB_NOUSER; + #endif ++ mutex_init(&sbinfo->idr_lock); ++ idr_init(&sbinfo->idr); + sbinfo->max_blocks = ctx->blocks; + sbinfo->free_inodes = sbinfo->max_inodes = ctx->inodes; + if (sb->s_flags & SB_KERNMOUNT) { +@@ -3777,6 +3789,15 @@ static void shmem_destroy_inodecache(void) + kmem_cache_destroy(shmem_inode_cachep); + } + ++static __init void shmem_no_idr(struct super_block *sb) ++{ ++ struct shmem_sb_info *sbinfo; ++ ++ sbinfo = SHMEM_SB(sb); ++ sbinfo->idr_nouse = true; ++ idr_destroy(&sbinfo->idr); ++} ++ + const struct address_space_operations shmem_aops = { + .writepage = shmem_writepage, + .set_page_dirty = __set_page_dirty_no_writeback, +@@ -3918,6 +3939,7 @@ int __init shmem_init(void) + pr_err("Could not kern_mount tmpfs\n"); + goto out1; + } ++ shmem_no_idr(shm_mnt->mnt_sb); + + #ifdef CONFIG_TRANSPARENT_HUGEPAGE + if (has_transparent_hugepage() && shmem_huge > SHMEM_HUGE_DENY) diff --git a/kernel/kernel/files/patches/aufs5/vfs-ino.patch b/kernel/kernel/files/patches/aufs5/vfs-ino.patch new file mode 100644 index 00000000..992d86c1 --- /dev/null +++ b/kernel/kernel/files/patches/aufs5/vfs-ino.patch @@ -0,0 +1,24 @@ +SPDX-License-Identifier: GPL-2.0 + +diff --git a/fs/inode.c b/fs/inode.c +index 9abc88d7959c..82b13641423c 100644 +--- a/fs/inode.c ++++ b/fs/inode.c +@@ -904,6 +904,8 @@ unsigned int get_next_ino(void) + unsigned int *p = &get_cpu_var(last_ino); + unsigned int res = *p; + ++start: ++ + #ifdef CONFIG_SMP + if (unlikely((res & (LAST_INO_BATCH-1)) == 0)) { + static atomic_t shared_last_ino; +@@ -916,7 +918,7 @@ unsigned int get_next_ino(void) + res++; + /* get_next_ino should not provide a 0 inode number */ + if (unlikely(!res)) +- res++; ++ goto start; + *p = res; + put_cpu_var(last_ino); + return res; diff --git a/kernel/kernel/files/patches/linux/patch-5.15.41.xz b/kernel/kernel/files/patches/linux/patch-5.15.41.xz new file mode 100644 index 0000000000000000000000000000000000000000..3de4fc5db1cf131b5f2437e80a82d14901e814d0 GIT binary patch literal 1725572 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%0AIU{M((_ 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 m?45(9y`e)*!SgoY5U08WCN6KVtTTKJXexuK* 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

gswMJV5t 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%0A5X@5TFbUwrKS<-~IC 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℞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¥}}a#kQp5 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Ð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

!xSoG63M8$LcEK!e3|Gi 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