diff --git a/kernel/kernel/files/configs/kernel-x86_64-config b/kernel/kernel/files/configs/kernel-x86_64-config index b6092c88..9a624aec 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 4.4.2 Kernel Configuration +# Linux/x86_64 4.4.4 Kernel Configuration # CONFIG_64BIT=y CONFIG_X86_64=y @@ -6625,6 +6625,6 @@ CONFIG_ARCH_HAS_MMIO_FLUSH=y # Unofficial 3rd party kernel additions # CONFIG_NDISWRAPPER=m +CONFIG_VIAHSS=m CONFIG_RTL8723BS=m CONFIG_WLAN_SDIO=y -CONFIG_VIAHSS=m diff --git a/kernel/kernel/files/patches/linux/patch-4.4.4.xz b/kernel/kernel/files/patches/linux/patch-4.4.4.xz new file mode 100644 index 00000000..f8dad414 Binary files /dev/null and b/kernel/kernel/files/patches/linux/patch-4.4.4.xz differ diff --git a/kernel/kernel/files/patches/mageia/ata-Adding-Intel-Lewisburg-device-IDs-for-SATA.patch b/kernel/kernel/files/patches/mageia/ata-Adding-Intel-Lewisburg-device-IDs-for-SATA.patch new file mode 100644 index 00000000..96ca0e8b --- /dev/null +++ b/kernel/kernel/files/patches/mageia/ata-Adding-Intel-Lewisburg-device-IDs-for-SATA.patch @@ -0,0 +1,44 @@ +From f5bdd66c705484b4bc77eb914be15c1b7881fae7 Mon Sep 17 00:00:00 2001 +From: Alexandra Yates +Date: Wed, 17 Feb 2016 19:36:20 -0800 +Subject: [PATCH] Adding Intel Lewisburg device IDs for SATA + +This patch complements the list of device IDs previously +added for lewisburg sata. + +Signed-off-by: Alexandra Yates +Signed-off-by: Tejun Heo +Cc: stable@vger.kernel.org +--- + drivers/ata/ahci.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c +index 546a369..b6263b3 100644 +--- a/drivers/ata/ahci.c ++++ b/drivers/ata/ahci.c +@@ -367,15 +367,21 @@ static const struct pci_device_id ahci_pci_tbl[] = { + { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */ + { PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */ + { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/ ++ { PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Lewisburg AHCI*/ + { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* Lewisburg RAID*/ ++ { PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0xa182), board_ahci }, /* Lewisburg AHCI*/ + { PCI_VDEVICE(INTEL, 0xa184), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0xa186), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0xa18e), board_ahci }, /* Lewisburg RAID*/ ++ { PCI_VDEVICE(INTEL, 0xa1d2), board_ahci }, /* Lewisburg RAID*/ ++ { PCI_VDEVICE(INTEL, 0xa1d6), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0xa202), board_ahci }, /* Lewisburg AHCI*/ + { PCI_VDEVICE(INTEL, 0xa204), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0xa20e), board_ahci }, /* Lewisburg RAID*/ ++ { PCI_VDEVICE(INTEL, 0xa252), board_ahci }, /* Lewisburg RAID*/ ++ { PCI_VDEVICE(INTEL, 0xa256), board_ahci }, /* Lewisburg RAID*/ + + /* JMicron 360/1/3/5/6, match class to avoid IDE function */ + { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, +-- +2.7.2 + diff --git a/kernel/kernel/files/patches/mageia/ata-ahci-don-t-mark-HotPlugCapable-Ports-as-external.patch b/kernel/kernel/files/patches/mageia/ata-ahci-don-t-mark-HotPlugCapable-Ports-as-external.patch new file mode 100644 index 00000000..6b53ff17 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/ata-ahci-don-t-mark-HotPlugCapable-Ports-as-external.patch @@ -0,0 +1,45 @@ +From dc8b4afc4a04fac8ee55a19b59f2356a25e7e778 Mon Sep 17 00:00:00 2001 +From: Manuel Lauss +Date: Sat, 27 Feb 2016 16:10:05 +0100 +Subject: [PATCH] ata: ahci: don't mark HotPlugCapable Ports as + external/removable + +The HPCP bit is set by bioses for on-board sata ports either because +they think sata is hotplug capable in general or to allow Windows +to display a "device eject" icon on ports which are routed to an +external connector bracket. + +However in Redhat Bugzilla #1310682, users report that with kernel 4.4, +where this bit test first appeared, a lot of partitions on sata drives +are now mounted automatically. + +This patch should fix redhat and a lot of other distros which +unconditionally automount all devices which have the "removable" +bit set. + +Signed-off-by: Manuel Lauss +Signed-off-by: Tejun Heo +Fixes: 8a3e33cf92c7 ("ata: ahci: find eSATA ports and flag them as removable" changes userspace behavior) +Link: http://lkml.kernel.org/g/56CF35FA.1070500@redhat.com +Cc: stable@vger.kernel.org #v4.4+ +--- + drivers/ata/libahci.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c +index 513b3fa..85ea514 100644 +--- a/drivers/ata/libahci.c ++++ b/drivers/ata/libahci.c +@@ -1168,8 +1168,7 @@ static void ahci_port_init(struct device *dev, struct ata_port *ap, + + /* mark esata ports */ + tmp = readl(port_mmio + PORT_CMD); +- if ((tmp & PORT_CMD_HPCP) || +- ((tmp & PORT_CMD_ESP) && (hpriv->cap & HOST_CAP_SXS))) ++ if ((tmp & PORT_CMD_ESP) && (hpriv->cap & HOST_CAP_SXS)) + ap->pflags |= ATA_PFLAG_EXTERNAL; + } + +-- +2.7.2 + diff --git a/kernel/kernel/files/patches/mageia/fs-aufs-4.4-modular.patch b/kernel/kernel/files/patches/mageia/fs-aufs-4.4-modular.patch index 44d224bc..6d4da033 100644 --- a/kernel/kernel/files/patches/mageia/fs-aufs-4.4-modular.patch +++ b/kernel/kernel/files/patches/mageia/fs-aufs-4.4-modular.patch @@ -1,22 +1,25 @@ fs/aufs/Kconfig | 2 +- fs/dcache.c | 1 + - fs/file_table.c | 2 ++ - fs/inode.c | 1 + + fs/exec.c | 1 + + fs/fcntl.c | 1 + + fs/file_table.c | 4 ++++ fs/namespace.c | 2 ++ fs/notify/group.c | 4 ++++ fs/notify/mark.c | 4 ++++ fs/open.c | 2 ++ fs/read_write.c | 2 ++ fs/splice.c | 2 ++ + fs/xattr.c | 1 + + kernel/task_work.c | 1 + security/commoncap.c | 2 ++ security/device_cgroup.c | 2 ++ security/security.c | 10 ++++++++++ - 13 files changed, 35 insertions(+), 1 deletion(-) + 16 files changed, 40 insertions(+), 1 deletion(-) -diff -Nurp linux-4.4-rc6.aufs/fs/aufs/Kconfig linux-4.4-rc6.aufs.mod/fs/aufs/Kconfig ---- linux-4.4-rc6.aufs/fs/aufs/Kconfig 2015-12-21 19:54:42.973923445 +0200 -+++ linux-4.4-rc6.aufs.mod/fs/aufs/Kconfig 2015-12-21 19:55:29.522275768 +0200 +diff -Nurp linux-4.4.3-aufs/fs/aufs/Kconfig linux-4.4.3-aufs-mod/fs/aufs/Kconfig +--- linux-4.4.3-aufs/fs/aufs/Kconfig 2016-03-02 17:59:37.360498681 +0200 ++++ linux-4.4.3-aufs-mod/fs/aufs/Kconfig 2016-03-03 09:50:41.232631276 +0200 @@ -1,5 +1,5 @@ config AUFS_FS - bool "Aufs (Advanced multi layered unification filesystem) support" @@ -24,9 +27,9 @@ diff -Nurp linux-4.4-rc6.aufs/fs/aufs/Kconfig linux-4.4-rc6.aufs.mod/fs/aufs/Kco help Aufs is a stackable unification filesystem such as Unionfs, which unifies several directories and provides a merged single -diff -Nurp linux-4.4-rc6.aufs/fs/dcache.c linux-4.4-rc6.aufs.mod/fs/dcache.c ---- linux-4.4-rc6.aufs/fs/dcache.c 2015-12-21 19:54:42.986923543 +0200 -+++ linux-4.4-rc6.aufs.mod/fs/dcache.c 2015-12-21 19:55:29.523275775 +0200 +diff -Nurp linux-4.4.3-aufs/fs/dcache.c linux-4.4.3-aufs-mod/fs/dcache.c +--- linux-4.4.3-aufs/fs/dcache.c 2016-03-02 17:59:37.376498796 +0200 ++++ linux-4.4.3-aufs-mod/fs/dcache.c 2016-03-03 09:50:34.633586562 +0200 @@ -1272,6 +1272,7 @@ rename_retry: seq = 1; goto again; @@ -35,39 +38,66 @@ diff -Nurp linux-4.4-rc6.aufs/fs/dcache.c linux-4.4-rc6.aufs.mod/fs/dcache.c /* * Search for at least 1 mount point in the dentry's subdirs. -diff -Nurp linux-4.4-rc6.aufs/fs/file_table.c linux-4.4-rc6.aufs.mod/fs/file_table.c ---- linux-4.4-rc6.aufs/fs/file_table.c 2015-11-02 02:05:25.000000000 +0200 -+++ linux-4.4-rc6.aufs.mod/fs/file_table.c 2015-12-21 19:55:29.523275775 +0200 +diff -Nurp linux-4.4.3-aufs/fs/exec.c linux-4.4.3-aufs-mod/fs/exec.c +--- linux-4.4.3-aufs/fs/exec.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs-mod/fs/exec.c 2016-03-03 09:50:34.633586562 +0200 +@@ -103,6 +103,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 -Nurp linux-4.4.3-aufs/fs/fcntl.c linux-4.4.3-aufs-mod/fs/fcntl.c +--- linux-4.4.3-aufs/fs/fcntl.c 2016-03-02 17:59:37.376498796 +0200 ++++ linux-4.4.3-aufs-mod/fs/fcntl.c 2016-03-03 09:50:34.633586562 +0200 +@@ -81,6 +81,7 @@ int setfl(int fd, struct file * filp, un + 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 linux-4.4.3-aufs/fs/file_table.c linux-4.4.3-aufs-mod/fs/file_table.c +--- linux-4.4.3-aufs/fs/file_table.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs-mod/fs/file_table.c 2016-03-03 09:50:34.633586562 +0200 @@ -147,6 +147,7 @@ over: } return ERR_PTR(-ENFILE); } -+EXPORT_SYMBOL(get_empty_filp); ++EXPORT_SYMBOL_GPL(get_empty_filp); /** * alloc_file - allocate and initialize a 'struct file' -@@ -308,6 +309,7 @@ void put_filp(struct file *file) +@@ -258,6 +259,7 @@ void flush_delayed_fput(void) + { + delayed_fput(NULL); + } ++EXPORT_SYMBOL_GPL(flush_delayed_fput); + + static DECLARE_DELAYED_WORK(delayed_fput_work, delayed_fput); + +@@ -300,6 +302,7 @@ void __fput_sync(struct file *file) + } + + EXPORT_SYMBOL(fput); ++EXPORT_SYMBOL_GPL(__fput_sync); + + void put_filp(struct file *file) + { +@@ -308,6 +311,7 @@ void put_filp(struct file *file) file_free(file); } } -+EXPORT_SYMBOL(put_filp); ++EXPORT_SYMBOL_GPL(put_filp); void __init files_init(void) { -diff -Nurp linux-4.4-rc6.aufs/fs/inode.c linux-4.4-rc6.aufs.mod/fs/inode.c ---- linux-4.4-rc6.aufs/fs/inode.c 2015-12-21 13:06:55.265034468 +0200 -+++ linux-4.4-rc6.aufs.mod/fs/inode.c 2015-12-21 19:55:29.524275783 +0200 -@@ -1593,6 +1593,7 @@ static int update_time(struct inode *ino - - return update_time(inode, time, flags); - } -+EXPORT_SYMBOL(update_time); - - /** - * touch_atime - update the access time -diff -Nurp linux-4.4-rc6.aufs/fs/namespace.c linux-4.4-rc6.aufs.mod/fs/namespace.c ---- linux-4.4-rc6.aufs/fs/namespace.c 2015-11-02 02:05:25.000000000 +0200 -+++ linux-4.4-rc6.aufs.mod/fs/namespace.c 2015-12-21 19:55:29.525275790 +0200 +diff -Nurp linux-4.4.3-aufs/fs/namespace.c linux-4.4.3-aufs-mod/fs/namespace.c +--- linux-4.4.3-aufs/fs/namespace.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs-mod/fs/namespace.c 2016-03-03 09:50:34.634586569 +0200 @@ -463,6 +463,7 @@ void __mnt_drop_write(struct vfsmount *m mnt_dec_writers(real_mount(mnt)); preempt_enable(); @@ -80,13 +110,13 @@ diff -Nurp linux-4.4-rc6.aufs/fs/namespace.c linux-4.4-rc6.aufs.mod/fs/namespace } return 0; } -+EXPORT_SYMBOL(iterate_mounts); ++EXPORT_SYMBOL_GPL(iterate_mounts); static void cleanup_group_ids(struct mount *mnt, struct mount *end) { -diff -Nurp linux-4.4-rc6.aufs/fs/notify/group.c linux-4.4-rc6.aufs.mod/fs/notify/group.c ---- linux-4.4-rc6.aufs/fs/notify/group.c 2015-11-02 02:05:25.000000000 +0200 -+++ linux-4.4-rc6.aufs.mod/fs/notify/group.c 2015-12-21 19:55:29.525275790 +0200 +diff -Nurp linux-4.4.3-aufs/fs/notify/group.c linux-4.4.3-aufs-mod/fs/notify/group.c +--- linux-4.4.3-aufs/fs/notify/group.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs-mod/fs/notify/group.c 2016-03-03 09:50:34.634586569 +0200 @@ -22,6 +22,7 @@ #include #include @@ -99,7 +129,7 @@ diff -Nurp linux-4.4-rc6.aufs/fs/notify/group.c linux-4.4-rc6.aufs.mod/fs/notify { atomic_inc(&group->refcnt); } -+EXPORT_SYMBOL(fsnotify_get_group); ++EXPORT_SYMBOL_GPL(fsnotify_get_group); /* * Drop a reference to a group. Free it if it's through. @@ -107,7 +137,7 @@ diff -Nurp linux-4.4-rc6.aufs/fs/notify/group.c linux-4.4-rc6.aufs.mod/fs/notify if (atomic_dec_and_test(&group->refcnt)) fsnotify_final_destroy_group(group); } -+EXPORT_SYMBOL(fsnotify_put_group); ++EXPORT_SYMBOL_GPL(fsnotify_put_group); /* * Create a new fsnotify_group and hold a reference for the group returned. @@ -115,53 +145,53 @@ diff -Nurp linux-4.4-rc6.aufs/fs/notify/group.c linux-4.4-rc6.aufs.mod/fs/notify return group; } -+EXPORT_SYMBOL(fsnotify_alloc_group); ++EXPORT_SYMBOL_GPL(fsnotify_alloc_group); int fsnotify_fasync(int fd, struct file *file, int on) { -diff -Nurp linux-4.4-rc6.aufs/fs/notify/mark.c linux-4.4-rc6.aufs.mod/fs/notify/mark.c ---- linux-4.4-rc6.aufs/fs/notify/mark.c 2015-11-02 02:05:25.000000000 +0200 -+++ linux-4.4-rc6.aufs.mod/fs/notify/mark.c 2015-12-21 19:55:29.525275790 +0200 +diff -Nurp linux-4.4.3-aufs/fs/notify/mark.c linux-4.4.3-aufs-mod/fs/notify/mark.c +--- linux-4.4.3-aufs/fs/notify/mark.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs-mod/fs/notify/mark.c 2016-03-03 09:50:34.634586569 +0200 @@ -109,6 +109,7 @@ void fsnotify_put_mark(struct fsnotify_m mark->free_mark(mark); } } -+EXPORT_SYMBOL(fsnotify_put_mark); ++EXPORT_SYMBOL_GPL(fsnotify_put_mark); /* Calculate mask of events for a list of marks */ u32 fsnotify_recalc_mask(struct hlist_head *head) -@@ -199,6 +200,7 @@ void fsnotify_free_mark(struct fsnotify_ - if (group->ops->freeing_mark) - group->ops->freeing_mark(mark, group); - } -+EXPORT_SYMBOL(fsnotify_destroy_mark); - - void fsnotify_destroy_mark(struct fsnotify_mark *mark, - struct fsnotify_group *group) -@@ -402,6 +404,7 @@ int fsnotify_add_mark(struct fsnotify_ma +@@ -208,6 +209,7 @@ void fsnotify_destroy_mark(struct fsnoti mutex_unlock(&group->mark_mutex); + fsnotify_free_mark(mark); + } ++EXPORT_SYMBOL_GPL(fsnotify_destroy_mark); + + void fsnotify_destroy_marks(struct hlist_head *head, spinlock_t *lock) + { +@@ -392,6 +394,7 @@ err: + return ret; } -+EXPORT_SYMBOL(fsnotify_add_mark); ++EXPORT_SYMBOL_GPL(fsnotify_add_mark); - /* - * Given a list of marks, find the mark associated with given group. If found + int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group, + struct inode *inode, struct vfsmount *mnt, int allow_dups) @@ -492,6 +495,7 @@ void fsnotify_init_mark(struct fsnotify_ atomic_set(&mark->refcnt, 1); mark->free_mark = free_mark; } -+EXPORT_SYMBOL(fsnotify_init_mark); ++EXPORT_SYMBOL_GPL(fsnotify_init_mark); static int fsnotify_mark_destroy(void *ignored) { -diff -Nurp linux-4.4-rc6.aufs/fs/open.c linux-4.4-rc6.aufs.mod/fs/open.c ---- linux-4.4-rc6.aufs/fs/open.c 2015-11-02 02:05:25.000000000 +0200 -+++ linux-4.4-rc6.aufs.mod/fs/open.c 2015-12-21 19:55:29.526275798 +0200 +diff -Nurp linux-4.4.3-aufs/fs/open.c linux-4.4.3-aufs-mod/fs/open.c +--- linux-4.4.3-aufs/fs/open.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs-mod/fs/open.c 2016-03-03 09:50:34.634586569 +0200 @@ -64,6 +64,7 @@ int do_truncate(struct dentry *dentry, l mutex_unlock(&dentry->d_inode->i_mutex); return ret; } -+EXPORT_SYMBOL(do_truncate); ++EXPORT_SYMBOL_GPL(do_truncate); long vfs_truncate(struct path *path, loff_t length) { @@ -169,18 +199,18 @@ diff -Nurp linux-4.4-rc6.aufs/fs/open.c linux-4.4-rc6.aufs.mod/fs/open.c } return 0; } -+EXPORT_SYMBOL(open_check_o_direct); ++EXPORT_SYMBOL_GPL(open_check_o_direct); static int do_dentry_open(struct file *f, struct inode *inode, -diff -Nurp linux-4.4-rc6.aufs/fs/read_write.c linux-4.4-rc6.aufs.mod/fs/read_write.c ---- linux-4.4-rc6.aufs/fs/read_write.c 2015-12-21 19:54:42.987923551 +0200 -+++ linux-4.4-rc6.aufs.mod/fs/read_write.c 2015-12-21 19:55:29.526275798 +0200 +diff -Nurp linux-4.4.3-aufs/fs/read_write.c linux-4.4.3-aufs-mod/fs/read_write.c +--- linux-4.4.3-aufs/fs/read_write.c 2016-03-02 17:59:37.377498803 +0200 ++++ linux-4.4.3-aufs-mod/fs/read_write.c 2016-03-03 09:50:34.634586569 +0200 @@ -504,6 +504,7 @@ vfs_readf_t vfs_readf(struct file *file) return new_sync_read; return ERR_PTR(-ENOSYS); } -+EXPORT_SYMBOL(vfs_readf); ++EXPORT_SYMBOL_GPL(vfs_readf); vfs_writef_t vfs_writef(struct file *file) { @@ -188,18 +218,18 @@ diff -Nurp linux-4.4-rc6.aufs/fs/read_write.c linux-4.4-rc6.aufs.mod/fs/read_wri return new_sync_write; return ERR_PTR(-ENOSYS); } -+EXPORT_SYMBOL(vfs_writef); ++EXPORT_SYMBOL_GPL(vfs_writef); ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos) { -diff -Nurp linux-4.4-rc6.aufs/fs/splice.c linux-4.4-rc6.aufs.mod/fs/splice.c ---- linux-4.4-rc6.aufs/fs/splice.c 2015-12-21 19:54:42.987923551 +0200 -+++ linux-4.4-rc6.aufs.mod/fs/splice.c 2015-12-21 19:55:29.526275798 +0200 +diff -Nurp linux-4.4.3-aufs/fs/splice.c linux-4.4.3-aufs-mod/fs/splice.c +--- linux-4.4.3-aufs/fs/splice.c 2016-03-02 17:59:37.377498803 +0200 ++++ linux-4.4.3-aufs-mod/fs/splice.c 2016-03-03 09:50:34.635586575 +0200 @@ -1123,6 +1123,7 @@ long do_splice_from(struct pipe_inode_in return splice_write(pipe, out, ppos, len, flags); } -+EXPORT_SYMBOL(do_splice_from); ++EXPORT_SYMBOL_GPL(do_splice_from); /* * Attempt to initiate a splice from a file to a pipe. @@ -207,31 +237,50 @@ diff -Nurp linux-4.4-rc6.aufs/fs/splice.c linux-4.4-rc6.aufs.mod/fs/splice.c return splice_read(in, ppos, pipe, len, flags); } -+EXPORT_SYMBOL(do_splice_to); ++EXPORT_SYMBOL_GPL(do_splice_to); /** * splice_direct_to_actor - splices data directly between two non-pipes -diff -Nurp linux-4.4-rc6.aufs/security/commoncap.c linux-4.4-rc6.aufs.mod/security/commoncap.c ---- linux-4.4-rc6.aufs/security/commoncap.c 2015-11-02 02:05:25.000000000 +0200 -+++ linux-4.4-rc6.aufs.mod/security/commoncap.c 2015-12-21 19:55:29.527275805 +0200 -@@ -1053,12 +1053,14 @@ int cap_mmap_addr(unsigned long addr) +diff -Nurp linux-4.4.3-aufs/fs/xattr.c linux-4.4.3-aufs-mod/fs/xattr.c +--- linux-4.4.3-aufs/fs/xattr.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs-mod/fs/xattr.c 2016-03-03 09:50:34.635586575 +0200 +@@ -207,6 +207,7 @@ vfs_getxattr_alloc(struct dentry *dentry + *xattr_value = value; + return error; + } ++EXPORT_SYMBOL_GPL(vfs_getxattr_alloc); + + /* Compare an extended attribute value with the given value */ + int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name, +diff -Nurp linux-4.4.3-aufs/kernel/task_work.c linux-4.4.3-aufs-mod/kernel/task_work.c +--- linux-4.4.3-aufs/kernel/task_work.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs-mod/kernel/task_work.c 2016-03-03 09:50:34.635586575 +0200 +@@ -118,3 +118,4 @@ void task_work_run(void) + } while (work); + } + } ++EXPORT_SYMBOL_GPL(task_work_run); +diff -Nurp linux-4.4.3-aufs/security/commoncap.c linux-4.4.3-aufs-mod/security/commoncap.c +--- linux-4.4.3-aufs/security/commoncap.c 2016-03-02 17:42:59.463713410 +0200 ++++ linux-4.4.3-aufs-mod/security/commoncap.c 2016-03-03 09:50:34.635586575 +0200 +@@ -1058,12 +1058,14 @@ int cap_mmap_addr(unsigned long addr) } return ret; } -+EXPORT_SYMBOL(cap_mmap_addr); ++EXPORT_SYMBOL_GPL(cap_mmap_addr); int cap_mmap_file(struct file *file, unsigned long reqprot, unsigned long prot, unsigned long flags) { return 0; } -+EXPORT_SYMBOL(cap_mmap_file); ++EXPORT_SYMBOL_GPL(cap_mmap_file); #ifdef CONFIG_SECURITY -diff -Nurp linux-4.4-rc6.aufs/security/device_cgroup.c linux-4.4-rc6.aufs.mod/security/device_cgroup.c ---- linux-4.4-rc6.aufs/security/device_cgroup.c 2015-11-02 02:05:25.000000000 +0200 -+++ linux-4.4-rc6.aufs.mod/security/device_cgroup.c 2015-12-21 19:55:29.527275805 +0200 +diff -Nurp linux-4.4.3-aufs/security/device_cgroup.c linux-4.4.3-aufs-mod/security/device_cgroup.c +--- linux-4.4.3-aufs/security/device_cgroup.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs-mod/security/device_cgroup.c 2016-03-03 09:50:34.635586575 +0200 @@ -7,6 +7,7 @@ #include #include @@ -244,18 +293,18 @@ diff -Nurp linux-4.4-rc6.aufs/security/device_cgroup.c linux-4.4-rc6.aufs.mod/se return __devcgroup_check_permission(type, imajor(inode), iminor(inode), access); } -+EXPORT_SYMBOL(__devcgroup_inode_permission); ++EXPORT_SYMBOL_GPL(__devcgroup_inode_permission); int devcgroup_inode_mknod(int mode, dev_t dev) { -diff -Nurp linux-4.4-rc6.aufs/security/security.c linux-4.4-rc6.aufs.mod/security/security.c ---- linux-4.4-rc6.aufs/security/security.c 2015-11-02 02:05:25.000000000 +0200 -+++ linux-4.4-rc6.aufs.mod/security/security.c 2015-12-21 19:55:29.528275813 +0200 +diff -Nurp linux-4.4.3-aufs/security/security.c linux-4.4.3-aufs-mod/security/security.c +--- linux-4.4.3-aufs/security/security.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs-mod/security/security.c 2016-03-03 09:50:34.636586582 +0200 @@ -433,6 +433,7 @@ int security_path_rmdir(struct path *dir return 0; return call_int_hook(path_rmdir, 0, dir, dentry); } -+EXPORT_SYMBOL(security_path_rmdir); ++EXPORT_SYMBOL_GPL(security_path_rmdir); int security_path_unlink(struct path *dir, struct dentry *dentry) { @@ -263,7 +312,7 @@ diff -Nurp linux-4.4-rc6.aufs/security/security.c linux-4.4-rc6.aufs.mod/securit return 0; return call_int_hook(path_symlink, 0, dir, dentry, old_name); } -+EXPORT_SYMBOL(security_path_symlink); ++EXPORT_SYMBOL_GPL(security_path_symlink); int security_path_link(struct dentry *old_dentry, struct path *new_dir, struct dentry *new_dentry) @@ -271,7 +320,7 @@ diff -Nurp linux-4.4-rc6.aufs/security/security.c linux-4.4-rc6.aufs.mod/securit return 0; return call_int_hook(path_link, 0, old_dentry, new_dir, new_dentry); } -+EXPORT_SYMBOL(security_path_link); ++EXPORT_SYMBOL_GPL(security_path_link); int security_path_rename(struct path *old_dir, struct dentry *old_dentry, struct path *new_dir, struct dentry *new_dentry, @@ -279,7 +328,7 @@ diff -Nurp linux-4.4-rc6.aufs/security/security.c linux-4.4-rc6.aufs.mod/securit return 0; return call_int_hook(path_truncate, 0, path); } -+EXPORT_SYMBOL(security_path_truncate); ++EXPORT_SYMBOL_GPL(security_path_truncate); int security_path_chmod(struct path *path, umode_t mode) { @@ -287,7 +336,7 @@ diff -Nurp linux-4.4-rc6.aufs/security/security.c linux-4.4-rc6.aufs.mod/securit return 0; return call_int_hook(path_chmod, 0, path, mode); } -+EXPORT_SYMBOL(security_path_chmod); ++EXPORT_SYMBOL_GPL(security_path_chmod); int security_path_chown(struct path *path, kuid_t uid, kgid_t gid) { @@ -295,7 +344,7 @@ diff -Nurp linux-4.4-rc6.aufs/security/security.c linux-4.4-rc6.aufs.mod/securit return 0; return call_int_hook(path_chown, 0, path, uid, gid); } -+EXPORT_SYMBOL(security_path_chown); ++EXPORT_SYMBOL_GPL(security_path_chown); int security_path_chroot(struct path *path) { @@ -303,7 +352,7 @@ diff -Nurp linux-4.4-rc6.aufs/security/security.c linux-4.4-rc6.aufs.mod/securit return 0; return call_int_hook(inode_readlink, 0, dentry); } -+EXPORT_SYMBOL(security_inode_readlink); ++EXPORT_SYMBOL_GPL(security_inode_readlink); int security_inode_follow_link(struct dentry *dentry, struct inode *inode, bool rcu) @@ -311,7 +360,7 @@ diff -Nurp linux-4.4-rc6.aufs/security/security.c linux-4.4-rc6.aufs.mod/securit return 0; return call_int_hook(inode_permission, 0, inode, mask); } -+EXPORT_SYMBOL(security_inode_permission); ++EXPORT_SYMBOL_GPL(security_inode_permission); int security_inode_setattr(struct dentry *dentry, struct iattr *attr) { @@ -319,7 +368,7 @@ diff -Nurp linux-4.4-rc6.aufs/security/security.c linux-4.4-rc6.aufs.mod/securit return fsnotify_perm(file, mask); } -+EXPORT_SYMBOL(security_file_permission); ++EXPORT_SYMBOL_GPL(security_file_permission); int security_file_alloc(struct file *file) { @@ -327,7 +376,7 @@ diff -Nurp linux-4.4-rc6.aufs/security/security.c linux-4.4-rc6.aufs.mod/securit return ret; return ima_file_mmap(file, prot); } -+EXPORT_SYMBOL(security_mmap_file); ++EXPORT_SYMBOL_GPL(security_mmap_file); int security_mmap_addr(unsigned long addr) { diff --git a/kernel/kernel/files/patches/mageia/fs-aufs-4.4.patch b/kernel/kernel/files/patches/mageia/fs-aufs-4.4.patch index dde11710..fc6f4fdc 100644 --- a/kernel/kernel/files/patches/mageia/fs-aufs-4.4.patch +++ b/kernel/kernel/files/patches/mageia/fs-aufs-4.4.patch @@ -1,120 +1,120 @@ - Documentation/ABI/testing/debugfs-aufs | 50 + - Documentation/ABI/testing/sysfs-aufs | 31 + - Documentation/filesystems/aufs/README | 383 ++++ - Documentation/filesystems/aufs/design/01intro.txt | 157 ++ - Documentation/filesystems/aufs/design/02struct.txt | 245 +++ - .../filesystems/aufs/design/03atomic_open.txt | 72 + - Documentation/filesystems/aufs/design/03lookup.txt | 100 ++ - Documentation/filesystems/aufs/design/04branch.txt | 61 + - .../filesystems/aufs/design/05wbr_policy.txt | 51 + - Documentation/filesystems/aufs/design/06fhsm.txt | 105 ++ - Documentation/filesystems/aufs/design/06mmap.txt | 59 + - Documentation/filesystems/aufs/design/06xattr.txt | 81 + - Documentation/filesystems/aufs/design/07export.txt | 45 + - Documentation/filesystems/aufs/design/08shwh.txt | 39 + - Documentation/filesystems/aufs/design/10dynop.txt | 34 + - MAINTAINERS | 13 + - drivers/block/loop.c | 18 + - fs/Kconfig | 1 + - fs/Makefile | 1 + - fs/aufs/Kconfig | 185 ++ - fs/aufs/Makefile | 36 + - fs/aufs/aufs.h | 46 + - fs/aufs/branch.c | 1394 +++++++++++++++ - fs/aufs/branch.h | 266 +++ - fs/aufs/cpup.c | 1306 ++++++++++++++ - fs/aufs/cpup.h | 81 + - fs/aufs/dbgaufs.c | 419 +++++ - fs/aufs/dbgaufs.h | 35 + - fs/aufs/dcsub.c | 211 +++ - fs/aufs/dcsub.h | 123 ++ - fs/aufs/debug.c | 425 +++++ - fs/aufs/debug.h | 212 +++ - fs/aufs/dentry.c | 1123 ++++++++++++ - fs/aufs/dentry.h | 221 +++ - fs/aufs/dinfo.c | 537 ++++++ - fs/aufs/dir.c | 740 ++++++++ - fs/aufs/dir.h | 118 ++ - fs/aufs/dynop.c | 356 ++++ - fs/aufs/dynop.h | 61 + - fs/aufs/export.c | 819 +++++++++ - fs/aufs/f_op.c | 725 ++++++++ - fs/aufs/fhsm.c | 412 +++++ - fs/aufs/file.c | 831 +++++++++ - fs/aufs/file.h | 278 +++ - fs/aufs/finfo.c | 143 ++ - fs/aufs/fstype.h | 387 ++++ - fs/aufs/hfsnotify.c | 275 +++ - fs/aufs/hfsplus.c | 43 + - fs/aufs/hnotify.c | 697 ++++++++ - fs/aufs/i_op.c | 1471 ++++++++++++++++ - fs/aufs/i_op_add.c | 919 ++++++++++ - fs/aufs/i_op_del.c | 497 ++++++ - fs/aufs/i_op_ren.c | 1002 +++++++++++ - fs/aufs/iinfo.c | 264 +++ - fs/aufs/inode.c | 515 ++++++ - fs/aufs/inode.h | 672 +++++++ - fs/aufs/ioctl.c | 206 +++ - fs/aufs/loop.c | 133 ++ - fs/aufs/loop.h | 39 + - fs/aufs/magic.mk | 30 + - fs/aufs/module.c | 207 +++ - fs/aufs/module.h | 91 + - fs/aufs/mvdown.c | 690 ++++++++ - fs/aufs/opts.c | 1846 ++++++++++++++++++++ - fs/aufs/opts.h | 198 +++ - fs/aufs/plink.c | 515 ++++++ - fs/aufs/poll.c | 39 + - fs/aufs/posix_acl.c | 86 + - fs/aufs/procfs.c | 156 ++ - fs/aufs/rdu.c | 375 ++++ - fs/aufs/rwsem.h | 178 ++ - fs/aufs/sbinfo.c | 353 ++++ - fs/aufs/spl.h | 98 ++ - fs/aufs/super.c | 1026 +++++++++++ - fs/aufs/super.h | 628 +++++++ - fs/aufs/sysaufs.c | 91 + - fs/aufs/sysaufs.h | 88 + - fs/aufs/sysfs.c | 340 ++++ - fs/aufs/sysrq.c | 144 ++ - fs/aufs/vdir.c | 875 ++++++++++ - fs/aufs/vfsub.c | 835 +++++++++ - fs/aufs/vfsub.h | 274 +++ - fs/aufs/wbr_policy.c | 752 ++++++++ - fs/aufs/whout.c | 1047 +++++++++++ - fs/aufs/whout.h | 72 + - fs/aufs/wkq.c | 200 +++ - fs/aufs/wkq.h | 78 + - fs/aufs/xattr.c | 331 ++++ - fs/aufs/xino.c | 1283 ++++++++++++++ - fs/dcache.c | 2 +- - fs/proc/base.c | 2 +- - fs/proc/nommu.c | 5 +- - fs/proc/task_mmu.c | 7 +- - fs/proc/task_nommu.c | 5 +- - fs/read_write.c | 22 + - fs/splice.c | 10 +- - include/linux/file.h | 1 + - include/linux/fs.h | 6 + - include/linux/mm.h | 22 + - include/linux/mm_types.h | 2 + - include/linux/splice.h | 6 + - include/uapi/linux/Kbuild | 1 + - include/uapi/linux/aufs_type.h | 406 +++++ - kernel/fork.c | 2 +- - mm/Makefile | 2 +- - mm/filemap.c | 2 +- - mm/memory.c | 2 +- - mm/mmap.c | 17 +- - mm/nommu.c | 10 +- - mm/prfile.c | 86 + - 110 files changed, 33284 insertions(+), 29 deletions(-) -diff --git a/Documentation/ABI/testing/debugfs-aufs b/Documentation/ABI/testing/debugfs-aufs -new file mode 100644 -index 0000000..99642d1 ---- /dev/null -+++ b/Documentation/ABI/testing/debugfs-aufs + Documentation/ABI/testing/debugfs-aufs | 50 + Documentation/ABI/testing/sysfs-aufs | 31 + Documentation/filesystems/aufs/README | 391 +++ + Documentation/filesystems/aufs/design/01intro.txt | 157 + + Documentation/filesystems/aufs/design/02struct.txt | 245 ++ + Documentation/filesystems/aufs/design/03atomic_open.txt | 72 + Documentation/filesystems/aufs/design/03lookup.txt | 100 + Documentation/filesystems/aufs/design/04branch.txt | 61 + Documentation/filesystems/aufs/design/05wbr_policy.txt | 51 + Documentation/filesystems/aufs/design/06fhsm.txt | 105 + Documentation/filesystems/aufs/design/06mmap.txt | 59 + Documentation/filesystems/aufs/design/06xattr.txt | 81 + Documentation/filesystems/aufs/design/07export.txt | 45 + Documentation/filesystems/aufs/design/08shwh.txt | 39 + Documentation/filesystems/aufs/design/10dynop.txt | 34 + MAINTAINERS | 13 + drivers/block/loop.c | 18 + fs/Kconfig | 1 + fs/Makefile | 1 + fs/aufs/Kconfig | 185 + + fs/aufs/Makefile | 36 + fs/aufs/aufs.h | 46 + fs/aufs/branch.c | 1394 ++++++++++++ + fs/aufs/branch.h | 266 ++ + fs/aufs/cpup.c | 1366 +++++++++++ + fs/aufs/cpup.h | 81 + fs/aufs/dbgaufs.c | 419 +++ + fs/aufs/dbgaufs.h | 35 + fs/aufs/dcsub.c | 211 + + fs/aufs/dcsub.h | 123 + + fs/aufs/debug.c | 425 +++ + fs/aufs/debug.h | 212 + + fs/aufs/dentry.c | 1123 +++++++++ + fs/aufs/dentry.h | 221 + + fs/aufs/dinfo.c | 537 ++++ + fs/aufs/dir.c | 745 ++++++ + fs/aufs/dir.h | 118 + + fs/aufs/dynop.c | 356 +++ + fs/aufs/dynop.h | 61 + fs/aufs/export.c | 819 +++++++ + fs/aufs/f_op.c | 759 ++++++ + fs/aufs/fhsm.c | 412 +++ + fs/aufs/file.c | 831 +++++++ + fs/aufs/file.h | 278 ++ + fs/aufs/finfo.c | 143 + + fs/aufs/fstype.h | 387 +++ + fs/aufs/hfsnotify.c | 275 ++ + fs/aufs/hfsplus.c | 43 + fs/aufs/hnotify.c | 697 ++++++ + fs/aufs/i_op.c | 1477 ++++++++++++ + fs/aufs/i_op_add.c | 919 +++++++ + fs/aufs/i_op_del.c | 497 ++++ + fs/aufs/i_op_ren.c | 1002 ++++++++ + fs/aufs/iinfo.c | 264 ++ + fs/aufs/inode.c | 514 ++++ + fs/aufs/inode.h | 672 +++++ + fs/aufs/ioctl.c | 206 + + fs/aufs/loop.c | 133 + + fs/aufs/loop.h | 39 + fs/aufs/magic.mk | 30 + fs/aufs/module.c | 207 + + fs/aufs/module.h | 92 + fs/aufs/mvdown.c | 690 +++++ + fs/aufs/opts.c | 1846 ++++++++++++++++ + fs/aufs/opts.h | 198 + + fs/aufs/plink.c | 515 ++++ + fs/aufs/poll.c | 39 + fs/aufs/posix_acl.c | 85 + fs/aufs/procfs.c | 156 + + fs/aufs/rdu.c | 375 +++ + fs/aufs/rwsem.h | 178 + + fs/aufs/sbinfo.c | 353 +++ + fs/aufs/spl.h | 98 + fs/aufs/super.c | 1026 ++++++++ + fs/aufs/super.h | 628 +++++ + fs/aufs/sysaufs.c | 91 + fs/aufs/sysaufs.h | 88 + fs/aufs/sysfs.c | 340 ++ + fs/aufs/sysrq.c | 144 + + fs/aufs/vdir.c | 875 +++++++ + fs/aufs/vfsub.c | 853 +++++++ + fs/aufs/vfsub.h | 295 ++ + fs/aufs/wbr_policy.c | 752 ++++++ + fs/aufs/whout.c | 1047 +++++++++ + fs/aufs/whout.h | 72 + fs/aufs/wkq.c | 200 + + fs/aufs/wkq.h | 78 + fs/aufs/xattr.c | 331 ++ + fs/aufs/xino.c | 1305 +++++++++++ + fs/dcache.c | 2 + fs/fcntl.c | 4 + fs/proc/base.c | 2 + fs/proc/nommu.c | 5 + fs/proc/task_mmu.c | 7 + fs/proc/task_nommu.c | 5 + fs/read_write.c | 22 + fs/splice.c | 10 + include/linux/file.h | 1 + include/linux/fs.h | 8 + include/linux/mm.h | 22 + include/linux/mm_types.h | 2 + include/linux/splice.h | 6 + include/uapi/linux/Kbuild | 1 + include/uapi/linux/aufs_type.h | 406 +++ + kernel/fork.c | 2 + mm/Makefile | 2 + mm/filemap.c | 2 + mm/memory.c | 2 + mm/mmap.c | 17 + mm/nommu.c | 10 + mm/prfile.c | 86 + 111 files changed, 33462 insertions(+), 30 deletions(-) + +diff -Nurp linux-4.4.3/Documentation/ABI/testing/debugfs-aufs linux-4.4.3-aufs/Documentation/ABI/testing/debugfs-aufs +--- linux-4.4.3/Documentation/ABI/testing/debugfs-aufs 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/Documentation/ABI/testing/debugfs-aufs 2016-03-02 17:59:37.356498653 +0200 @@ -0,0 +1,50 @@ +What: /debug/aufs/si_/ +Date: March 2009 @@ -166,11 +166,9 @@ index 0000000..99642d1 + be created. + When the aufs mount option 'noxino' is specified, it + will be empty. About XINO files, see the aufs manual. -diff --git a/Documentation/ABI/testing/sysfs-aufs b/Documentation/ABI/testing/sysfs-aufs -new file mode 100644 -index 0000000..82f9518 ---- /dev/null -+++ b/Documentation/ABI/testing/sysfs-aufs +diff -Nurp linux-4.4.3/Documentation/ABI/testing/sysfs-aufs linux-4.4.3-aufs/Documentation/ABI/testing/sysfs-aufs +--- linux-4.4.3/Documentation/ABI/testing/sysfs-aufs 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/Documentation/ABI/testing/sysfs-aufs 2016-03-02 17:59:37.356498653 +0200 @@ -0,0 +1,31 @@ +What: /sys/fs/aufs/si_/ +Date: March 2009 @@ -203,403 +201,12 @@ index 0000000..82f9518 + 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 --git a/Documentation/filesystems/aufs/README b/Documentation/filesystems/aufs/README -new file mode 100644 -index 0000000..2915102 ---- /dev/null -+++ b/Documentation/filesystems/aufs/README -@@ -0,0 +1,383 @@ -+ -+Aufs4 -- advanced multi layered unification filesystem version 4.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 becomes totally different from -+Unionfs while keeping the basic features. -+Recently, Unionfs Version 2.x series begin taking some of the same -+approaches to aufs1's. -+Unionfs is being developed by Professor Erez Zadok at Stony Brook -+University and his team. -+ -+Aufs4 supports linux-4.0 and later, and for linux-3.x series try aufs3. -+If you want older kernel version support, try aufs2-2.6.git or -+aufs2-standalone.git repository, 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 aufs4. -+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 aufs4, aufs4-linux.git, -+aufs4-standalone.git, and aufs-util.git. Note that there is no "4" in -+"aufs-util.git." -+While the aufs-util is always necessary, you need either of aufs4-linux -+or aufs4-standalone. -+ -+The aufs4-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 aufs4 as an external kernel module. -+Several extra patches are not included in this tree. Only -+aufs4-standalone tree contains them. They are describe in the later -+section "Configuration and Compilation." -+ -+On the other hand, the aufs4-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 "aufs4.x" where "x" -+represents the linux kernel version, "linux-4.x". For instance, -+"aufs4.0" is for linux-4.0. For latest "linux-4.x-rcN", use -+"aufs4.x-rcN" branch. -+ -+o aufs4-linux tree -+$ git clone --reference /your/linux/git/tree \ -+ git://github.com/sfjro/aufs4-linux.git aufs4-linux.git -+- if you don't have linux GIT tree, then remove "--reference ..." -+$ cd aufs4-linux.git -+$ git checkout origin/aufs4.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 aufs4 git://github.com/sfjro/aufs4-linux.git -+$ git fetch aufs4 -+$ git checkout -b my4.0 v4.0 -+$ (add your local change...) -+$ git pull aufs4 aufs4.0 -+- now you have v4.0 + your_changes + aufs4.0 in you my4.0 branch. -+- you may need to solve some conflicts between your_changes and -+ aufs4.0. in this case, git-rerere is recommended so that you can -+ solve the similar conflicts automatically when you upgrade to 4.1 or -+ later in the future. -+ -+o aufs4-standalone tree -+$ git clone git://github.com/sfjro/aufs4-standalone.git aufs4-standalone.git -+$ cd aufs4-standalone.git -+$ git checkout origin/aufs4.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/aufs4.0 -+ -+Note: The 4.x-rcN branch is to be used with `rc' kernel versions ONLY. -+The minor version number, 'x' in '4.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-4.10" and the "aufs4.10" branch -+does not exist in aufs-util repository, then "aufs4.9", "aufs4.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 aufs4-linux tree, -+- enable CONFIG_AUFS_FS. -+- set other aufs configurations if necessary. -+ -+For aufs4-standalone tree, -+There are several ways to build. -+ -+1. -+- apply ./aufs4-kbuild.patch to your kernel source files. -+- apply ./aufs4-base.patch too. -+- apply ./aufs4-mmap.patch too. -+- apply ./aufs4-standalone.patch too, if you have a plan to set -+ CONFIG_AUFS_FS=m. otherwise you don't need ./aufs4-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. -+ Note: Since linux-3.9, every filesystem module requires an alias -+ "fs-". You should make sure that "fs-aufs" is listed in your -+ modules.aliases file if you set CONFIG_AUFS_FS=m. -+- 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 ./aufs4-base.patch to your kernel source files. -+- apply ./aufs4-mmap.patch too. -+- apply ./aufs4-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". -+ Note: Since linux-3.9, every filesystem module requires an alias -+ "fs-". You should make sure that "fs-aufs" is listed in your -+ modules.aliases file. -+- 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 aufs4-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 aufs4-standalone.git. They are all -+optional. When you meet some problems, they will help you. -+- aufs4-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) -+- 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 and 2015/7). -+Stefano Di Biase made a donation (2014/8). -+Daniel Epellei made a donation (2015/1). -+ -+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 --git a/Documentation/filesystems/aufs/design/01intro.txt b/Documentation/filesystems/aufs/design/01intro.txt -new file mode 100644 -index 0000000..02a8c7b ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/01intro.txt +diff -Nurp linux-4.4.3/Documentation/filesystems/aufs/design/01intro.txt linux-4.4.3-aufs/Documentation/filesystems/aufs/design/01intro.txt +--- linux-4.4.3/Documentation/filesystems/aufs/design/01intro.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/Documentation/filesystems/aufs/design/01intro.txt 2016-03-02 17:59:37.357498660 +0200 @@ -0,0 +1,157 @@ + -+# Copyright (C) 2005-2015 Junjiro R. Okajima ++# Copyright (C) 2005-2016 Junjiro R. Okajima + +Introduction +---------------------------------------- @@ -755,14 +362,12 @@ index 0000000..02a8c7b +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 --git a/Documentation/filesystems/aufs/design/02struct.txt b/Documentation/filesystems/aufs/design/02struct.txt -new file mode 100644 -index 0000000..1a5e5d0 ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/02struct.txt +diff -Nurp linux-4.4.3/Documentation/filesystems/aufs/design/02struct.txt linux-4.4.3-aufs/Documentation/filesystems/aufs/design/02struct.txt +--- linux-4.4.3/Documentation/filesystems/aufs/design/02struct.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/Documentation/filesystems/aufs/design/02struct.txt 2016-03-02 17:59:37.357498660 +0200 @@ -0,0 +1,245 @@ + -+# Copyright (C) 2005-2015 Junjiro R. Okajima ++# Copyright (C) 2005-2016 Junjiro R. Okajima + +Basic Aufs Internal Structure + @@ -1006,14 +611,12 @@ index 0000000..1a5e5d0 +- etc. + +For this purpose, use "aumvdown" command in aufs-util.git. -diff --git a/Documentation/filesystems/aufs/design/03atomic_open.txt b/Documentation/filesystems/aufs/design/03atomic_open.txt -new file mode 100644 -index 0000000..d2c9834 ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/03atomic_open.txt +diff -Nurp linux-4.4.3/Documentation/filesystems/aufs/design/03atomic_open.txt linux-4.4.3-aufs/Documentation/filesystems/aufs/design/03atomic_open.txt +--- linux-4.4.3/Documentation/filesystems/aufs/design/03atomic_open.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/Documentation/filesystems/aufs/design/03atomic_open.txt 2016-03-02 17:59:37.357498660 +0200 @@ -0,0 +1,72 @@ + -+# Copyright (C) 2015 Junjiro R. Okajima ++# Copyright (C) 2015-2016 Junjiro R. Okajima + +Support for a branch who has its ->atomic_open() +---------------------------------------------------------------------- @@ -1084,14 +687,12 @@ index 0000000..d2c9834 + ->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 --git a/Documentation/filesystems/aufs/design/03lookup.txt b/Documentation/filesystems/aufs/design/03lookup.txt -new file mode 100644 -index 0000000..7adf4cc ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/03lookup.txt +diff -Nurp linux-4.4.3/Documentation/filesystems/aufs/design/03lookup.txt linux-4.4.3-aufs/Documentation/filesystems/aufs/design/03lookup.txt +--- linux-4.4.3/Documentation/filesystems/aufs/design/03lookup.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/Documentation/filesystems/aufs/design/03lookup.txt 2016-03-02 17:59:37.358498667 +0200 @@ -0,0 +1,100 @@ + -+# Copyright (C) 2005-2015 Junjiro R. Okajima ++# Copyright (C) 2005-2016 Junjiro R. Okajima + +Lookup in a Branch +---------------------------------------------------------------------- @@ -1190,14 +791,12 @@ index 0000000..7adf4cc + 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 --git a/Documentation/filesystems/aufs/design/04branch.txt b/Documentation/filesystems/aufs/design/04branch.txt -new file mode 100644 -index 0000000..1d11dbe ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/04branch.txt +diff -Nurp linux-4.4.3/Documentation/filesystems/aufs/design/04branch.txt linux-4.4.3-aufs/Documentation/filesystems/aufs/design/04branch.txt +--- linux-4.4.3/Documentation/filesystems/aufs/design/04branch.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/Documentation/filesystems/aufs/design/04branch.txt 2016-03-02 17:59:37.358498667 +0200 @@ -0,0 +1,61 @@ + -+# Copyright (C) 2005-2015 Junjiro R. Okajima ++# Copyright (C) 2005-2016 Junjiro R. Okajima + +Branch Manipulation + @@ -1257,14 +856,12 @@ index 0000000..1d11dbe + - 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 --git a/Documentation/filesystems/aufs/design/05wbr_policy.txt b/Documentation/filesystems/aufs/design/05wbr_policy.txt -new file mode 100644 -index 0000000..0419a90 ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/05wbr_policy.txt +diff -Nurp linux-4.4.3/Documentation/filesystems/aufs/design/05wbr_policy.txt linux-4.4.3-aufs/Documentation/filesystems/aufs/design/05wbr_policy.txt +--- linux-4.4.3/Documentation/filesystems/aufs/design/05wbr_policy.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/Documentation/filesystems/aufs/design/05wbr_policy.txt 2016-03-02 17:59:37.358498667 +0200 @@ -0,0 +1,51 @@ + -+# Copyright (C) 2005-2015 Junjiro R. Okajima ++# Copyright (C) 2005-2016 Junjiro R. Okajima + +Policies to Select One among Multiple Writable Branches +---------------------------------------------------------------------- @@ -1314,14 +911,12 @@ index 0000000..0419a90 + 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 --git a/Documentation/filesystems/aufs/design/06fhsm.txt b/Documentation/filesystems/aufs/design/06fhsm.txt -new file mode 100644 -index 0000000..0eb7a82 ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/06fhsm.txt +diff -Nurp linux-4.4.3/Documentation/filesystems/aufs/design/06fhsm.txt linux-4.4.3-aufs/Documentation/filesystems/aufs/design/06fhsm.txt +--- linux-4.4.3/Documentation/filesystems/aufs/design/06fhsm.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/Documentation/filesystems/aufs/design/06fhsm.txt 2016-03-02 17:59:37.358498667 +0200 @@ -0,0 +1,105 @@ + -+# Copyright (C) 2011-2015 Junjiro R. Okajima ++# Copyright (C) 2011-2016 Junjiro R. Okajima + +File-based Hierarchical Storage Management (FHSM) +---------------------------------------------------------------------- @@ -1425,14 +1020,12 @@ index 0000000..0eb7a82 + +And of course, in every step, an error may happen. So the operation +should restore the original file state after an error happens. -diff --git a/Documentation/filesystems/aufs/design/06mmap.txt b/Documentation/filesystems/aufs/design/06mmap.txt -new file mode 100644 -index 0000000..f22d2a1 ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/06mmap.txt +diff -Nurp linux-4.4.3/Documentation/filesystems/aufs/design/06mmap.txt linux-4.4.3-aufs/Documentation/filesystems/aufs/design/06mmap.txt +--- linux-4.4.3/Documentation/filesystems/aufs/design/06mmap.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/Documentation/filesystems/aufs/design/06mmap.txt 2016-03-02 17:59:37.358498667 +0200 @@ -0,0 +1,59 @@ + -+# Copyright (C) 2005-2015 Junjiro R. Okajima ++# Copyright (C) 2005-2016 Junjiro R. Okajima + +mmap(2) -- File Memory Mapping +---------------------------------------------------------------------- @@ -1490,14 +1083,12 @@ index 0000000..f22d2a1 + equivalent to vm_prfile described above. + +I have to give up this "looks-smater" approach. -diff --git a/Documentation/filesystems/aufs/design/06xattr.txt b/Documentation/filesystems/aufs/design/06xattr.txt -new file mode 100644 -index 0000000..ec1e68c ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/06xattr.txt +diff -Nurp linux-4.4.3/Documentation/filesystems/aufs/design/06xattr.txt linux-4.4.3-aufs/Documentation/filesystems/aufs/design/06xattr.txt +--- linux-4.4.3/Documentation/filesystems/aufs/design/06xattr.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/Documentation/filesystems/aufs/design/06xattr.txt 2016-03-02 17:59:37.358498667 +0200 @@ -0,0 +1,81 @@ + -+# Copyright (C) 2014-2015 Junjiro R. Okajima ++# Copyright (C) 2014-2016 Junjiro R. Okajima + +Listing XATTR/EA and getting the value +---------------------------------------------------------------------- @@ -1577,14 +1168,12 @@ index 0000000..ec1e68c +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 --git a/Documentation/filesystems/aufs/design/07export.txt b/Documentation/filesystems/aufs/design/07export.txt -new file mode 100644 -index 0000000..221d70c ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/07export.txt +diff -Nurp linux-4.4.3/Documentation/filesystems/aufs/design/07export.txt linux-4.4.3-aufs/Documentation/filesystems/aufs/design/07export.txt +--- linux-4.4.3/Documentation/filesystems/aufs/design/07export.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/Documentation/filesystems/aufs/design/07export.txt 2016-03-02 17:59:37.358498667 +0200 @@ -0,0 +1,45 @@ + -+# Copyright (C) 2005-2015 Junjiro R. Okajima ++# Copyright (C) 2005-2016 Junjiro R. Okajima + +Export Aufs via NFS +---------------------------------------------------------------------- @@ -1628,14 +1217,12 @@ index 0000000..221d70c + 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 --git a/Documentation/filesystems/aufs/design/08shwh.txt b/Documentation/filesystems/aufs/design/08shwh.txt -new file mode 100644 -index 0000000..181dc02 ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/08shwh.txt +diff -Nurp linux-4.4.3/Documentation/filesystems/aufs/design/08shwh.txt linux-4.4.3-aufs/Documentation/filesystems/aufs/design/08shwh.txt +--- linux-4.4.3/Documentation/filesystems/aufs/design/08shwh.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/Documentation/filesystems/aufs/design/08shwh.txt 2016-03-02 17:59:37.358498667 +0200 @@ -0,0 +1,39 @@ + -+# Copyright (C) 2005-2015 Junjiro R. Okajima ++# Copyright (C) 2005-2016 Junjiro R. Okajima + +Show Whiteout Mode (shwh) +---------------------------------------------------------------------- @@ -1673,14 +1260,12 @@ index 0000000..181dc02 + +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 --git a/Documentation/filesystems/aufs/design/10dynop.txt b/Documentation/filesystems/aufs/design/10dynop.txt -new file mode 100644 -index 0000000..9d502b5 ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/10dynop.txt +diff -Nurp linux-4.4.3/Documentation/filesystems/aufs/design/10dynop.txt linux-4.4.3-aufs/Documentation/filesystems/aufs/design/10dynop.txt +--- linux-4.4.3/Documentation/filesystems/aufs/design/10dynop.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/Documentation/filesystems/aufs/design/10dynop.txt 2016-03-02 17:59:37.359498674 +0200 @@ -0,0 +1,34 @@ + -+# Copyright (C) 2010-2015 Junjiro R. Okajima ++# Copyright (C) 2010-2016 Junjiro R. Okajima + +Dynamically customizable FS operations +---------------------------------------------------------------------- @@ -1713,35 +1298,405 @@ index 0000000..9d502b5 +XIP (DAX) mainly. +Currently this approach is applied to address_space_operations for +regular files only. -diff --git a/MAINTAINERS b/MAINTAINERS -index 9bff63c..093dd5b 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -2029,6 +2029,19 @@ F: include/linux/audit.h - F: include/uapi/linux/audit.h - F: kernel/audit* - -+AUFS (advanced multi layered unification filesystem) FILESYSTEM -+M: "J. R. Okajima" -+L: linux-unionfs@vger.kernel.org -+L: aufs-users@lists.sourceforge.net (members only) -+W: http://aufs.sourceforge.net -+T: git://github.com/sfjro/aufs4-linux.git -+S: Supported -+F: Documentation/filesystems/aufs/ -+F: Documentation/ABI/testing/debugfs-aufs -+F: Documentation/ABI/testing/sysfs-aufs -+F: fs/aufs/ -+F: include/uapi/linux/aufs_type.h +diff -Nurp linux-4.4.3/Documentation/filesystems/aufs/README linux-4.4.3-aufs/Documentation/filesystems/aufs/README +--- linux-4.4.3/Documentation/filesystems/aufs/README 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/Documentation/filesystems/aufs/README 2016-03-02 17:59:37.357498660 +0200 +@@ -0,0 +1,391 @@ + - AUXILIARY DISPLAY DRIVERS - M: Miguel Ojeda Sandonis - W: http://miguelojeda.es/auxdisplay.htm -diff --git a/drivers/block/loop.c b/drivers/block/loop.c -index 423f4ca..abfdd2b 100644 ---- a/drivers/block/loop.c -+++ b/drivers/block/loop.c -@@ -706,6 +706,24 @@ static inline int is_loop_device(struct file *file) ++Aufs4 -- advanced multi layered unification filesystem version 4.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 becomes totally different from ++Unionfs while keeping the basic features. ++Recently, Unionfs Version 2.x series begin taking some of the same ++approaches to aufs1's. ++Unionfs is being developed by Professor Erez Zadok at Stony Brook ++University and his team. ++ ++Aufs4 supports linux-4.0 and later, and for linux-3.x series try aufs3. ++If you want older kernel version support, try aufs2-2.6.git or ++aufs2-standalone.git repository, 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 aufs4. ++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 aufs4, aufs4-linux.git, ++aufs4-standalone.git, and aufs-util.git. Note that there is no "4" in ++"aufs-util.git." ++While the aufs-util is always necessary, you need either of aufs4-linux ++or aufs4-standalone. ++ ++The aufs4-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 aufs4 as an external kernel module. ++Several extra patches are not included in this tree. Only ++aufs4-standalone tree contains them. They are described in the later ++section "Configuration and Compilation." ++ ++On the other hand, the aufs4-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 "aufs4.x" where "x" ++represents the linux kernel version, "linux-4.x". For instance, ++"aufs4.0" is for linux-4.0. For latest "linux-4.x-rcN", use ++"aufs4.x-rcN" branch. ++ ++o aufs4-linux tree ++$ git clone --reference /your/linux/git/tree \ ++ git://github.com/sfjro/aufs4-linux.git aufs4-linux.git ++- if you don't have linux GIT tree, then remove "--reference ..." ++$ cd aufs4-linux.git ++$ git checkout origin/aufs4.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 aufs4 git://github.com/sfjro/aufs4-linux.git ++$ git fetch aufs4 ++$ git checkout -b my4.0 v4.0 ++$ (add your local change...) ++$ git pull aufs4 aufs4.0 ++- now you have v4.0 + your_changes + aufs4.0 in you my4.0 branch. ++- you may need to solve some conflicts between your_changes and ++ aufs4.0. in this case, git-rerere is recommended so that you can ++ solve the similar conflicts automatically when you upgrade to 4.1 or ++ later in the future. ++ ++o aufs4-standalone tree ++$ git clone git://github.com/sfjro/aufs4-standalone.git aufs4-standalone.git ++$ cd aufs4-standalone.git ++$ git checkout origin/aufs4.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/aufs4.0 ++ ++Note: The 4.x-rcN branch is to be used with `rc' kernel versions ONLY. ++The minor version number, 'x' in '4.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-4.10" and the "aufs4.10" branch ++does not exist in aufs-util repository, then "aufs4.9", "aufs4.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 aufs4-linux tree, ++- enable CONFIG_AUFS_FS. ++- set other aufs configurations if necessary. ++ ++For aufs4-standalone tree, ++There are several ways to build. ++ ++1. ++- apply ./aufs4-kbuild.patch to your kernel source files. ++- apply ./aufs4-base.patch too. ++- apply ./aufs4-mmap.patch too. ++- apply ./aufs4-standalone.patch too, if you have a plan to set ++ CONFIG_AUFS_FS=m. otherwise you don't need ./aufs4-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. ++ Note: Since linux-3.9, every filesystem module requires an alias ++ "fs-". You should make sure that "fs-aufs" is listed in your ++ modules.aliases file if you set CONFIG_AUFS_FS=m. ++- 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 ./aufs4-base.patch to your kernel source files. ++- apply ./aufs4-mmap.patch too. ++- apply ./aufs4-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". ++ Note: Since linux-3.9, every filesystem module requires an alias ++ "fs-". You should make sure that "fs-aufs" is listed in your ++ modules.aliases file. ++- 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 aufs4-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 aufs4-standalone.git. They are all ++optional. When you meet some problems, they will help you. ++- aufs4-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. ++- lockdep-debug.patch ++ 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 apply this debug patch to expand several constant values. ++ If don't know what LOCKDEP, then you don't have apply 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) ++- 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 and 2015/7). ++Stefano Di Biase made a donation (2014/8). ++Daniel Epellei made a donation (2015/1). ++OmegaPhil made a donation (2016/1). ++ ++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 -Nurp linux-4.4.3/drivers/block/loop.c linux-4.4.3-aufs/drivers/block/loop.c +--- linux-4.4.3/drivers/block/loop.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/drivers/block/loop.c 2016-03-02 17:59:37.360498681 +0200 +@@ -706,6 +706,24 @@ static inline int is_loop_device(struct return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == LOOP_MAJOR; } @@ -1761,273 +1716,17 @@ index 423f4ca..abfdd2b 100644 + } + return ret; +} -+EXPORT_SYMBOL(loop_backing_file); ++EXPORT_SYMBOL_GPL(loop_backing_file); + /* loop sysfs attributes */ static ssize_t loop_attr_show(struct device *dev, char *page, -diff --git a/fs/Kconfig b/fs/Kconfig -index 6ce72d8..4aa31ea 100644 ---- a/fs/Kconfig -+++ b/fs/Kconfig -@@ -221,6 +221,7 @@ source "fs/pstore/Kconfig" - source "fs/sysv/Kconfig" - source "fs/ufs/Kconfig" - source "fs/exofs/Kconfig" -+source "fs/aufs/Kconfig" - - endif # MISC_FILESYSTEMS - -diff --git a/fs/Makefile b/fs/Makefile -index 79f5225..a7c7f16 100644 ---- a/fs/Makefile -+++ b/fs/Makefile -@@ -126,3 +126,4 @@ obj-y += exofs/ # Multiple modules - obj-$(CONFIG_CEPH_FS) += ceph/ - obj-$(CONFIG_PSTORE) += pstore/ - obj-$(CONFIG_EFIVAR_FS) += efivarfs/ -+obj-$(CONFIG_AUFS_FS) += aufs/ -diff --git a/fs/aufs/Kconfig b/fs/aufs/Kconfig -new file mode 100644 -index 0000000..a4efb8b ---- /dev/null -+++ b/fs/aufs/Kconfig -@@ -0,0 +1,185 @@ -+config AUFS_FS -+ bool "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 = y -+ 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_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 --git a/fs/aufs/Makefile b/fs/aufs/Makefile -new file mode 100644 -index 0000000..c7efb62 ---- /dev/null -+++ b/fs/aufs/Makefile -@@ -0,0 +1,36 @@ -+ -+include ${srctree}/${src}/magic.mk -+ -+# cf. include/linux/kernel.h -+# enable pr_debug -+ccflags-y += -DDEBUG -+# sparse requires the full pathname -+ccflags-y += -include ${srctree}/include/uapi/linux/aufs_type.h -+ -+obj-$(CONFIG_AUFS_FS) += aufs.o -+aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.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_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 --git a/fs/aufs/aufs.h b/fs/aufs/aufs.h -new file mode 100644 -index 0000000..75290bd ---- /dev/null -+++ b/fs/aufs/aufs.h +diff -Nurp linux-4.4.3/fs/aufs/aufs.h linux-4.4.3-aufs/fs/aufs/aufs.h +--- linux-4.4.3/fs/aufs/aufs.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/aufs.h 2016-03-02 17:59:37.361498688 +0200 @@ -0,0 +1,46 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -2072,14 +1771,12 @@ index 0000000..75290bd + +#endif /* __KERNEL__ */ +#endif /* __AUFS_H__ */ -diff --git a/fs/aufs/branch.c b/fs/aufs/branch.c -new file mode 100644 -index 0000000..f491422 ---- /dev/null -+++ b/fs/aufs/branch.c +diff -Nurp linux-4.4.3/fs/aufs/branch.c linux-4.4.3-aufs/fs/aufs/branch.c +--- linux-4.4.3/fs/aufs/branch.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/branch.c 2016-03-02 17:59:37.361498688 +0200 @@ -0,0 +1,1394 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -3472,14 +3169,12 @@ index 0000000..f491422 + + return err; +} -diff --git a/fs/aufs/branch.h b/fs/aufs/branch.h -new file mode 100644 -index 0000000..7b9e7c9 ---- /dev/null -+++ b/fs/aufs/branch.h +diff -Nurp linux-4.4.3/fs/aufs/branch.h linux-4.4.3-aufs/fs/aufs/branch.h +--- linux-4.4.3/fs/aufs/branch.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/branch.h 2016-03-02 17:59:37.361498688 +0200 @@ -0,0 +1,266 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -3744,14 +3439,12 @@ index 0000000..7b9e7c9 + +#endif /* __KERNEL__ */ +#endif /* __AUFS_BRANCH_H__ */ -diff --git a/fs/aufs/cpup.c b/fs/aufs/cpup.c -new file mode 100644 -index 0000000..cd32274 ---- /dev/null -+++ b/fs/aufs/cpup.c -@@ -0,0 +1,1306 @@ +diff -Nurp linux-4.4.3/fs/aufs/cpup.c linux-4.4.3-aufs/fs/aufs/cpup.c +--- linux-4.4.3/fs/aufs/cpup.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/cpup.c 2016-03-02 17:59:37.362498696 +0200 +@@ -0,0 +1,1366 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -3760,6 +3453,7 @@ index 0000000..cd32274 + +#include +#include ++#include +#include "aufs.h" + +void au_cpup_attr_flags(struct inode *dst, unsigned int iflags) @@ -4132,6 +3826,7 @@ index 0000000..cd32274 + } + }; + struct super_block *sb; ++ struct task_struct *tsk = current; + + /* bsrc branch can be ro/rw. */ + sb = cpg->dentry->d_sb; @@ -4149,7 +3844,21 @@ index 0000000..cd32274 + IMustLock(d_inode(file[SRC].dentry)); + err = au_copy_file(file[DST].file, file[SRC].file, cpg->len); + -+ fput(file[DST].file); ++ /* i wonder if we had O_NO_DELAY_FPUT flag */ ++ if (tsk->flags & PF_KTHREAD) ++ __fput_sync(file[DST].file); ++ else { ++ WARN(1, "%pD\nPlease report this warning to aufs-users ML", ++ file[DST].file); ++ 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(); ++ } + au_sbr_put(sb, file[DST].bindex); + +out_src: @@ -4248,6 +3957,57 @@ index 0000000..cd32274 + 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; ++ ++ h_dentry = h_path->dentry; ++ h_inode = d_inode(h_dentry); ++ /* forget_all_cached_acls(h_inode)); */ ++ err = vfsub_removexattr(h_dentry, XATTR_NAME_POSIX_ACL_ACCESS); ++ AuTraceErr(err); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ if (!err) ++ err = vfsub_acl_chmod(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; ++ ++ err = vfsub_removexattr(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, ++ * particularry setattr case ++ */ ++ dir = d_inode(dst_parent); ++ if (au_ibstart(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) @@ -4260,7 +4020,7 @@ index 0000000..cd32274 + struct au_dtime dt; + struct path h_path; + struct dentry *h_src, *h_dst, *h_parent; -+ struct inode *h_inode, *h_dir, *dir, *inode; ++ struct inode *h_inode, *h_dir; + struct super_block *sb; + + /* bsrc branch can be ro/rw. */ @@ -4292,7 +4052,7 @@ index 0000000..cd32274 + switch (mode & S_IFMT) { + case S_IFREG: + isreg = 1; -+ err = vfsub_create(h_dir, &h_path, mode | S_IWUSR, ++ err = vfsub_create(h_dir, &h_path, S_IRUSR | S_IWUSR, + /*want_excl*/true); + if (!err) + err = au_do_cpup_regular(cpg, h_src_attr); @@ -4300,17 +4060,8 @@ index 0000000..cd32274 + case S_IFDIR: + isdir = 1; + err = vfsub_mkdir(h_dir, &h_path, mode); -+ if (!err) { -+ /* -+ * strange behaviour from the users view, -+ * particularry setattr case -+ */ -+ dir = d_inode(dst_parent); -+ if (au_ibstart(dir) == cpg->bdst) -+ au_cpup_attr_nlink(dir, /*force*/1); -+ inode = d_inode(cpg->dentry); -+ au_cpup_attr_nlink(inode, /*force*/1); -+ } ++ 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); @@ -4327,6 +4078,8 @@ index 0000000..cd32274 + 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) @@ -5056,14 +4809,12 @@ index 0000000..cd32274 + dput(parent); + return err; +} -diff --git a/fs/aufs/cpup.h b/fs/aufs/cpup.h -new file mode 100644 -index 0000000..3355f08 ---- /dev/null -+++ b/fs/aufs/cpup.h +diff -Nurp linux-4.4.3/fs/aufs/cpup.h linux-4.4.3-aufs/fs/aufs/cpup.h +--- linux-4.4.3/fs/aufs/cpup.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/cpup.h 2016-03-02 17:59:37.362498696 +0200 @@ -0,0 +1,81 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -5143,14 +4894,12 @@ index 0000000..3355f08 + +#endif /* __KERNEL__ */ +#endif /* __AUFS_CPUP_H__ */ -diff --git a/fs/aufs/dbgaufs.c b/fs/aufs/dbgaufs.c -new file mode 100644 -index 0000000..c7c612c ---- /dev/null -+++ b/fs/aufs/dbgaufs.c +diff -Nurp linux-4.4.3/fs/aufs/dbgaufs.c linux-4.4.3-aufs/fs/aufs/dbgaufs.c +--- linux-4.4.3/fs/aufs/dbgaufs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/dbgaufs.c 2016-03-02 17:59:37.362498696 +0200 @@ -0,0 +1,419 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -5568,14 +5317,12 @@ index 0000000..c7c612c + err = 0; + return err; +} -diff --git a/fs/aufs/dbgaufs.h b/fs/aufs/dbgaufs.h -new file mode 100644 -index 0000000..efa9a4d ---- /dev/null -+++ b/fs/aufs/dbgaufs.h +diff -Nurp linux-4.4.3/fs/aufs/dbgaufs.h linux-4.4.3-aufs/fs/aufs/dbgaufs.h +--- linux-4.4.3/fs/aufs/dbgaufs.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/dbgaufs.h 2016-03-02 17:59:37.362498696 +0200 @@ -0,0 +1,35 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -5609,14 +5356,12 @@ index 0000000..efa9a4d + +#endif /* __KERNEL__ */ +#endif /* __DBGAUFS_H__ */ -diff --git a/fs/aufs/dcsub.c b/fs/aufs/dcsub.c -new file mode 100644 -index 0000000..f9d9d52 ---- /dev/null -+++ b/fs/aufs/dcsub.c +diff -Nurp linux-4.4.3/fs/aufs/dcsub.c linux-4.4.3-aufs/fs/aufs/dcsub.c +--- linux-4.4.3/fs/aufs/dcsub.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/dcsub.c 2016-03-02 17:59:37.362498696 +0200 @@ -0,0 +1,211 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -5826,14 +5571,12 @@ index 0000000..f9d9d52 + + return path_is_under(path + 0, path + 1); +} -diff --git a/fs/aufs/dcsub.h b/fs/aufs/dcsub.h -new file mode 100644 -index 0000000..2aa87ac ---- /dev/null -+++ b/fs/aufs/dcsub.h +diff -Nurp linux-4.4.3/fs/aufs/dcsub.h linux-4.4.3-aufs/fs/aufs/dcsub.h +--- linux-4.4.3/fs/aufs/dcsub.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/dcsub.h 2016-03-02 17:59:37.362498696 +0200 @@ -0,0 +1,123 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -5955,14 +5698,12 @@ index 0000000..2aa87ac + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DCSUB_H__ */ -diff --git a/fs/aufs/debug.c b/fs/aufs/debug.c -new file mode 100644 -index 0000000..42053aa ---- /dev/null -+++ b/fs/aufs/debug.c +diff -Nurp linux-4.4.3/fs/aufs/debug.c linux-4.4.3-aufs/fs/aufs/debug.c +--- linux-4.4.3/fs/aufs/debug.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/debug.c 2016-03-02 17:59:37.363498703 +0200 @@ -0,0 +1,425 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -6386,14 +6127,12 @@ index 0000000..42053aa + + return 0; +} -diff --git a/fs/aufs/debug.h b/fs/aufs/debug.h -new file mode 100644 -index 0000000..0a2e7e7 ---- /dev/null -+++ b/fs/aufs/debug.h +diff -Nurp linux-4.4.3/fs/aufs/debug.h linux-4.4.3-aufs/fs/aufs/debug.h +--- linux-4.4.3/fs/aufs/debug.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/debug.h 2016-03-02 17:59:37.363498703 +0200 @@ -0,0 +1,212 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -6604,14 +6343,12 @@ index 0000000..0a2e7e7 + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DEBUG_H__ */ -diff --git a/fs/aufs/dentry.c b/fs/aufs/dentry.c -new file mode 100644 -index 0000000..aad25be ---- /dev/null -+++ b/fs/aufs/dentry.c +diff -Nurp linux-4.4.3/fs/aufs/dentry.c linux-4.4.3-aufs/fs/aufs/dentry.c +--- linux-4.4.3/fs/aufs/dentry.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/dentry.c 2016-03-02 17:59:37.363498703 +0200 @@ -0,0 +1,1123 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -7733,14 +7470,12 @@ index 0000000..aad25be +const struct dentry_operations aufs_dop_noreval = { + .d_release = aufs_d_release +}; -diff --git a/fs/aufs/dentry.h b/fs/aufs/dentry.h -new file mode 100644 -index 0000000..5225221 ---- /dev/null -+++ b/fs/aufs/dentry.h +diff -Nurp linux-4.4.3/fs/aufs/dentry.h linux-4.4.3-aufs/fs/aufs/dentry.h +--- linux-4.4.3/fs/aufs/dentry.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/dentry.h 2016-03-02 17:59:37.363498703 +0200 @@ -0,0 +1,221 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -7960,14 +7695,12 @@ index 0000000..5225221 + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DENTRY_H__ */ -diff --git a/fs/aufs/dinfo.c b/fs/aufs/dinfo.c -new file mode 100644 -index 0000000..25b971b ---- /dev/null -+++ b/fs/aufs/dinfo.c +diff -Nurp linux-4.4.3/fs/aufs/dinfo.c linux-4.4.3-aufs/fs/aufs/dinfo.c +--- linux-4.4.3/fs/aufs/dinfo.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/dinfo.c 2016-03-02 17:59:37.364498710 +0200 @@ -0,0 +1,537 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -8503,14 +8236,12 @@ index 0000000..25b971b + return bindex; + return -1; +} -diff --git a/fs/aufs/dir.c b/fs/aufs/dir.c -new file mode 100644 -index 0000000..ccdcebe ---- /dev/null -+++ b/fs/aufs/dir.c -@@ -0,0 +1,740 @@ +diff -Nurp linux-4.4.3/fs/aufs/dir.c linux-4.4.3-aufs/fs/aufs/dir.c +--- linux-4.4.3/fs/aufs/dir.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/dir.c 2016-03-02 17:59:37.364498710 +0200 +@@ -0,0 +1,745 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -8748,11 +8479,13 @@ index 0000000..ccdcebe + 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 = d_inode(dentry)->i_version; + bindex = au_dbstart(dentry); @@ -8764,6 +8497,9 @@ index 0000000..ccdcebe + 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); @@ -9249,14 +8985,12 @@ index 0000000..ccdcebe + .flush = aufs_flush_dir, + .fsync = aufs_fsync_dir +}; -diff --git a/fs/aufs/dir.h b/fs/aufs/dir.h -new file mode 100644 -index 0000000..803a0f1 ---- /dev/null -+++ b/fs/aufs/dir.h +diff -Nurp linux-4.4.3/fs/aufs/dir.h linux-4.4.3-aufs/fs/aufs/dir.h +--- linux-4.4.3/fs/aufs/dir.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/dir.h 2016-03-02 17:59:37.364498710 +0200 @@ -0,0 +1,118 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -9373,14 +9107,12 @@ index 0000000..803a0f1 + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DIR_H__ */ -diff --git a/fs/aufs/dynop.c b/fs/aufs/dynop.c -new file mode 100644 -index 0000000..1f12838 ---- /dev/null -+++ b/fs/aufs/dynop.c +diff -Nurp linux-4.4.3/fs/aufs/dynop.c linux-4.4.3-aufs/fs/aufs/dynop.c +--- linux-4.4.3/fs/aufs/dynop.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/dynop.c 2016-03-02 17:59:37.364498710 +0200 @@ -0,0 +1,356 @@ +/* -+ * Copyright (C) 2010-2015 Junjiro R. Okajima ++ * Copyright (C) 2010-2016 Junjiro R. Okajima + */ + +/* @@ -9735,14 +9467,12 @@ index 0000000..1f12838 + for (i = 0; i < AuDyLast; i++) + WARN_ON(!list_empty(&dynop[i].head)); +} -diff --git a/fs/aufs/dynop.h b/fs/aufs/dynop.h -new file mode 100644 -index 0000000..6d739c1 ---- /dev/null -+++ b/fs/aufs/dynop.h +diff -Nurp linux-4.4.3/fs/aufs/dynop.h linux-4.4.3-aufs/fs/aufs/dynop.h +--- linux-4.4.3/fs/aufs/dynop.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/dynop.h 2016-03-02 17:59:37.364498710 +0200 @@ -0,0 +1,61 @@ +/* -+ * Copyright (C) 2010-2015 Junjiro R. Okajima ++ * Copyright (C) 2010-2016 Junjiro R. Okajima + */ + +/* @@ -9802,14 +9532,12 @@ index 0000000..6d739c1 + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DYNOP_H__ */ -diff --git a/fs/aufs/export.c b/fs/aufs/export.c -new file mode 100644 -index 0000000..3026f39 ---- /dev/null -+++ b/fs/aufs/export.c +diff -Nurp linux-4.4.3/fs/aufs/export.c linux-4.4.3-aufs/fs/aufs/export.c +--- linux-4.4.3/fs/aufs/export.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/export.c 2016-03-02 17:59:37.365498717 +0200 @@ -0,0 +1,819 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -10407,7 +10135,7 @@ index 0000000..3026f39 + ino = decode_ino(fh + Fh_ino); + /* it should never happen */ + if (unlikely(ino == AUFS_ROOT_INO)) -+ goto out; ++ goto out_unlock; + + dir_ino = decode_ino(fh + Fh_dir_ino); + dentry = decode_by_ino(sb, ino, dir_ino); @@ -10627,745 +10355,12 @@ index 0000000..3026f39 + BUILD_BUG_ON(sizeof(u) != sizeof(int)); + atomic_set(&sbinfo->si_xigen_next, u); +} -diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c -new file mode 100644 -index 0000000..91c2ce7 ---- /dev/null -+++ b/fs/aufs/f_op.c -@@ -0,0 +1,725 @@ -+/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima -+ */ -+ -+/* -+ * 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; -+ 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_dbstart(dentry); -+ if (!h_file) -+ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); -+ else -+ get_file(h_file); -+ if (IS_ERR(h_file)) -+ err = PTR_ERR(h_file); -+ else { -+ if ((flags & __O_TMPFILE) -+ && !(flags & O_EXCL)) { -+ h_inode = file_inode(h_file); -+ spin_lock(&h_inode->i_lock); -+ h_inode->i_state |= I_LINKABLE; -+ spin_unlock(&h_inode->i_lock); -+ } -+ au_set_fbstart(file, bindex); -+ au_set_h_fptr(file, bindex, h_file); -+ au_update_figen(file); -+ /* todo: necessary? */ -+ /* file->f_ra = h_file->f_ra; */ -+ } -+ -+ 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_sphl_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-mamagement (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) -+{ -+ struct file *h_file; -+ int err; -+ -+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); -+ 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 { -+ blkcnt_t blks; -+ aufs_bindex_t bstart; -+}; -+ -+/* -+ * 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; -+ struct au_pin pin; -+ -+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); -+ 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->bstart = au_fbstart(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_ibstart(inode) != wpre->bstart); -+ h_inode = file_inode(h_file); -+ inode->i_mode = h_inode->i_mode; -+ ii_write_unlock(inode); -+ fput(h_file); -+ -+ /* AuDbg("blks %llu, %llu\n", (u64)blks, (u64)h_inode->i_blocks); */ -+ if (written > 0) -+ au_fhsm_wrote(inode->i_sb, wpre->bstart, -+ /*force*/h_inode->i_blocks > wpre->blks); -+} -+ -+static ssize_t aufs_read(struct file *file, char __user *buf, size_t count, -+ loff_t *ppos) -+{ -+ ssize_t err; -+ struct inode *inode; -+ struct file *h_file; -+ 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); -+ err = PTR_ERR(h_file); -+ if (IS_ERR(h_file)) -+ goto out; -+ -+ /* filedata may be obsoleted by concurrent copyup, but no problem */ -+ err = vfsub_read_u(h_file, buf, count, ppos); -+ /* todo: necessary? */ -+ /* file->f_ra = h_file->f_ra; */ -+ au_read_post(inode, h_file); -+ -+out: -+ si_read_unlock(sb); -+ return err; -+} -+ -+/* -+ * 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) { -+ mutex_lock(&inode->i_mutex); -+ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); -+ if (!err) -+ break; -+ mutex_unlock(&inode->i_mutex); -+ si_read_lock(sb, AuLock_NOPLMW); -+ si_read_unlock(sb); -+ } -+} -+ -+static ssize_t aufs_write(struct file *file, const char __user *ubuf, -+ size_t count, loff_t *ppos) -+{ -+ ssize_t err; -+ struct au_write_pre wpre; -+ struct inode *inode; -+ struct file *h_file; -+ char __user *buf = (char __user *)ubuf; -+ -+ inode = file_inode(file); -+ au_mtx_and_read_lock(inode); -+ -+ h_file = au_write_pre(file, /*do_ready*/1, &wpre); -+ err = PTR_ERR(h_file); -+ if (IS_ERR(h_file)) -+ goto out; -+ -+ err = vfsub_write_u(h_file, buf, count, ppos); -+ au_write_post(inode, h_file, &wpre, err); -+ -+out: -+ si_read_unlock(inode->i_sb); -+ mutex_unlock(&inode->i_mutex); -+ return err; -+} -+ -+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; -+ 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*/0); -+ err = PTR_ERR(h_file); -+ if (IS_ERR(h_file)) -+ goto out; -+ -+ 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); -+ -+ 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); -+ mutex_unlock(&inode->i_mutex); -+ return err; -+} -+ -+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*/1); -+ 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 = vfsub_splice_to(h_file, ppos, pipe, len, flags); -+ /* todo: necessasry? */ -+ /* 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); -+ -+ 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); -+ mutex_unlock(&inode->i_mutex); -+ 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); -+ -+ 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); -+ mutex_unlock(&inode->i_mutex); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * 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 definitly bad, but is not a problem since "si_rwsem for -+ * read" allows muliple processes to acquire it and [fdi]i_rwsem are not held in -+ * file I/O. Aufs needs to stop lockdep in aufs_mmap() though. -+ * 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 = h_file->f_op->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); -+ -+ 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); -+ mutex_unlock(&inode->i_mutex); -+out: -+ return err; -+} -+ -+/* no one supports this operation, currently */ -+#if 0 -+static int aufs_aio_fsync_nondir(struct kiocb *kio, int datasync) -+{ -+ int err; -+ struct au_write_pre wpre; -+ struct inode *inode; -+ struct file *file, *h_file; -+ -+ err = 0; /* -EBADF; */ /* posix? */ -+ if (unlikely(!(file->f_mode & FMODE_WRITE))) -+ goto out; -+ -+ file = kio->ki_filp; -+ inode = file_inode(file); -+ au_mtx_and_read_lock(inode); -+ -+ h_file = au_write_pre(file, /*do_ready*/1, &wpre); -+ err = PTR_ERR(h_file); -+ if (IS_ERR(h_file)) -+ goto out_unlock; -+ -+ err = -ENOSYS; -+ h_file = au_hf_top(file); -+ if (h_file->f_op->aio_fsync) { -+ struct mutex *h_mtx; -+ -+ h_mtx = &file_inode(h_file)->i_mutex; -+ if (!is_sync_kiocb(kio)) { -+ get_file(h_file); -+ fput(file); -+ } -+ kio->ki_filp = h_file; -+ err = h_file->f_op->aio_fsync(kio, datasync); -+ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); -+ if (!err) -+ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); -+ /*ignore*/ -+ mutex_unlock(h_mtx); -+ } -+ au_write_post(inode, h_file, &wpre, /*written*/0); -+ -+out_unlock: -+ si_read_unlock(inode->sb); -+ mutex_unlock(&inode->i_mutex); -+out: -+ return err; -+} -+#endif -+ -+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); -+ 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; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* no one supports this operation, currently */ -+#if 0 -+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 = aufs_read, -+ .write = aufs_write, -+ .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, -+ /* .aio_fsync = aufs_aio_fsync_nondir, */ -+ .fasync = aufs_fasync, -+ /* .sendpage = aufs_sendpage, */ -+ .splice_write = aufs_splice_write, -+ .splice_read = aufs_splice_read, -+#if 0 -+ .aio_splice_write = aufs_aio_splice_write, -+ .aio_splice_read = aufs_aio_splice_read, -+#endif -+ .fallocate = aufs_fallocate -+}; -diff --git a/fs/aufs/fhsm.c b/fs/aufs/fhsm.c -new file mode 100644 -index 0000000..47106cb ---- /dev/null -+++ b/fs/aufs/fhsm.c +diff -Nurp linux-4.4.3/fs/aufs/fhsm.c linux-4.4.3-aufs/fs/aufs/fhsm.c +--- linux-4.4.3/fs/aufs/fhsm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/fhsm.c 2016-03-02 17:59:37.365498717 +0200 @@ -0,0 +1,412 @@ +/* -+ * Copyright (C) 2011-2015 Junjiro R. Okajima ++ * Copyright (C) 2011-2016 Junjiro R. Okajima + */ + +/* @@ -11776,14 +10771,12 @@ index 0000000..47106cb + if (u != AUFS_FHSM_CACHE_DEF_SEC) + seq_printf(seq, ",fhsm_sec=%u", u); +} -diff --git a/fs/aufs/file.c b/fs/aufs/file.c -new file mode 100644 -index 0000000..72316b1 ---- /dev/null -+++ b/fs/aufs/file.c +diff -Nurp linux-4.4.3/fs/aufs/file.c linux-4.4.3-aufs/fs/aufs/file.c +--- linux-4.4.3/fs/aufs/file.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/file.c 2016-03-02 17:59:37.366498724 +0200 @@ -0,0 +1,831 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -12613,14 +11606,12 @@ index 0000000..72316b1 + .swap_deactivate = aufs_swap_deactivate +#endif /* CONFIG_AUFS_DEBUG */ +}; -diff --git a/fs/aufs/file.h b/fs/aufs/file.h -new file mode 100644 -index 0000000..488473e ---- /dev/null -+++ b/fs/aufs/file.h +diff -Nurp linux-4.4.3/fs/aufs/file.h linux-4.4.3-aufs/fs/aufs/file.h +--- linux-4.4.3/fs/aufs/file.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/file.h 2016-03-02 17:59:37.366498724 +0200 @@ -0,0 +1,278 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -12897,14 +11888,12 @@ index 0000000..488473e + +#endif /* __KERNEL__ */ +#endif /* __AUFS_FILE_H__ */ -diff --git a/fs/aufs/finfo.c b/fs/aufs/finfo.c -new file mode 100644 -index 0000000..e709205 ---- /dev/null -+++ b/fs/aufs/finfo.c +diff -Nurp linux-4.4.3/fs/aufs/finfo.c linux-4.4.3-aufs/fs/aufs/finfo.c +--- linux-4.4.3/fs/aufs/finfo.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/finfo.c 2016-03-02 17:59:37.366498724 +0200 @@ -0,0 +1,143 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -13046,14 +12035,775 @@ index 0000000..e709205 +out: + return err; +} -diff --git a/fs/aufs/fstype.h b/fs/aufs/fstype.h -new file mode 100644 -index 0000000..6196c60 ---- /dev/null -+++ b/fs/aufs/fstype.h +diff -Nurp linux-4.4.3/fs/aufs/f_op.c linux-4.4.3-aufs/fs/aufs/f_op.c +--- linux-4.4.3/fs/aufs/f_op.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/f_op.c 2016-03-02 17:59:37.365498717 +0200 +@@ -0,0 +1,759 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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_dbstart(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); ++ } else { ++ h_dentry = h_file->f_path.dentry; ++ err = vfsub_test_mntns(file->f_path.mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ goto out; ++ get_file(h_file); ++ } ++ if (IS_ERR(h_file)) ++ err = PTR_ERR(h_file); ++ else { ++ if ((flags & __O_TMPFILE) ++ && !(flags & O_EXCL)) { ++ h_inode = file_inode(h_file); ++ spin_lock(&h_inode->i_lock); ++ h_inode->i_state |= I_LINKABLE; ++ spin_unlock(&h_inode->i_lock); ++ } ++ au_set_fbstart(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_sphl_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-mamagement (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) ++{ ++ struct file *h_file; ++ int err; ++ ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); ++ 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 { ++ blkcnt_t blks; ++ aufs_bindex_t bstart; ++}; ++ ++/* ++ * 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; ++ struct au_pin pin; ++ ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); ++ 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->bstart = au_fbstart(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_ibstart(inode) != wpre->bstart); ++ h_inode = file_inode(h_file); ++ inode->i_mode = h_inode->i_mode; ++ ii_write_unlock(inode); ++ fput(h_file); ++ ++ /* AuDbg("blks %llu, %llu\n", (u64)blks, (u64)h_inode->i_blocks); */ ++ if (written > 0) ++ au_fhsm_wrote(inode->i_sb, wpre->bstart, ++ /*force*/h_inode->i_blocks > wpre->blks); ++} ++ ++static ssize_t aufs_read(struct file *file, char __user *buf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ struct inode *inode; ++ struct file *h_file; ++ 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); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ /* filedata may be obsoleted by concurrent copyup, but no problem */ ++ err = vfsub_read_u(h_file, buf, count, ppos); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ au_read_post(inode, h_file); ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ++ * 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) { ++ mutex_lock(&inode->i_mutex); ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (!err) ++ break; ++ mutex_unlock(&inode->i_mutex); ++ si_read_lock(sb, AuLock_NOPLMW); ++ si_read_unlock(sb); ++ } ++} ++ ++static ssize_t aufs_write(struct file *file, const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ char __user *buf = (char __user *)ubuf; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = vfsub_write_u(h_file, buf, count, ppos); ++ au_write_post(inode, h_file, &wpre, err); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ mutex_unlock(&inode->i_mutex); ++ return err; ++} ++ ++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; ++ 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*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ 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); ++ ++ 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); ++ mutex_unlock(&inode->i_mutex); ++ return err; ++} ++ ++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*/1); ++ 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 = vfsub_splice_to(h_file, ppos, pipe, len, flags); ++ /* todo: necessasry? */ ++ /* 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); ++ ++ 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); ++ mutex_unlock(&inode->i_mutex); ++ 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); ++ ++ 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); ++ mutex_unlock(&inode->i_mutex); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * 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 definitly bad, but is not a problem since "si_rwsem for ++ * read" allows muliple processes to acquire it and [fdi]i_rwsem are not held in ++ * file I/O. Aufs needs to stop lockdep in aufs_mmap() though. ++ * 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 = h_file->f_op->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); ++ ++ 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); ++ mutex_unlock(&inode->i_mutex); ++out: ++ return err; ++} ++ ++/* no one supports this operation, currently */ ++#if 0 ++static int aufs_aio_fsync_nondir(struct kiocb *kio, int datasync) ++{ ++ int err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *file, *h_file; ++ ++ err = 0; /* -EBADF; */ /* posix? */ ++ if (unlikely(!(file->f_mode & FMODE_WRITE))) ++ goto out; ++ ++ file = kio->ki_filp; ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out_unlock; ++ ++ err = -ENOSYS; ++ h_file = au_hf_top(file); ++ if (h_file->f_op->aio_fsync) { ++ struct mutex *h_mtx; ++ ++ h_mtx = &file_inode(h_file)->i_mutex; ++ if (!is_sync_kiocb(kio)) { ++ get_file(h_file); ++ fput(file); ++ } ++ kio->ki_filp = h_file; ++ err = h_file->f_op->aio_fsync(kio, datasync); ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); ++ if (!err) ++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); ++ /*ignore*/ ++ mutex_unlock(h_mtx); ++ } ++ au_write_post(inode, h_file, &wpre, /*written*/0); ++ ++out_unlock: ++ si_read_unlock(inode->sb); ++ mutex_unlock(&inode->i_mutex); ++out: ++ return err; ++} ++#endif ++ ++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); ++ 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); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ arg |= vfsub_file_flags(file) & FASYNC; /* stop calling h_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 ++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 = aufs_read, ++ .write = aufs_write, ++ .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, ++ /* .aio_fsync = aufs_aio_fsync_nondir, */ ++ .fasync = aufs_fasync, ++ /* .sendpage = aufs_sendpage, */ ++ .setfl = aufs_setfl, ++ .splice_write = aufs_splice_write, ++ .splice_read = aufs_splice_read, ++#if 0 ++ .aio_splice_write = aufs_aio_splice_write, ++ .aio_splice_read = aufs_aio_splice_read, ++#endif ++ .fallocate = aufs_fallocate ++}; +diff -Nurp linux-4.4.3/fs/aufs/fstype.h linux-4.4.3-aufs/fs/aufs/fstype.h +--- linux-4.4.3/fs/aufs/fstype.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/fstype.h 2016-03-02 17:59:37.366498724 +0200 @@ -0,0 +1,387 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -13439,14 +13189,12 @@ index 0000000..6196c60 + +#endif /* __KERNEL__ */ +#endif /* __AUFS_FSTYPE_H__ */ -diff --git a/fs/aufs/hfsnotify.c b/fs/aufs/hfsnotify.c -new file mode 100644 -index 0000000..5c370196 ---- /dev/null -+++ b/fs/aufs/hfsnotify.c +diff -Nurp linux-4.4.3/fs/aufs/hfsnotify.c linux-4.4.3-aufs/fs/aufs/hfsnotify.c +--- linux-4.4.3/fs/aufs/hfsnotify.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/hfsnotify.c 2016-03-02 17:59:37.366498724 +0200 @@ -0,0 +1,275 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -13720,14 +13468,12 @@ index 0000000..5c370196 + .fin_br = au_hfsn_fin_br, + .init_br = au_hfsn_init_br +}; -diff --git a/fs/aufs/hfsplus.c b/fs/aufs/hfsplus.c -new file mode 100644 -index 0000000..34c1f1a ---- /dev/null -+++ b/fs/aufs/hfsplus.c +diff -Nurp linux-4.4.3/fs/aufs/hfsplus.c linux-4.4.3-aufs/fs/aufs/hfsplus.c +--- linux-4.4.3/fs/aufs/hfsplus.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/hfsplus.c 2016-03-02 17:59:37.366498724 +0200 @@ -0,0 +1,43 @@ +/* -+ * Copyright (C) 2010-2015 Junjiro R. Okajima ++ * Copyright (C) 2010-2016 Junjiro R. Okajima + */ + +/* @@ -13769,14 +13515,12 @@ index 0000000..34c1f1a + au_sbr_put(dentry->d_sb, bindex); + } +} -diff --git a/fs/aufs/hnotify.c b/fs/aufs/hnotify.c -new file mode 100644 -index 0000000..3943dc4 ---- /dev/null -+++ b/fs/aufs/hnotify.c +diff -Nurp linux-4.4.3/fs/aufs/hnotify.c linux-4.4.3-aufs/fs/aufs/hnotify.c +--- linux-4.4.3/fs/aufs/hnotify.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/hnotify.c 2016-03-02 17:59:37.367498731 +0200 @@ -0,0 +1,697 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -14472,14 +14216,2607 @@ index 0000000..3943dc4 + if (au_cachep[AuCache_HNOTIFY]) + au_hn_destroy_cache(); +} -diff --git a/fs/aufs/i_op.c b/fs/aufs/i_op.c -new file mode 100644 -index 0000000..daad67a ---- /dev/null -+++ b/fs/aufs/i_op.c -@@ -0,0 +1,1471 @@ +diff -Nurp linux-4.4.3/fs/aufs/iinfo.c linux-4.4.3-aufs/fs/aufs/iinfo.c +--- linux-4.4.3/fs/aufs/iinfo.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/iinfo.c 2016-03-02 17:59:37.368498738 +0200 +@@ -0,0 +1,264 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode private data ++ */ ++ ++#include "aufs.h" ++ ++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct inode *h_inode; ++ ++ IiMustAnyLock(inode); ++ ++ h_inode = au_ii(inode)->ii_hinode[0 + bindex].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 = iinfo->ii_hinode + 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_bstart) ++ 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_ii(inode)->ii_hinode + 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, bend; ++ ++ iinfo = au_ii(inode); ++ if (!iinfo) ++ return; ++ ++ IiMustWriteLock(inode); ++ ++ if (do_put_zero && iinfo->ii_bstart >= 0) { ++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; ++ bindex++) { ++ struct inode *h_i; ++ ++ h_i = iinfo->ii_hinode[0 + 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_bstart = -1; ++ iinfo->ii_bend = -1; ++ bend = au_sbend(inode->i_sb); ++ for (bindex = 0; bindex <= bend; bindex++) ++ if (iinfo->ii_hinode[0 + bindex].hi_inode) { ++ iinfo->ii_bstart = bindex; ++ break; ++ } ++ if (iinfo->ii_bstart >= 0) ++ for (bindex = bend; bindex >= iinfo->ii_bstart; bindex--) ++ if (iinfo->ii_hinode[0 + bindex].hi_inode) { ++ iinfo->ii_bend = bindex; ++ break; ++ } ++ AuDebugOn(iinfo->ii_bstart > iinfo->ii_bend); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_icntnr_init_once(void *_c) ++{ ++ struct au_icntnr *c = _c; ++ struct au_iinfo *iinfo = &c->iinfo; ++ static struct lock_class_key aufs_ii; ++ ++ spin_lock_init(&iinfo->ii_generation.ig_spin); ++ au_rw_init(&iinfo->ii_rwsem); ++ au_rw_class(&iinfo->ii_rwsem, &aufs_ii); ++ inode_init_once(&c->vfs_inode); ++} ++ ++int au_iinfo_init(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct super_block *sb; ++ int nbr, i; ++ ++ sb = inode->i_sb; ++ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++ nbr = au_sbend(sb) + 1; ++ if (unlikely(nbr <= 0)) ++ nbr = 1; ++ iinfo->ii_hinode = kcalloc(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS); ++ if (iinfo->ii_hinode) { ++ au_ninodes_inc(sb); ++ for (i = 0; i < nbr; i++) ++ iinfo->ii_hinode[i].hi_id = -1; ++ ++ iinfo->ii_generation.ig_generation = au_sigen(sb); ++ iinfo->ii_bstart = -1; ++ iinfo->ii_bend = -1; ++ iinfo->ii_vdir = NULL; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++int au_ii_realloc(struct au_iinfo *iinfo, int nbr) ++{ ++ int err, sz; ++ struct au_hinode *hip; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*hip) * (iinfo->ii_bend + 1); ++ if (!sz) ++ sz = sizeof(*hip); ++ hip = au_kzrealloc(iinfo->ii_hinode, sz, sizeof(*hip) * nbr, GFP_NOFS); ++ if (hip) { ++ iinfo->ii_hinode = 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, bend; ++ const unsigned char unlinked = !inode->i_nlink; ++ ++ iinfo = au_ii(inode); ++ /* bad_inode case */ ++ if (!iinfo) ++ return; ++ ++ sb = inode->i_sb; ++ au_ninodes_dec(sb); ++ 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(); ++ } ++ ++ if (iinfo->ii_vdir) ++ au_vdir_free(iinfo->ii_vdir); ++ ++ bindex = iinfo->ii_bstart; ++ if (bindex >= 0) { ++ hi = iinfo->ii_hinode + bindex; ++ bend = iinfo->ii_bend; ++ while (bindex++ <= bend) { ++ if (hi->hi_inode) ++ au_hiput(hi); ++ hi++; ++ } ++ } ++ kfree(iinfo->ii_hinode); ++ iinfo->ii_hinode = NULL; ++ AuRwDestroy(&iinfo->ii_rwsem); ++} +diff -Nurp linux-4.4.3/fs/aufs/inode.c linux-4.4.3-aufs/fs/aufs/inode.c +--- linux-4.4.3/fs/aufs/inode.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/inode.c 2016-03-02 17:59:37.368498738 +0200 +@@ -0,0 +1,514 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode functions ++ */ ++ ++#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->i_version++; ++} ++ ++static int au_ii_refresh(struct inode *inode, int *update) ++{ ++ int err, e; ++ umode_t type; ++ aufs_bindex_t bindex, new_bindex; ++ struct super_block *sb; ++ struct au_iinfo *iinfo; ++ struct au_hinode *p, *q, tmp; ++ ++ IiMustWriteLock(inode); ++ ++ *update = 0; ++ sb = inode->i_sb; ++ type = inode->i_mode & S_IFMT; ++ iinfo = au_ii(inode); ++ err = au_ii_realloc(iinfo, au_sbend(sb) + 1); ++ if (unlikely(err)) ++ goto out; ++ ++ AuDebugOn(iinfo->ii_bstart < 0); ++ p = iinfo->ii_hinode + iinfo->ii_bstart; ++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; ++ 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_bstart) ++ iinfo->ii_bstart = new_bindex; ++ if (iinfo->ii_bend < new_bindex) ++ iinfo->ii_bend = new_bindex; ++ /* swap two lower inode, and loop again */ ++ q = iinfo->ii_hinode + new_bindex; ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hi_inode) { ++ bindex--; ++ p--; ++ } ++ } ++ au_update_ibrange(inode, /*do_put_zero*/0); ++ 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, bend; ++ 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 = iinfo->ii_hinode + iinfo->ii_bstart; ++ mode = (inode->i_mode & S_IFMT); ++ isdir = S_ISDIR(mode); ++ flags = au_hi_flags(inode, isdir); ++ bend = au_dbend(dentry); ++ for (bindex = au_dbstart(dentry); bindex <= bend; 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_bstart <= bindex && bindex <= iinfo->ii_bend) { ++ h_i = au_h_iptr(inode, bindex); ++ if (h_i) { ++ if (h_i == h_inode) ++ continue; ++ err = -EIO; ++ break; ++ } ++ } ++ if (bindex < iinfo->ii_bstart) ++ iinfo->ii_bstart = bindex; ++ if (iinfo->ii_bend < bindex) ++ iinfo->ii_bend = 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, bstart, btail; ++ unsigned char isdir; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_iinfo *iinfo; ++ struct inode_operations *iop; ++ ++ IiMustWriteLock(inode); ++ ++ err = 0; ++ isdir = 0; ++ iop = au_sbi(inode->i_sb)->si_iop_array; ++ bstart = au_dbstart(dentry); ++ h_dentry = au_h_dptr(dentry, bstart); ++ 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, bstart, 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_bstart = bstart; ++ iinfo->ii_bend = btail; ++ for (bindex = bstart; 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, bend; ++ 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_dbstart(dentry)); ++ h_dinode = d_inode(h_dentry); ++ bend = au_ibend(inode); ++ for (bindex = au_ibstart(inode); bindex <= bend; 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; ++ struct mutex *mtx; ++ ++ /* prevent hardlinked inode number from race condition */ ++ mtx = NULL; ++ if (d_type != DT_DIR) { ++ mtx = &au_sbr(sb, bindex)->br_xino.xi_nondir_mtx; ++ mutex_lock(mtx); ++ } ++ err = au_xino_read(sb, bindex, h_ino, ino); ++ if (unlikely(err)) ++ goto out; ++ ++ if (!*ino) { ++ err = -EIO; ++ *ino = au_xino_new_ino(sb); ++ if (unlikely(!*ino)) ++ goto out; ++ err = au_xino_write(sb, bindex, h_ino, *ino); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++out: ++ if (mtx) ++ mutex_unlock(mtx); ++ 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; ++ struct mutex *mtx; ++ ino_t h_ino, ino; ++ int err; ++ aufs_bindex_t bstart; ++ ++ sb = dentry->d_sb; ++ bstart = au_dbstart(dentry); ++ h_dentry = au_h_dptr(dentry, bstart); ++ h_inode = d_inode(h_dentry); ++ h_ino = h_inode->i_ino; ++ ++ /* ++ * stop 'race'-ing between hardlinks under different ++ * parents. ++ */ ++ mtx = NULL; ++ if (!d_is_dir(h_dentry)) ++ mtx = &au_sbr(sb, bstart)->br_xino.xi_nondir_mtx; ++ ++new_ino: ++ if (mtx) ++ mutex_lock(mtx); ++ err = au_xino_read(sb, bstart, h_ino, &ino); ++ inode = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ if (!ino) { ++ ino = au_xino_new_ino(sb); ++ if (unlikely(!ino)) { ++ inode = ERR_PTR(-EIO); ++ goto out; ++ } ++ } ++ ++ AuDbg("i%lu\n", (unsigned long)ino); ++ inode = au_iget_locked(sb, ino); ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out; ++ ++ AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW)); ++ if (inode->i_state & I_NEW) { ++ /* verbose coding for lock class name */ ++ if (unlikely(d_is_symlink(h_dentry))) ++ au_rw_class(&au_ii(inode)->ii_rwsem, ++ au_lc_key + AuLcSymlink_IIINFO); ++ else if (unlikely(d_is_dir(h_dentry))) ++ au_rw_class(&au_ii(inode)->ii_rwsem, ++ au_lc_key + AuLcDir_IIINFO); ++ else /* likely */ ++ au_rw_class(&au_ii(inode)->ii_rwsem, ++ au_lc_key + AuLcNonDir_IIINFO); ++ ++ ii_write_lock_new_child(inode); ++ err = set_inode(inode, dentry); ++ if (!err) { ++ unlock_new_inode(inode); ++ goto out; /* 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, bstart, 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 (mtx) ++ mutex_unlock(mtx); ++ err = reval_inode(inode, dentry); ++ if (unlikely(err < 0)) { ++ mtx = NULL; ++ goto out_iput; ++ } ++ ++ if (!err) { ++ mtx = NULL; ++ goto out; /* success */ ++ } else if (mtx) ++ mutex_lock(mtx); ++ } ++ ++ 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", ++ bstart, au_sbtype(h_dentry->d_sb), dentry, ++ (unsigned long)h_ino, (unsigned long)ino); ++ ino = 0; ++ err = au_xino_write(sb, bstart, h_ino, /*ino*/0); ++ if (!err) { ++ iput(inode); ++ if (mtx) ++ mutex_unlock(mtx); ++ goto new_ino; ++ } ++ ++out_iput: ++ iput(inode); ++ inode = ERR_PTR(err); ++out: ++ if (mtx) ++ mutex_unlock(mtx); ++ 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_ibstart(inode) <= bindex ++ && bindex <= au_ibend(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 inode *h_inode, int mask) ++{ ++ if (uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) ++ return 0; ++ return inode_permission(h_inode, mask); ++} ++ ++int au_test_h_perm_sio(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_inode, mask); ++} +diff -Nurp linux-4.4.3/fs/aufs/inode.h linux-4.4.3-aufs/fs/aufs/inode.h +--- linux-4.4.3/fs/aufs/inode.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/inode.h 2016-03-02 17:59:37.369498746 +0200 +@@ -0,0 +1,672 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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 */ ++#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_bstart, ii_bend; ++ __u32 ii_higen; ++ struct au_hinode *ii_hinode; ++ struct au_vdir *ii_vdir; ++}; ++ ++struct au_icntnr { ++ struct au_iinfo iinfo; ++ struct inode vfs_inode; ++} ____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_set_owner(struct au_pin *p, struct task_struct *task); ++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) ++{ ++ struct au_iinfo *iinfo; ++ ++ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++ if (iinfo->ii_hinode) ++ return iinfo; ++ return NULL; /* debugging bad_inode case */ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* 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 inode *h_inode, int mask); ++int au_test_h_perm_sio(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], ++ 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, int force, struct path *h_path); ++ ++/* 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 inode *dir, struct dentry *dentry, umode_t mode, ++ dev_t dev); ++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); ++int aufs_create(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 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 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 inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct dentry *dentry); ++ ++/* 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); ++int au_iinfo_init(struct inode *inode); ++void au_iinfo_fin(struct inode *inode); ++int au_ii_realloc(struct au_iinfo *iinfo, int nbr); ++ ++#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 dentry *h_dst, struct dentry *h_src, int ignore_flags, ++ unsigned int verbose); ++ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size); ++ssize_t aufs_getxattr(struct dentry *dentry, const char *name, void *value, ++ size_t size); ++int aufs_setxattr(struct dentry *dentry, const char *name, const void *value, ++ size_t size, int flags); ++int aufs_removexattr(struct dentry *dentry, const char *name); ++ ++/* void au_xattr_init(struct super_block *sb); */ ++#else ++AuStubInt0(au_cpup_xattr, struct dentry *h_dst, struct dentry *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); ++int aufs_set_acl(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_XATTR_REMOVE, ++ AU_ACL_SET ++}; ++ ++struct au_srxattr { ++ int type; ++ union { ++ struct { ++ const char *name; ++ const void *value; ++ size_t size; ++ int flags; ++ } set; ++ struct { ++ const char *name; ++ } remove; ++ struct { ++ struct posix_acl *acl; ++ int type; ++ } acl_set; ++ } u; ++}; ++ssize_t au_srxattr(struct dentry *dentry, struct au_srxattr *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 ++ ++/* ++ * ii_read_unlock, ii_write_unlock, ii_downgrade_lock ++ */ ++AuSimpleUnlockRwsemFuncs(ii, struct inode *i, &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 aufs_bindex_t au_ii_br_id(struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_hinode[0 + bindex].hi_id; ++} ++ ++static inline aufs_bindex_t au_ibstart(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_bstart; ++} ++ ++static inline aufs_bindex_t au_ibend(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_bend; ++} ++ ++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_ii(inode)->ii_hinode[0 + bindex].hi_whdentry; ++} ++ ++static inline void au_set_ibstart(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_bstart = bindex; ++} ++ ++static inline void au_set_ibend(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_bend = 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_ii(inode)->ii_hinode + 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 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, ++ 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_imtx_lock(struct au_hinode *hdir) ++{ ++ mutex_lock(&hdir->hi_inode->i_mutex); ++ au_hn_suspend(hdir); ++} ++ ++static inline void au_hn_imtx_lock_nested(struct au_hinode *hdir, ++ unsigned int sc __maybe_unused) ++{ ++ mutex_lock_nested(&hdir->hi_inode->i_mutex, sc); ++ au_hn_suspend(hdir); ++} ++ ++static inline void au_hn_imtx_unlock(struct au_hinode *hdir) ++{ ++ au_hn_resume(hdir); ++ mutex_unlock(&hdir->hi_inode->i_mutex); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_INODE_H__ */ +diff -Nurp linux-4.4.3/fs/aufs/ioctl.c linux-4.4.3-aufs/fs/aufs/ioctl.c +--- linux-4.4.3/fs/aufs/ioctl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/ioctl.c 2016-03-02 17:59:37.369498746 +0200 +@@ -0,0 +1,206 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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, bend; ++ 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); ++ bend = au_sbend(sb); ++ if (wbrfd.brid >= 0) { ++ wbi = au_br_index(sb, wbrfd.brid); ++ if (unlikely(wbi < 0 || wbi > bend)) ++ 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 <= bend; 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; ++ ++ atomic_dec(&br->br_count); /* 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 -Nurp linux-4.4.3/fs/aufs/i_op_add.c linux-4.4.3-aufs/fs/aufs/i_op_add.c +--- linux-4.4.3/fs/aufs/i_op_add.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/i_op_add.c 2016-03-02 17:59:37.367498731 +0200 +@@ -0,0 +1,919 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations (add entry) ++ */ ++ ++#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); ++ dir->i_version++; ++ 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_dbstart(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 bstart; ++ unsigned char created; ++ const unsigned char try_aopen ++ = (arg->type == Creat && arg->u.c.try_aopen); ++ struct dentry *wh_dentry, *parent; ++ struct inode *h_dir; ++ struct super_block *sb; ++ struct au_branch *br; ++ /* to reuduce 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; ++ ++ bstart = au_dbstart(dentry); ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bstart); ++ a->h_path.dentry = au_h_dptr(dentry, bstart); ++ a->h_path.mnt = au_br_mnt(br); ++ h_dir = au_pinned_h_dir(&a->pin); ++ switch (arg->type) { ++ case Creat: ++ err = 0; ++ if (!try_aopen || !h_dir->i_op->atomic_open) ++ err = vfsub_create(h_dir, &a->h_path, arg->u.c.mode, ++ arg->u.c.want_excl); ++ else ++ err = vfsub_atomic_open(h_dir, a->h_path.dentry, ++ arg->u.c.aopen, br); ++ break; ++ case Symlink: ++ err = vfsub_symlink(h_dir, &a->h_path, arg->u.s.symname); ++ break; ++ case Mknod: ++ err = vfsub_mknod(h_dir, &a->h_path, arg->u.m.mode, ++ arg->u.m.dev); ++ break; ++ default: ++ BUG(); ++ } ++ created = !err; ++ if (!err) ++ err = epilog(dir, bstart, wh_dentry, dentry); ++ ++ /* revert */ ++ if (unlikely(created && err && 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 (!err && try_aopen && !h_dir->i_op->atomic_open) ++ *arg->u.c.aopen->opened |= FILE_CREATED; ++ ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++ ++out_parent: ++ if (!try_aopen) ++ di_write_unlock(parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbstart(dentry); ++ d_drop(dentry); ++ } ++ if (!try_aopen) ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ kfree(a); ++out: ++ return err; ++} ++ ++int aufs_mknod(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 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 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 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 au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = AuWrDir_TMPFILE ++ }; ++ ++ /* copy-up may happen */ ++ mutex_lock(&dir->i_mutex); ++ ++ 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_dbstart(parent); ++ au_set_dbstart(dentry, bindex); ++ au_set_dbend(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_parent = au_h_dptr(parent, bindex); ++ err = inode_permission(d_inode(h_parent), MAY_WRITE | MAY_EXEC); ++ if (unlikely(err)) ++ goto out_mnt; ++ ++ err = -ENOMEM; ++ h_dentry = d_alloc(h_parent, &dentry->d_name); ++ if (unlikely(!h_dentry)) ++ goto out_mnt; ++ ++ err = h_dir->i_op->tmpfile(h_dir, h_dentry, mode); ++ if (unlikely(err)) ++ goto out_dentry; ++ ++ au_set_dbstart(dentry, bindex); ++ au_set_dbend(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_dbstart(dentry, -1); ++ au_set_dbend(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_ibstart(dir) == au_dbstart(dentry)) ++ au_cpup_attr_timesizes(dir); ++ } ++ ++out_dentry: ++ dput(h_dentry); ++out_mnt: ++ vfsub_mnt_drop_write(h_mnt); ++out_parent: ++ di_write_unlock(parent); ++ dput(parent); ++ di_write_unlock(dentry); ++ if (!err) ++#if 0 ++ /* verbose coding for lock class name */ ++ au_rw_class(&au_di(dentry)->di_rwsem, ++ au_lc_key + AuLcNonDir_DIINFO); ++#else ++ ; ++#endif ++ else { ++ au_di_fin(dentry); ++ dentry->d_fsdata = NULL; ++ } ++out_si: ++ si_read_unlock(sb); ++out: ++ mutex_unlock(&dir->i_mutex); ++ 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 bend; ++ 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_ibstart(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. */ ++ bend = au_dbend(dentry); ++ if (bend < a->bsrc) ++ au_set_dbend(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_dbend(dentry, bend); ++ } 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_ibstart(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_dbstart(dentry); ++ a->h_path.dentry = au_h_dptr(dentry, a->bdst); ++ a->h_path.mnt = au_sbr_mnt(sb, a->bdst); ++ a->bsrc = au_ibstart(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_dbstart(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; ++ } ++ ++ 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); ++ dir->i_version++; ++ 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_dbstart(dentry); ++ d_drop(dentry); ++ } ++ aufs_read_and_write_unlock2(dentry, src_dentry); ++out_kfree: ++ kfree(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int aufs_mkdir(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 mutex *h_mtx; ++ 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_dbstart(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_mtx = &d_inode(h_path.dentry)->i_mutex; ++ if (wh_dentry ++ || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) { ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); ++ opq_dentry = au_diropq_create(dentry, bindex); ++ mutex_unlock(h_mtx); ++ 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); ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(dentry, bindex); ++ mutex_unlock(h_mtx); ++ 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_dbstart(dentry); ++ d_drop(dentry); ++ } ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ kfree(a); ++out: ++ return err; ++} +diff -Nurp linux-4.4.3/fs/aufs/i_op.c linux-4.4.3-aufs/fs/aufs/i_op.c +--- linux-4.4.3/fs/aufs/i_op.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/i_op.c 2016-03-02 17:59:37.367498731 +0200 +@@ -0,0 +1,1477 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -15443,6 +17780,12 @@ index 0000000..daad67a + 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)) ++ err = vfsub_acl_chmod(a->h_inode, ia->ia_mode); + if (!err) + au_cpup_attr_changeable(inode); + @@ -15949,939 +18292,12 @@ index 0000000..daad67a + .update_time = aufs_update_time + } +}; -diff --git a/fs/aufs/i_op_add.c b/fs/aufs/i_op_add.c -new file mode 100644 -index 0000000..0c3530e ---- /dev/null -+++ b/fs/aufs/i_op_add.c -@@ -0,0 +1,919 @@ -+/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima -+ */ -+ -+/* -+ * inode operations (add entry) -+ */ -+ -+#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); -+ dir->i_version++; -+ 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_dbstart(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 bstart; -+ unsigned char created; -+ const unsigned char try_aopen -+ = (arg->type == Creat && arg->u.c.try_aopen); -+ struct dentry *wh_dentry, *parent; -+ struct inode *h_dir; -+ struct super_block *sb; -+ struct au_branch *br; -+ /* to reuduce 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; -+ -+ bstart = au_dbstart(dentry); -+ sb = dentry->d_sb; -+ br = au_sbr(sb, bstart); -+ a->h_path.dentry = au_h_dptr(dentry, bstart); -+ a->h_path.mnt = au_br_mnt(br); -+ h_dir = au_pinned_h_dir(&a->pin); -+ switch (arg->type) { -+ case Creat: -+ err = 0; -+ if (!try_aopen || !h_dir->i_op->atomic_open) -+ err = vfsub_create(h_dir, &a->h_path, arg->u.c.mode, -+ arg->u.c.want_excl); -+ else -+ err = vfsub_atomic_open(h_dir, a->h_path.dentry, -+ arg->u.c.aopen, br); -+ break; -+ case Symlink: -+ err = vfsub_symlink(h_dir, &a->h_path, arg->u.s.symname); -+ break; -+ case Mknod: -+ err = vfsub_mknod(h_dir, &a->h_path, arg->u.m.mode, -+ arg->u.m.dev); -+ break; -+ default: -+ BUG(); -+ } -+ created = !err; -+ if (!err) -+ err = epilog(dir, bstart, wh_dentry, dentry); -+ -+ /* revert */ -+ if (unlikely(created && err && 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 (!err && try_aopen && !h_dir->i_op->atomic_open) -+ *arg->u.c.aopen->opened |= FILE_CREATED; -+ -+ au_unpin(&a->pin); -+ dput(wh_dentry); -+ -+out_parent: -+ if (!try_aopen) -+ di_write_unlock(parent); -+out_unlock: -+ if (unlikely(err)) { -+ au_update_dbstart(dentry); -+ d_drop(dentry); -+ } -+ if (!try_aopen) -+ aufs_read_unlock(dentry, AuLock_DW); -+out_free: -+ kfree(a); -+out: -+ return err; -+} -+ -+int aufs_mknod(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 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 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 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 au_wr_dir_args wr_dir_args = { -+ .force_btgt = -1, -+ .flags = AuWrDir_TMPFILE -+ }; -+ -+ /* copy-up may happen */ -+ mutex_lock(&dir->i_mutex); -+ -+ 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_dbstart(parent); -+ au_set_dbstart(dentry, bindex); -+ au_set_dbend(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_parent = au_h_dptr(parent, bindex); -+ err = inode_permission(d_inode(h_parent), MAY_WRITE | MAY_EXEC); -+ if (unlikely(err)) -+ goto out_mnt; -+ -+ err = -ENOMEM; -+ h_dentry = d_alloc(h_parent, &dentry->d_name); -+ if (unlikely(!h_dentry)) -+ goto out_mnt; -+ -+ err = h_dir->i_op->tmpfile(h_dir, h_dentry, mode); -+ if (unlikely(err)) -+ goto out_dentry; -+ -+ au_set_dbstart(dentry, bindex); -+ au_set_dbend(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_dbstart(dentry, -1); -+ au_set_dbend(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_ibstart(dir) == au_dbstart(dentry)) -+ au_cpup_attr_timesizes(dir); -+ } -+ -+out_dentry: -+ dput(h_dentry); -+out_mnt: -+ vfsub_mnt_drop_write(h_mnt); -+out_parent: -+ di_write_unlock(parent); -+ dput(parent); -+ di_write_unlock(dentry); -+ if (!err) -+#if 0 -+ /* verbose coding for lock class name */ -+ au_rw_class(&au_di(dentry)->di_rwsem, -+ au_lc_key + AuLcNonDir_DIINFO); -+#else -+ ; -+#endif -+ else { -+ au_di_fin(dentry); -+ dentry->d_fsdata = NULL; -+ } -+out_si: -+ si_read_unlock(sb); -+out: -+ mutex_unlock(&dir->i_mutex); -+ 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 bend; -+ 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_ibstart(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. */ -+ bend = au_dbend(dentry); -+ if (bend < a->bsrc) -+ au_set_dbend(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_dbend(dentry, bend); -+ } 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_ibstart(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_dbstart(dentry); -+ a->h_path.dentry = au_h_dptr(dentry, a->bdst); -+ a->h_path.mnt = au_sbr_mnt(sb, a->bdst); -+ a->bsrc = au_ibstart(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_dbstart(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; -+ } -+ -+ 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); -+ dir->i_version++; -+ 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_dbstart(dentry); -+ d_drop(dentry); -+ } -+ aufs_read_and_write_unlock2(dentry, src_dentry); -+out_kfree: -+ kfree(a); -+out: -+ AuTraceErr(err); -+ return err; -+} -+ -+int aufs_mkdir(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 mutex *h_mtx; -+ 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_dbstart(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_mtx = &d_inode(h_path.dentry)->i_mutex; -+ if (wh_dentry -+ || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) { -+ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); -+ opq_dentry = au_diropq_create(dentry, bindex); -+ mutex_unlock(h_mtx); -+ 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); -+ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); -+ rerr = au_diropq_remove(dentry, bindex); -+ mutex_unlock(h_mtx); -+ 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_dbstart(dentry); -+ d_drop(dentry); -+ } -+ aufs_read_unlock(dentry, AuLock_DW); -+out_free: -+ kfree(a); -+out: -+ return err; -+} -diff --git a/fs/aufs/i_op_del.c b/fs/aufs/i_op_del.c -new file mode 100644 -index 0000000..3cd4c7b ---- /dev/null -+++ b/fs/aufs/i_op_del.c +diff -Nurp linux-4.4.3/fs/aufs/i_op_del.c linux-4.4.3-aufs/fs/aufs/i_op_del.c +--- linux-4.4.3/fs/aufs/i_op_del.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/i_op_del.c 2016-03-02 17:59:37.368498738 +0200 @@ -0,0 +1,497 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -17377,14 +18793,12 @@ index 0000000..3cd4c7b + AuTraceErr(err); + return err; +} -diff --git a/fs/aufs/i_op_ren.c b/fs/aufs/i_op_ren.c -new file mode 100644 -index 0000000..fd815fd ---- /dev/null -+++ b/fs/aufs/i_op_ren.c +diff -Nurp linux-4.4.3/fs/aufs/i_op_ren.c linux-4.4.3-aufs/fs/aufs/i_op_ren.c +--- linux-4.4.3/fs/aufs/i_op_ren.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/i_op_ren.c 2016-03-02 17:59:37.368498738 +0200 @@ -0,0 +1,1002 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -18385,1695 +19799,201 @@ index 0000000..fd815fd + AuTraceErr(err); + return err; +} -diff --git a/fs/aufs/iinfo.c b/fs/aufs/iinfo.c -new file mode 100644 -index 0000000..c604f69 ---- /dev/null -+++ b/fs/aufs/iinfo.c -@@ -0,0 +1,264 @@ -+/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima -+ */ -+ -+/* -+ * inode private data -+ */ -+ -+#include "aufs.h" -+ -+struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex) -+{ -+ struct inode *h_inode; -+ -+ IiMustAnyLock(inode); -+ -+ h_inode = au_ii(inode)->ii_hinode[0 + bindex].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 = iinfo->ii_hinode + 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_bstart) -+ 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_ii(inode)->ii_hinode + 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, bend; -+ -+ iinfo = au_ii(inode); -+ if (!iinfo) -+ return; -+ -+ IiMustWriteLock(inode); -+ -+ if (do_put_zero && iinfo->ii_bstart >= 0) { -+ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; -+ bindex++) { -+ struct inode *h_i; -+ -+ h_i = iinfo->ii_hinode[0 + 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_bstart = -1; -+ iinfo->ii_bend = -1; -+ bend = au_sbend(inode->i_sb); -+ for (bindex = 0; bindex <= bend; bindex++) -+ if (iinfo->ii_hinode[0 + bindex].hi_inode) { -+ iinfo->ii_bstart = bindex; -+ break; -+ } -+ if (iinfo->ii_bstart >= 0) -+ for (bindex = bend; bindex >= iinfo->ii_bstart; bindex--) -+ if (iinfo->ii_hinode[0 + bindex].hi_inode) { -+ iinfo->ii_bend = bindex; -+ break; -+ } -+ AuDebugOn(iinfo->ii_bstart > iinfo->ii_bend); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+void au_icntnr_init_once(void *_c) -+{ -+ struct au_icntnr *c = _c; -+ struct au_iinfo *iinfo = &c->iinfo; -+ static struct lock_class_key aufs_ii; -+ -+ spin_lock_init(&iinfo->ii_generation.ig_spin); -+ au_rw_init(&iinfo->ii_rwsem); -+ au_rw_class(&iinfo->ii_rwsem, &aufs_ii); -+ inode_init_once(&c->vfs_inode); -+} -+ -+int au_iinfo_init(struct inode *inode) -+{ -+ struct au_iinfo *iinfo; -+ struct super_block *sb; -+ int nbr, i; -+ -+ sb = inode->i_sb; -+ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); -+ nbr = au_sbend(sb) + 1; -+ if (unlikely(nbr <= 0)) -+ nbr = 1; -+ iinfo->ii_hinode = kcalloc(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS); -+ if (iinfo->ii_hinode) { -+ au_ninodes_inc(sb); -+ for (i = 0; i < nbr; i++) -+ iinfo->ii_hinode[i].hi_id = -1; -+ -+ iinfo->ii_generation.ig_generation = au_sigen(sb); -+ iinfo->ii_bstart = -1; -+ iinfo->ii_bend = -1; -+ iinfo->ii_vdir = NULL; -+ return 0; -+ } -+ return -ENOMEM; -+} -+ -+int au_ii_realloc(struct au_iinfo *iinfo, int nbr) -+{ -+ int err, sz; -+ struct au_hinode *hip; -+ -+ AuRwMustWriteLock(&iinfo->ii_rwsem); -+ -+ err = -ENOMEM; -+ sz = sizeof(*hip) * (iinfo->ii_bend + 1); -+ if (!sz) -+ sz = sizeof(*hip); -+ hip = au_kzrealloc(iinfo->ii_hinode, sz, sizeof(*hip) * nbr, GFP_NOFS); -+ if (hip) { -+ iinfo->ii_hinode = 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, bend; -+ const unsigned char unlinked = !inode->i_nlink; -+ -+ iinfo = au_ii(inode); -+ /* bad_inode case */ -+ if (!iinfo) -+ return; -+ -+ sb = inode->i_sb; -+ au_ninodes_dec(sb); -+ 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(); -+ } -+ -+ if (iinfo->ii_vdir) -+ au_vdir_free(iinfo->ii_vdir); -+ -+ bindex = iinfo->ii_bstart; -+ if (bindex >= 0) { -+ hi = iinfo->ii_hinode + bindex; -+ bend = iinfo->ii_bend; -+ while (bindex++ <= bend) { -+ if (hi->hi_inode) -+ au_hiput(hi); -+ hi++; -+ } -+ } -+ kfree(iinfo->ii_hinode); -+ iinfo->ii_hinode = NULL; -+ AuRwDestroy(&iinfo->ii_rwsem); -+} -diff --git a/fs/aufs/inode.c b/fs/aufs/inode.c -new file mode 100644 -index 0000000..6db3d6f ---- /dev/null -+++ b/fs/aufs/inode.c -@@ -0,0 +1,515 @@ -+/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima -+ */ -+ -+/* -+ * inode functions -+ */ -+ -+#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->i_version++; -+} -+ -+static int au_ii_refresh(struct inode *inode, int *update) -+{ -+ int err, e; -+ umode_t type; -+ aufs_bindex_t bindex, new_bindex; -+ struct super_block *sb; -+ struct au_iinfo *iinfo; -+ struct au_hinode *p, *q, tmp; -+ -+ IiMustWriteLock(inode); -+ -+ *update = 0; -+ sb = inode->i_sb; -+ type = inode->i_mode & S_IFMT; -+ iinfo = au_ii(inode); -+ err = au_ii_realloc(iinfo, au_sbend(sb) + 1); -+ if (unlikely(err)) -+ goto out; -+ -+ AuDebugOn(iinfo->ii_bstart < 0); -+ p = iinfo->ii_hinode + iinfo->ii_bstart; -+ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; -+ 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_bstart) -+ iinfo->ii_bstart = new_bindex; -+ if (iinfo->ii_bend < new_bindex) -+ iinfo->ii_bend = new_bindex; -+ /* swap two lower inode, and loop again */ -+ q = iinfo->ii_hinode + new_bindex; -+ tmp = *q; -+ *q = *p; -+ *p = tmp; -+ if (tmp.hi_inode) { -+ bindex--; -+ p--; -+ } -+ } -+ au_update_ibrange(inode, /*do_put_zero*/0); -+ 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, bend; -+ 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 = iinfo->ii_hinode + iinfo->ii_bstart; -+ mode = (inode->i_mode & S_IFMT); -+ isdir = S_ISDIR(mode); -+ flags = au_hi_flags(inode, isdir); -+ bend = au_dbend(dentry); -+ for (bindex = au_dbstart(dentry); bindex <= bend; 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_bstart <= bindex && bindex <= iinfo->ii_bend) { -+ h_i = au_h_iptr(inode, bindex); -+ if (h_i) { -+ if (h_i == h_inode) -+ continue; -+ err = -EIO; -+ break; -+ } -+ } -+ if (bindex < iinfo->ii_bstart) -+ iinfo->ii_bstart = bindex; -+ if (iinfo->ii_bend < bindex) -+ iinfo->ii_bend = 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, bstart, btail; -+ unsigned char isdir; -+ struct dentry *h_dentry; -+ struct inode *h_inode; -+ struct au_iinfo *iinfo; -+ struct inode_operations *iop; -+ -+ IiMustWriteLock(inode); -+ -+ err = 0; -+ isdir = 0; -+ iop = au_sbi(inode->i_sb)->si_iop_array; -+ bstart = au_dbstart(dentry); -+ h_dentry = au_h_dptr(dentry, bstart); -+ 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, bstart, 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_bstart = bstart; -+ iinfo->ii_bend = btail; -+ for (bindex = bstart; 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; -+ struct au_iigen iigen; -+ aufs_bindex_t bindex, bend; -+ 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_dbstart(dentry)); -+ h_dinode = d_inode(h_dentry); -+ bend = au_ibend(inode); -+ for (bindex = au_ibstart(inode); bindex <= bend; bindex++) { -+ h_inode = au_h_iptr(inode, bindex); -+ if (!h_inode || h_inode != h_dinode) -+ continue; -+ -+ err = 0; -+ gen = au_iigen(inode, &iigen); -+ if (gen == au_digen(dentry) -+ && !au_ig_ftest(iigen.ig_flags, 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; -+ struct mutex *mtx; -+ -+ /* prevent hardlinked inode number from race condition */ -+ mtx = NULL; -+ if (d_type != DT_DIR) { -+ mtx = &au_sbr(sb, bindex)->br_xino.xi_nondir_mtx; -+ mutex_lock(mtx); -+ } -+ err = au_xino_read(sb, bindex, h_ino, ino); -+ if (unlikely(err)) -+ goto out; -+ -+ if (!*ino) { -+ err = -EIO; -+ *ino = au_xino_new_ino(sb); -+ if (unlikely(!*ino)) -+ goto out; -+ err = au_xino_write(sb, bindex, h_ino, *ino); -+ if (unlikely(err)) -+ goto out; -+ } -+ -+out: -+ if (mtx) -+ mutex_unlock(mtx); -+ 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; -+ struct mutex *mtx; -+ ino_t h_ino, ino; -+ int err; -+ aufs_bindex_t bstart; -+ -+ sb = dentry->d_sb; -+ bstart = au_dbstart(dentry); -+ h_dentry = au_h_dptr(dentry, bstart); -+ h_inode = d_inode(h_dentry); -+ h_ino = h_inode->i_ino; -+ -+ /* -+ * stop 'race'-ing between hardlinks under different -+ * parents. -+ */ -+ mtx = NULL; -+ if (!d_is_dir(h_dentry)) -+ mtx = &au_sbr(sb, bstart)->br_xino.xi_nondir_mtx; -+ -+new_ino: -+ if (mtx) -+ mutex_lock(mtx); -+ err = au_xino_read(sb, bstart, h_ino, &ino); -+ inode = ERR_PTR(err); -+ if (unlikely(err)) -+ goto out; -+ -+ if (!ino) { -+ ino = au_xino_new_ino(sb); -+ if (unlikely(!ino)) { -+ inode = ERR_PTR(-EIO); -+ goto out; -+ } -+ } -+ -+ AuDbg("i%lu\n", (unsigned long)ino); -+ inode = au_iget_locked(sb, ino); -+ err = PTR_ERR(inode); -+ if (IS_ERR(inode)) -+ goto out; -+ -+ AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW)); -+ if (inode->i_state & I_NEW) { -+ /* verbose coding for lock class name */ -+ if (unlikely(d_is_symlink(h_dentry))) -+ au_rw_class(&au_ii(inode)->ii_rwsem, -+ au_lc_key + AuLcSymlink_IIINFO); -+ else if (unlikely(d_is_dir(h_dentry))) -+ au_rw_class(&au_ii(inode)->ii_rwsem, -+ au_lc_key + AuLcDir_IIINFO); -+ else /* likely */ -+ au_rw_class(&au_ii(inode)->ii_rwsem, -+ au_lc_key + AuLcNonDir_IIINFO); -+ -+ ii_write_lock_new_child(inode); -+ err = set_inode(inode, dentry); -+ if (!err) { -+ unlock_new_inode(inode); -+ goto out; /* 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, bstart, 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 (mtx) -+ mutex_unlock(mtx); -+ err = reval_inode(inode, dentry); -+ if (unlikely(err < 0)) { -+ mtx = NULL; -+ goto out_iput; -+ } -+ -+ if (!err) { -+ mtx = NULL; -+ goto out; /* success */ -+ } else if (mtx) -+ mutex_lock(mtx); -+ } -+ -+ 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", -+ bstart, au_sbtype(h_dentry->d_sb), dentry, -+ (unsigned long)h_ino, (unsigned long)ino); -+ ino = 0; -+ err = au_xino_write(sb, bstart, h_ino, /*ino*/0); -+ if (!err) { -+ iput(inode); -+ if (mtx) -+ mutex_unlock(mtx); -+ goto new_ino; -+ } -+ -+out_iput: -+ iput(inode); -+ inode = ERR_PTR(err); -+out: -+ if (mtx) -+ mutex_unlock(mtx); -+ 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_ibstart(inode) <= bindex -+ && bindex <= au_ibend(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 inode *h_inode, int mask) -+{ -+ if (uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) -+ return 0; -+ return inode_permission(h_inode, mask); -+} -+ -+int au_test_h_perm_sio(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_inode, mask); -+} -diff --git a/fs/aufs/inode.h b/fs/aufs/inode.h -new file mode 100644 -index 0000000..31e31f4 ---- /dev/null -+++ b/fs/aufs/inode.h -@@ -0,0 +1,672 @@ -+/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima -+ */ -+ -+/* -+ * 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 */ -+#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_bstart, ii_bend; -+ __u32 ii_higen; -+ struct au_hinode *ii_hinode; -+ struct au_vdir *ii_vdir; -+}; -+ -+struct au_icntnr { -+ struct au_iinfo iinfo; -+ struct inode vfs_inode; -+} ____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_set_owner(struct au_pin *p, struct task_struct *task); -+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) -+{ -+ struct au_iinfo *iinfo; -+ -+ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); -+ if (iinfo->ii_hinode) -+ return iinfo; -+ return NULL; /* debugging bad_inode case */ -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* 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 inode *h_inode, int mask); -+int au_test_h_perm_sio(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], -+ 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, int force, struct path *h_path); -+ -+/* 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 inode *dir, struct dentry *dentry, umode_t mode, -+ dev_t dev); -+int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); -+int aufs_create(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 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 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 inode *src_dir, struct dentry *src_dentry, -+ struct inode *dir, struct dentry *dentry); -+ -+/* 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); -+int au_iinfo_init(struct inode *inode); -+void au_iinfo_fin(struct inode *inode); -+int au_ii_realloc(struct au_iinfo *iinfo, int nbr); -+ -+#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 dentry *h_dst, struct dentry *h_src, int ignore_flags, -+ unsigned int verbose); -+ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size); -+ssize_t aufs_getxattr(struct dentry *dentry, const char *name, void *value, -+ size_t size); -+int aufs_setxattr(struct dentry *dentry, const char *name, const void *value, -+ size_t size, int flags); -+int aufs_removexattr(struct dentry *dentry, const char *name); -+ -+/* void au_xattr_init(struct super_block *sb); */ -+#else -+AuStubInt0(au_cpup_xattr, struct dentry *h_dst, struct dentry *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); -+int aufs_set_acl(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_XATTR_REMOVE, -+ AU_ACL_SET -+}; -+ -+struct au_srxattr { -+ int type; -+ union { -+ struct { -+ const char *name; -+ const void *value; -+ size_t size; -+ int flags; -+ } set; -+ struct { -+ const char *name; -+ } remove; -+ struct { -+ struct posix_acl *acl; -+ int type; -+ } acl_set; -+ } u; -+}; -+ssize_t au_srxattr(struct dentry *dentry, struct au_srxattr *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 -+ -+/* -+ * ii_read_unlock, ii_write_unlock, ii_downgrade_lock -+ */ -+AuSimpleUnlockRwsemFuncs(ii, struct inode *i, &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, struct au_iigen *iigen_arg) -+{ -+ 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 (iigen_arg) -+ *iigen_arg = *iigen; -+ 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 aufs_bindex_t au_ii_br_id(struct inode *inode, -+ aufs_bindex_t bindex) -+{ -+ IiMustAnyLock(inode); -+ return au_ii(inode)->ii_hinode[0 + bindex].hi_id; -+} -+ -+static inline aufs_bindex_t au_ibstart(struct inode *inode) -+{ -+ IiMustAnyLock(inode); -+ return au_ii(inode)->ii_bstart; -+} -+ -+static inline aufs_bindex_t au_ibend(struct inode *inode) -+{ -+ IiMustAnyLock(inode); -+ return au_ii(inode)->ii_bend; -+} -+ -+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_ii(inode)->ii_hinode[0 + bindex].hi_whdentry; -+} -+ -+static inline void au_set_ibstart(struct inode *inode, aufs_bindex_t bindex) -+{ -+ IiMustWriteLock(inode); -+ au_ii(inode)->ii_bstart = bindex; -+} -+ -+static inline void au_set_ibend(struct inode *inode, aufs_bindex_t bindex) -+{ -+ IiMustWriteLock(inode); -+ au_ii(inode)->ii_bend = 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_ii(inode)->ii_hinode + 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 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, -+ 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_imtx_lock(struct au_hinode *hdir) -+{ -+ mutex_lock(&hdir->hi_inode->i_mutex); -+ au_hn_suspend(hdir); -+} -+ -+static inline void au_hn_imtx_lock_nested(struct au_hinode *hdir, -+ unsigned int sc __maybe_unused) -+{ -+ mutex_lock_nested(&hdir->hi_inode->i_mutex, sc); -+ au_hn_suspend(hdir); -+} -+ -+static inline void au_hn_imtx_unlock(struct au_hinode *hdir) -+{ -+ au_hn_resume(hdir); -+ mutex_unlock(&hdir->hi_inode->i_mutex); -+} -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_INODE_H__ */ -diff --git a/fs/aufs/ioctl.c b/fs/aufs/ioctl.c -new file mode 100644 -index 0000000..87e3ddc ---- /dev/null -+++ b/fs/aufs/ioctl.c -@@ -0,0 +1,206 @@ -+/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima -+ */ -+ -+/* -+ * 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, bend; -+ 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); -+ bend = au_sbend(sb); -+ if (wbrfd.brid >= 0) { -+ wbi = au_br_index(sb, wbrfd.brid); -+ if (unlikely(wbi < 0 || wbi > bend)) -+ 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 <= bend; 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; -+ -+ atomic_dec(&br->br_count); /* 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 --git a/fs/aufs/loop.c b/fs/aufs/loop.c -new file mode 100644 -index 0000000..f324758 ---- /dev/null -+++ b/fs/aufs/loop.c +diff -Nurp linux-4.4.3/fs/aufs/Kconfig linux-4.4.3-aufs/fs/aufs/Kconfig +--- linux-4.4.3/fs/aufs/Kconfig 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/Kconfig 2016-03-02 17:59:37.360498681 +0200 +@@ -0,0 +1,185 @@ ++config AUFS_FS ++ bool "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 = y ++ 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_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 -Nurp linux-4.4.3/fs/aufs/loop.c linux-4.4.3-aufs/fs/aufs/loop.c +--- linux-4.4.3/fs/aufs/loop.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/loop.c 2016-03-02 17:59:37.369498746 +0200 @@ -0,0 +1,133 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -20205,14 +20125,12 @@ index 0000000..f324758 + symbol_put(loop_backing_file); + kfree(au_warn_loopback_array); +} -diff --git a/fs/aufs/loop.h b/fs/aufs/loop.h -new file mode 100644 -index 0000000..6d9864d ---- /dev/null -+++ b/fs/aufs/loop.h +diff -Nurp linux-4.4.3/fs/aufs/loop.h linux-4.4.3-aufs/fs/aufs/loop.h +--- linux-4.4.3/fs/aufs/loop.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/loop.h 2016-03-02 17:59:37.369498746 +0200 @@ -0,0 +1,39 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -20250,11 +20168,9 @@ index 0000000..6d9864d + +#endif /* __KERNEL__ */ +#endif /* __AUFS_LOOP_H__ */ -diff --git a/fs/aufs/magic.mk b/fs/aufs/magic.mk -new file mode 100644 -index 0000000..4f83bdf ---- /dev/null -+++ b/fs/aufs/magic.mk +diff -Nurp linux-4.4.3/fs/aufs/magic.mk linux-4.4.3-aufs/fs/aufs/magic.mk +--- linux-4.4.3/fs/aufs/magic.mk 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/magic.mk 2016-03-02 17:59:37.369498746 +0200 @@ -0,0 +1,30 @@ + +# defined in ${srctree}/fs/fuse/inode.c @@ -20286,14 +20202,52 @@ index 0000000..4f83bdf +ifdef CONFIG_HFSPLUS_FS +ccflags-y += -DHFSPLUS_SUPER_MAGIC=0x482b +endif -diff --git a/fs/aufs/module.c b/fs/aufs/module.c -new file mode 100644 -index 0000000..3268e62 ---- /dev/null -+++ b/fs/aufs/module.c +diff -Nurp linux-4.4.3/fs/aufs/Makefile linux-4.4.3-aufs/fs/aufs/Makefile +--- linux-4.4.3/fs/aufs/Makefile 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/Makefile 2016-03-02 17:59:37.361498688 +0200 +@@ -0,0 +1,36 @@ ++ ++include ${srctree}/${src}/magic.mk ++ ++# cf. include/linux/kernel.h ++# enable pr_debug ++ccflags-y += -DDEBUG ++# sparse requires the full pathname ++ccflags-y += -include ${srctree}/include/uapi/linux/aufs_type.h ++ ++obj-$(CONFIG_AUFS_FS) += aufs.o ++aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.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_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 -Nurp linux-4.4.3/fs/aufs/module.c linux-4.4.3-aufs/fs/aufs/module.c +--- linux-4.4.3/fs/aufs/module.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/module.c 2016-03-02 17:59:37.369498746 +0200 @@ -0,0 +1,207 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -20389,7 +20343,7 @@ index 0000000..3268e62 +module_param_named(brs, sysaufs_brs, int, S_IRUGO); + +/* this module parameter has no meaning when USER_NS is disabled */ -+static bool au_userns; ++bool au_userns; +MODULE_PARM_DESC(allow_userns, "allow unprivileged to mount under userns"); +module_param_named(allow_userns, au_userns, bool, S_IRUGO); + @@ -20499,14 +20453,12 @@ index 0000000..3268e62 + +module_init(aufs_init); +module_exit(aufs_exit); -diff --git a/fs/aufs/module.h b/fs/aufs/module.h -new file mode 100644 -index 0000000..adee827 ---- /dev/null -+++ b/fs/aufs/module.h -@@ -0,0 +1,91 @@ +diff -Nurp linux-4.4.3/fs/aufs/module.h linux-4.4.3-aufs/fs/aufs/module.h +--- linux-4.4.3/fs/aufs/module.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/module.h 2016-03-02 17:59:37.369498746 +0200 +@@ -0,0 +1,92 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -20525,6 +20477,7 @@ index 0000000..adee827 + +/* module parameters */ +extern int sysaufs_brs; ++extern bool au_userns; + +/* ---------------------------------------------------------------------- */ + @@ -20596,14 +20549,12 @@ index 0000000..adee827 + +#endif /* __KERNEL__ */ +#endif /* __AUFS_MODULE_H__ */ -diff --git a/fs/aufs/mvdown.c b/fs/aufs/mvdown.c -new file mode 100644 -index 0000000..53e0f6a ---- /dev/null -+++ b/fs/aufs/mvdown.c +diff -Nurp linux-4.4.3/fs/aufs/mvdown.c linux-4.4.3-aufs/fs/aufs/mvdown.c +--- linux-4.4.3/fs/aufs/mvdown.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/mvdown.c 2016-03-02 17:59:37.370498753 +0200 @@ -0,0 +1,690 @@ +/* -+ * Copyright (C) 2011-2015 Junjiro R. Okajima ++ * Copyright (C) 2011-2016 Junjiro R. Okajima + */ + +/* @@ -21292,14 +21243,12 @@ index 0000000..53e0f6a + AuTraceErr(err); + return err; +} -diff --git a/fs/aufs/opts.c b/fs/aufs/opts.c -new file mode 100644 -index 0000000..f79d15e ---- /dev/null -+++ b/fs/aufs/opts.c +diff -Nurp linux-4.4.3/fs/aufs/opts.c linux-4.4.3-aufs/fs/aufs/opts.c +--- linux-4.4.3/fs/aufs/opts.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/opts.c 2016-03-02 17:59:37.370498753 +0200 @@ -0,0 +1,1846 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -23144,14 +23093,12 @@ index 0000000..f79d15e +{ + return au_mntflags(sb) & AuOptMask_UDBA; +} -diff --git a/fs/aufs/opts.h b/fs/aufs/opts.h -new file mode 100644 -index 0000000..3899e92 ---- /dev/null -+++ b/fs/aufs/opts.h +diff -Nurp linux-4.4.3/fs/aufs/opts.h linux-4.4.3-aufs/fs/aufs/opts.h +--- linux-4.4.3/fs/aufs/opts.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/opts.h 2016-03-02 17:59:37.370498753 +0200 @@ -0,0 +1,198 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -23348,14 +23295,12 @@ index 0000000..3899e92 + +#endif /* __KERNEL__ */ +#endif /* __AUFS_OPTS_H__ */ -diff --git a/fs/aufs/plink.c b/fs/aufs/plink.c -new file mode 100644 -index 0000000..af2246c ---- /dev/null -+++ b/fs/aufs/plink.c +diff -Nurp linux-4.4.3/fs/aufs/plink.c linux-4.4.3-aufs/fs/aufs/plink.c +--- linux-4.4.3/fs/aufs/plink.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/plink.c 2016-03-02 17:59:37.370498753 +0200 @@ -0,0 +1,515 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -23869,14 +23814,12 @@ index 0000000..af2246c + } + } +} -diff --git a/fs/aufs/poll.c b/fs/aufs/poll.c -new file mode 100644 -index 0000000..c324fc7 ---- /dev/null -+++ b/fs/aufs/poll.c +diff -Nurp linux-4.4.3/fs/aufs/poll.c linux-4.4.3-aufs/fs/aufs/poll.c +--- linux-4.4.3/fs/aufs/poll.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/poll.c 2016-03-02 17:59:37.370498753 +0200 @@ -0,0 +1,39 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -23914,14 +23857,12 @@ index 0000000..c324fc7 + AuTraceErr((int)mask); + return mask; +} -diff --git a/fs/aufs/posix_acl.c b/fs/aufs/posix_acl.c -new file mode 100644 -index 0000000..d9ce957 ---- /dev/null -+++ b/fs/aufs/posix_acl.c -@@ -0,0 +1,86 @@ +diff -Nurp linux-4.4.3/fs/aufs/posix_acl.c linux-4.4.3-aufs/fs/aufs/posix_acl.c +--- linux-4.4.3/fs/aufs/posix_acl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/posix_acl.c 2016-03-02 17:59:37.371498760 +0200 +@@ -0,0 +1,85 @@ +/* -+ * Copyright (C) 2014-2015 Junjiro R. Okajima ++ * Copyright (C) 2014-2016 Junjiro R. Okajima + */ + +/* @@ -23929,7 +23870,6 @@ index 0000000..d9ce957 + */ + +#include -+#include +#include "aufs.h" + +struct posix_acl *aufs_get_acl(struct inode *inode, int type) @@ -24006,14 +23946,12 @@ index 0000000..d9ce957 + mutex_unlock(&inode->i_mutex); + return err; +} -diff --git a/fs/aufs/procfs.c b/fs/aufs/procfs.c -new file mode 100644 -index 0000000..ead2a00 ---- /dev/null -+++ b/fs/aufs/procfs.c +diff -Nurp linux-4.4.3/fs/aufs/procfs.c linux-4.4.3-aufs/fs/aufs/procfs.c +--- linux-4.4.3/fs/aufs/procfs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/procfs.c 2016-03-02 17:59:37.371498760 +0200 @@ -0,0 +1,156 @@ +/* -+ * Copyright (C) 2010-2015 Junjiro R. Okajima ++ * Copyright (C) 2010-2016 Junjiro R. Okajima + */ + +/* @@ -24168,14 +24106,12 @@ index 0000000..ead2a00 +out: + return err; +} -diff --git a/fs/aufs/rdu.c b/fs/aufs/rdu.c -new file mode 100644 -index 0000000..f11d9bb ---- /dev/null -+++ b/fs/aufs/rdu.c +diff -Nurp linux-4.4.3/fs/aufs/rdu.c linux-4.4.3-aufs/fs/aufs/rdu.c +--- linux-4.4.3/fs/aufs/rdu.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/rdu.c 2016-03-02 17:59:37.371498760 +0200 @@ -0,0 +1,375 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -24549,14 +24485,12 @@ index 0000000..f11d9bb + return err; +} +#endif -diff --git a/fs/aufs/rwsem.h b/fs/aufs/rwsem.h -new file mode 100644 -index 0000000..171ee0c ---- /dev/null -+++ b/fs/aufs/rwsem.h +diff -Nurp linux-4.4.3/fs/aufs/rwsem.h linux-4.4.3-aufs/fs/aufs/rwsem.h +--- linux-4.4.3/fs/aufs/rwsem.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/rwsem.h 2016-03-02 17:59:37.371498760 +0200 @@ -0,0 +1,178 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -24733,14 +24667,12 @@ index 0000000..171ee0c + +#endif /* __KERNEL__ */ +#endif /* __AUFS_RWSEM_H__ */ -diff --git a/fs/aufs/sbinfo.c b/fs/aufs/sbinfo.c -new file mode 100644 -index 0000000..8f2ec55 ---- /dev/null -+++ b/fs/aufs/sbinfo.c +diff -Nurp linux-4.4.3/fs/aufs/sbinfo.c linux-4.4.3-aufs/fs/aufs/sbinfo.c +--- linux-4.4.3/fs/aufs/sbinfo.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/sbinfo.c 2016-03-02 17:59:37.371498760 +0200 @@ -0,0 +1,353 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -25092,14 +25024,12 @@ index 0000000..8f2ec55 + p = radix_tree_delete(&sbinfo->au_si_pid.tree, current->pid); + spin_unlock(&sbinfo->au_si_pid.tree_lock); +} -diff --git a/fs/aufs/spl.h b/fs/aufs/spl.h -new file mode 100644 -index 0000000..a66d39e ---- /dev/null -+++ b/fs/aufs/spl.h +diff -Nurp linux-4.4.3/fs/aufs/spl.h linux-4.4.3-aufs/fs/aufs/spl.h +--- linux-4.4.3/fs/aufs/spl.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/spl.h 2016-03-02 17:59:37.371498760 +0200 @@ -0,0 +1,98 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -25196,14 +25126,12 @@ index 0000000..a66d39e + +#endif /* __KERNEL__ */ +#endif /* __AUFS_SPL_H__ */ -diff --git a/fs/aufs/super.c b/fs/aufs/super.c -new file mode 100644 -index 0000000..98cfd64 ---- /dev/null -+++ b/fs/aufs/super.c +diff -Nurp linux-4.4.3/fs/aufs/super.c linux-4.4.3-aufs/fs/aufs/super.c +--- linux-4.4.3/fs/aufs/super.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/super.c 2016-03-02 17:59:37.372498767 +0200 @@ -0,0 +1,1026 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -26228,14 +26156,12 @@ index 0000000..98cfd64 + /* no need to __module_get() and module_put(). */ + .owner = THIS_MODULE, +}; -diff --git a/fs/aufs/super.h b/fs/aufs/super.h -new file mode 100644 -index 0000000..d151729 ---- /dev/null -+++ b/fs/aufs/super.h +diff -Nurp linux-4.4.3/fs/aufs/super.h linux-4.4.3-aufs/fs/aufs/super.h +--- linux-4.4.3/fs/aufs/super.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/super.h 2016-03-02 17:59:37.372498767 +0200 @@ -0,0 +1,628 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -26862,14 +26788,12 @@ index 0000000..d151729 + +#endif /* __KERNEL__ */ +#endif /* __AUFS_SUPER_H__ */ -diff --git a/fs/aufs/sysaufs.c b/fs/aufs/sysaufs.c -new file mode 100644 -index 0000000..29ac6fa ---- /dev/null -+++ b/fs/aufs/sysaufs.c +diff -Nurp linux-4.4.3/fs/aufs/sysaufs.c linux-4.4.3-aufs/fs/aufs/sysaufs.c +--- linux-4.4.3/fs/aufs/sysaufs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/sysaufs.c 2016-03-02 17:59:37.372498767 +0200 @@ -0,0 +1,91 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -26959,14 +26883,12 @@ index 0000000..29ac6fa +out: + return err; +} -diff --git a/fs/aufs/sysaufs.h b/fs/aufs/sysaufs.h -new file mode 100644 -index 0000000..feb78fd ---- /dev/null -+++ b/fs/aufs/sysaufs.h +diff -Nurp linux-4.4.3/fs/aufs/sysaufs.h linux-4.4.3-aufs/fs/aufs/sysaufs.h +--- linux-4.4.3/fs/aufs/sysaufs.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/sysaufs.h 2016-03-02 17:59:37.372498767 +0200 @@ -0,0 +1,88 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -27053,14 +26975,12 @@ index 0000000..feb78fd + +#endif /* __KERNEL__ */ +#endif /* __SYSAUFS_H__ */ -diff --git a/fs/aufs/sysfs.c b/fs/aufs/sysfs.c -new file mode 100644 -index 0000000..ec8df8f ---- /dev/null -+++ b/fs/aufs/sysfs.c +diff -Nurp linux-4.4.3/fs/aufs/sysfs.c linux-4.4.3-aufs/fs/aufs/sysfs.c +--- linux-4.4.3/fs/aufs/sysfs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/sysfs.c 2016-03-02 17:59:37.372498767 +0200 @@ -0,0 +1,340 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -27399,14 +27319,12 @@ index 0000000..ec8df8f + } + } +} -diff --git a/fs/aufs/sysrq.c b/fs/aufs/sysrq.c -new file mode 100644 -index 0000000..3a0182b ---- /dev/null -+++ b/fs/aufs/sysrq.c +diff -Nurp linux-4.4.3/fs/aufs/sysrq.c linux-4.4.3-aufs/fs/aufs/sysrq.c +--- linux-4.4.3/fs/aufs/sysrq.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/sysrq.c 2016-03-02 17:59:37.372498767 +0200 @@ -0,0 +1,144 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -27549,14 +27467,12 @@ index 0000000..3a0182b + if (unlikely(err)) + pr_err("err %d (ignored)\n", err); +} -diff --git a/fs/aufs/vdir.c b/fs/aufs/vdir.c -new file mode 100644 -index 0000000..db81f49 ---- /dev/null -+++ b/fs/aufs/vdir.c +diff -Nurp linux-4.4.3/fs/aufs/vdir.c linux-4.4.3-aufs/fs/aufs/vdir.c +--- linux-4.4.3/fs/aufs/vdir.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/vdir.c 2016-03-02 17:59:37.372498767 +0200 @@ -0,0 +1,875 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -28430,14 +28346,12 @@ index 0000000..db81f49 + /* smp_mb(); */ + return 0; +} -diff --git a/fs/aufs/vfsub.c b/fs/aufs/vfsub.c -new file mode 100644 -index 0000000..da0df5a ---- /dev/null -+++ b/fs/aufs/vfsub.c -@@ -0,0 +1,835 @@ +diff -Nurp linux-4.4.3/fs/aufs/vfsub.c linux-4.4.3-aufs/fs/aufs/vfsub.c +--- linux-4.4.3/fs/aufs/vfsub.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/vfsub.c 2016-03-02 17:59:37.373498774 +0200 +@@ -0,0 +1,853 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -28445,10 +28359,28 @@ index 0000000..da0df5a + */ + +#include ++#include +#include +#include ++#include "../fs/mount.h" +#include "aufs.h" + ++#ifdef CONFIG_AUFS_BR_FUSE ++int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb) ++{ ++ struct nsproxy *ns; ++ ++ if (!au_test_fuse(h_sb) || !au_userns) ++ return 0; ++ ++ ns = current->nsproxy; ++ /* no {get,put}_nsproxy(ns) */ ++ return real_mount(mnt)->mnt_ns == ns->mnt_ns ? 0 : -EACCES; ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ +int vfsub_update_h_iattr(struct path *h_path, int *did) +{ + int err; @@ -29271,14 +29203,12 @@ index 0000000..da0df5a + + return err; +} -diff --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h -new file mode 100644 -index 0000000..4218da1 ---- /dev/null -+++ b/fs/aufs/vfsub.h -@@ -0,0 +1,274 @@ +diff -Nurp linux-4.4.3/fs/aufs/vfsub.h linux-4.4.3-aufs/fs/aufs/vfsub.h +--- linux-4.4.3/fs/aufs/vfsub.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/vfsub.h 2016-03-02 17:59:37.373498774 +0200 +@@ -0,0 +1,295 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -29292,6 +29222,7 @@ index 0000000..4218da1 + +#include +#include ++#include +#include +#include "debug.h" + @@ -29342,6 +29273,12 @@ index 0000000..4218da1 + || 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_update_h_iattr(struct path *h_path, int *did); @@ -29481,6 +29418,20 @@ index 0000000..4218da1 + /* no vfsub_update_h_iattr() since we don't have struct path */ +} + ++#ifdef CONFIG_FS_POSIX_ACL ++static inline int vfsub_acl_chmod(struct inode *h_inode, umode_t h_mode) ++{ ++ int err; ++ ++ err = posix_acl_chmod(h_inode, h_mode); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ return err; ++} ++#else ++AuStubInt0(vfsub_acl_chmod, 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); @@ -29551,14 +29502,12 @@ index 0000000..4218da1 + +#endif /* __KERNEL__ */ +#endif /* __AUFS_VFSUB_H__ */ -diff --git a/fs/aufs/wbr_policy.c b/fs/aufs/wbr_policy.c -new file mode 100644 -index 0000000..53a01fb ---- /dev/null -+++ b/fs/aufs/wbr_policy.c +diff -Nurp linux-4.4.3/fs/aufs/wbr_policy.c linux-4.4.3-aufs/fs/aufs/wbr_policy.c +--- linux-4.4.3/fs/aufs/wbr_policy.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/wbr_policy.c 2016-03-02 17:59:37.373498774 +0200 @@ -0,0 +1,752 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -30309,14 +30258,12 @@ index 0000000..53a01fb + .fin = au_wbr_create_fin_mfs + } +}; -diff --git a/fs/aufs/whout.c b/fs/aufs/whout.c -new file mode 100644 -index 0000000..05ba085 ---- /dev/null -+++ b/fs/aufs/whout.c +diff -Nurp linux-4.4.3/fs/aufs/whout.c linux-4.4.3-aufs/fs/aufs/whout.c +--- linux-4.4.3/fs/aufs/whout.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/whout.c 2016-03-02 17:59:37.374498781 +0200 @@ -0,0 +1,1047 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -31362,14 +31309,12 @@ index 0000000..05ba085 + au_whtmp_rmdir_free(args); + } +} -diff --git a/fs/aufs/whout.h b/fs/aufs/whout.h -new file mode 100644 -index 0000000..b39acea ---- /dev/null -+++ b/fs/aufs/whout.h +diff -Nurp linux-4.4.3/fs/aufs/whout.h linux-4.4.3-aufs/fs/aufs/whout.h +--- linux-4.4.3/fs/aufs/whout.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/whout.h 2016-03-02 17:59:37.374498781 +0200 @@ -0,0 +1,72 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -31440,14 +31385,12 @@ index 0000000..b39acea + +#endif /* __KERNEL__ */ +#endif /* __AUFS_WHOUT_H__ */ -diff --git a/fs/aufs/wkq.c b/fs/aufs/wkq.c -new file mode 100644 -index 0000000..08870ec ---- /dev/null -+++ b/fs/aufs/wkq.c +diff -Nurp linux-4.4.3/fs/aufs/wkq.c linux-4.4.3-aufs/fs/aufs/wkq.c +--- linux-4.4.3/fs/aufs/wkq.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/wkq.c 2016-03-02 17:59:37.374498781 +0200 @@ -0,0 +1,200 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -31646,14 +31589,12 @@ index 0000000..08870ec + + return err; +} -diff --git a/fs/aufs/wkq.h b/fs/aufs/wkq.h -new file mode 100644 -index 0000000..8f01343 ---- /dev/null -+++ b/fs/aufs/wkq.h +diff -Nurp linux-4.4.3/fs/aufs/wkq.h linux-4.4.3-aufs/fs/aufs/wkq.h +--- linux-4.4.3/fs/aufs/wkq.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/wkq.h 2016-03-02 17:59:37.374498781 +0200 @@ -0,0 +1,78 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -31730,14 +31671,12 @@ index 0000000..8f01343 + +#endif /* __KERNEL__ */ +#endif /* __AUFS_WKQ_H__ */ -diff --git a/fs/aufs/xattr.c b/fs/aufs/xattr.c -new file mode 100644 -index 0000000..c1695b3 ---- /dev/null -+++ b/fs/aufs/xattr.c +diff -Nurp linux-4.4.3/fs/aufs/xattr.c linux-4.4.3-aufs/fs/aufs/xattr.c +--- linux-4.4.3/fs/aufs/xattr.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/xattr.c 2016-03-02 17:59:37.375498789 +0200 @@ -0,0 +1,331 @@ +/* -+ * Copyright (C) 2014-2015 Junjiro R. Okajima ++ * Copyright (C) 2014-2016 Junjiro R. Okajima + */ + +/* @@ -32067,14 +32006,12 @@ index 0000000..c1695b3 + /* sb->s_xattr = au_xattr_handlers; */ +} +#endif -diff --git a/fs/aufs/xino.c b/fs/aufs/xino.c -new file mode 100644 -index 0000000..90de8c5 ---- /dev/null -+++ b/fs/aufs/xino.c -@@ -0,0 +1,1283 @@ +diff -Nurp linux-4.4.3/fs/aufs/xino.c linux-4.4.3-aufs/fs/aufs/xino.c +--- linux-4.4.3/fs/aufs/xino.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/fs/aufs/xino.c 2016-03-02 17:59:37.376498796 +0200 +@@ -0,0 +1,1305 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +/* @@ -32115,6 +32052,9 @@ index 0000000..90de8c5 + +/* ---------------------------------------------------------------------- */ + ++static ssize_t xino_fwrite_wkq(vfs_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos); ++ +static ssize_t do_xino_fwrite(vfs_writef_t func, struct file *file, void *kbuf, + size_t size, loff_t *pos) +{ @@ -32124,14 +32064,26 @@ index 0000000..90de8c5 + void *k; + const char __user *u; + } buf; ++ int i; ++ const int prevent_endless = 10; + ++ i = 0; + buf.k = kbuf; + oldfs = get_fs(); + set_fs(KERNEL_DS); + do { -+ /* todo: signal_pending? */ + err = func(file, buf.u, size, pos); -+ } while (err == -EAGAIN || err == -EINTR); ++ if (err == -EINTR ++ && !au_wkq_test() ++ && fatal_signal_pending(current)) { ++ set_fs(oldfs); ++ err = xino_fwrite_wkq(func, file, kbuf, size, pos); ++ BUG_ON(err == -EINTR); ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ } ++ } while (i++ < prevent_endless ++ && (err == -EAGAIN || err == -EINTR)); + set_fs(oldfs); + +#if 0 /* reserved for future use */ @@ -32157,35 +32109,42 @@ index 0000000..90de8c5 + *a->errp = do_xino_fwrite(a->func, a->file, a->buf, a->size, a->pos); +} + ++static ssize_t xino_fwrite_wkq(vfs_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ int wkq_err; ++ struct do_xino_fwrite_args args = { ++ .errp = &err, ++ .func = func, ++ .file = file, ++ .buf = buf, ++ .size = size, ++ .pos = pos ++ }; ++ ++ /* ++ * it breaks RLIMIT_FSIZE and normal user's limit, ++ * users should care about quota and real 'filesystem full.' ++ */ ++ wkq_err = au_wkq_wait(call_do_xino_fwrite, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ +ssize_t xino_fwrite(vfs_writef_t func, struct file *file, void *buf, + size_t size, loff_t *pos) +{ + ssize_t err; + -+ /* todo: signal block and no wkq? */ + if (rlimit(RLIMIT_FSIZE) == RLIM_INFINITY) { + lockdep_off(); + err = do_xino_fwrite(func, file, buf, size, pos); + lockdep_on(); -+ } else { -+ /* -+ * it breaks RLIMIT_FSIZE and normal user's limit, -+ * users should care about quota and real 'filesystem full.' -+ */ -+ int wkq_err; -+ struct do_xino_fwrite_args args = { -+ .errp = &err, -+ .func = func, -+ .file = file, -+ .buf = buf, -+ .size = size, -+ .pos = pos -+ }; -+ -+ wkq_err = au_wkq_wait(call_do_xino_fwrite, &args); -+ if (unlikely(wkq_err)) -+ err = wkq_err; -+ } ++ } else ++ err = xino_fwrite_wkq(func, file, buf, size, pos); + + return err; +} @@ -33356,10 +33315,9 @@ index 0000000..90de8c5 +out: + return err; +} -diff --git a/fs/dcache.c b/fs/dcache.c -index 5c33aeb..8aa7f26 100644 ---- a/fs/dcache.c -+++ b/fs/dcache.c +diff -Nurp linux-4.4.3/fs/dcache.c linux-4.4.3-aufs/fs/dcache.c +--- linux-4.4.3/fs/dcache.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/fs/dcache.c 2016-03-02 17:59:37.376498796 +0200 @@ -1167,7 +1167,7 @@ enum d_walk_ret { * * The @enter() and @finish() callbacks are called with d_lock held. @@ -33369,11 +33327,50 @@ index 5c33aeb..8aa7f26 100644 enum d_walk_ret (*enter)(void *, struct dentry *), void (*finish)(void *)) { -diff --git a/fs/proc/base.c b/fs/proc/base.c -index bd3e9e6..fc42216 100644 ---- a/fs/proc/base.c -+++ b/fs/proc/base.c -@@ -1921,7 +1921,7 @@ static int proc_map_files_get_link(struct dentry *dentry, struct path *path) +diff -Nurp linux-4.4.3/fs/fcntl.c linux-4.4.3-aufs/fs/fcntl.c +--- linux-4.4.3/fs/fcntl.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/fs/fcntl.c 2016-03-02 17:59:37.376498796 +0200 +@@ -29,7 +29,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; +@@ -59,6 +59,8 @@ static int setfl(int fd, struct file * f + + 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 -Nurp linux-4.4.3/fs/Kconfig linux-4.4.3-aufs/fs/Kconfig +--- linux-4.4.3/fs/Kconfig 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/fs/Kconfig 2016-03-02 17:59:37.360498681 +0200 +@@ -221,6 +221,7 @@ source "fs/pstore/Kconfig" + source "fs/sysv/Kconfig" + source "fs/ufs/Kconfig" + source "fs/exofs/Kconfig" ++source "fs/aufs/Kconfig" + + endif # MISC_FILESYSTEMS + +diff -Nurp linux-4.4.3/fs/Makefile linux-4.4.3-aufs/fs/Makefile +--- linux-4.4.3/fs/Makefile 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/fs/Makefile 2016-03-02 17:59:37.360498681 +0200 +@@ -126,3 +126,4 @@ obj-y += exofs/ # Multiple modules + obj-$(CONFIG_CEPH_FS) += ceph/ + obj-$(CONFIG_PSTORE) += pstore/ + obj-$(CONFIG_EFIVAR_FS) += efivarfs/ ++obj-$(CONFIG_AUFS_FS) += aufs/ +diff -Nurp linux-4.4.3/fs/proc/base.c linux-4.4.3-aufs/fs/proc/base.c +--- linux-4.4.3/fs/proc/base.c 2016-03-02 17:42:59.444713286 +0200 ++++ linux-4.4.3-aufs/fs/proc/base.c 2016-03-02 17:59:37.376498796 +0200 +@@ -1922,7 +1922,7 @@ static int proc_map_files_get_link(struc down_read(&mm->mmap_sem); vma = find_exact_vma(mm, vm_start, vm_end); if (vma && vma->vm_file) { @@ -33382,11 +33379,10 @@ index bd3e9e6..fc42216 100644 path_get(path); rc = 0; } -diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c -index f8595e8..cb8eda0 100644 ---- a/fs/proc/nommu.c -+++ b/fs/proc/nommu.c -@@ -45,7 +45,10 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region) +diff -Nurp linux-4.4.3/fs/proc/nommu.c linux-4.4.3-aufs/fs/proc/nommu.c +--- linux-4.4.3/fs/proc/nommu.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/fs/proc/nommu.c 2016-03-02 17:59:37.377498803 +0200 +@@ -45,7 +45,10 @@ static int nommu_region_show(struct seq_ file = region->vm_file; if (file) { @@ -33398,11 +33394,10 @@ index f8595e8..cb8eda0 100644 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 187b3b5..e03793e 100644 ---- a/fs/proc/task_mmu.c -+++ b/fs/proc/task_mmu.c -@@ -281,7 +281,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) +diff -Nurp linux-4.4.3/fs/proc/task_mmu.c linux-4.4.3-aufs/fs/proc/task_mmu.c +--- linux-4.4.3/fs/proc/task_mmu.c 2016-03-02 17:42:59.444713286 +0200 ++++ linux-4.4.3-aufs/fs/proc/task_mmu.c 2016-03-02 17:59:37.377498803 +0200 +@@ -281,7 +281,10 @@ show_map_vma(struct seq_file *m, struct const char *name = NULL; if (file) { @@ -33414,7 +33409,7 @@ index 187b3b5..e03793e 100644 dev = inode->i_sb->s_dev; ino = inode->i_ino; pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT; -@@ -1505,7 +1508,7 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid) +@@ -1506,7 +1509,7 @@ static int show_numa_map(struct seq_file struct proc_maps_private *proc_priv = &numa_priv->proc_maps; struct vm_area_struct *vma = v; struct numa_maps *md = &numa_priv->md; @@ -33423,11 +33418,10 @@ index 187b3b5..e03793e 100644 struct mm_struct *mm = vma->vm_mm; struct mm_walk walk = { .hugetlb_entry = gather_hugetlb_stats, -diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c -index e0d64c9..7aa92db 100644 ---- a/fs/proc/task_nommu.c -+++ b/fs/proc/task_nommu.c -@@ -160,7 +160,10 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma, +diff -Nurp linux-4.4.3/fs/proc/task_nommu.c linux-4.4.3-aufs/fs/proc/task_nommu.c +--- linux-4.4.3/fs/proc/task_nommu.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/fs/proc/task_nommu.c 2016-03-02 17:59:37.377498803 +0200 +@@ -160,7 +160,10 @@ static int nommu_vma_show(struct seq_fil file = vma->vm_file; if (file) { @@ -33439,11 +33433,10 @@ index e0d64c9..7aa92db 100644 dev = inode->i_sb->s_dev; ino = inode->i_ino; pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT; -diff --git a/fs/read_write.c b/fs/read_write.c -index 819ef3f..fd0414e 100644 ---- a/fs/read_write.c -+++ b/fs/read_write.c -@@ -494,6 +494,28 @@ ssize_t __vfs_write(struct file *file, const char __user *p, size_t count, +diff -Nurp linux-4.4.3/fs/read_write.c linux-4.4.3-aufs/fs/read_write.c +--- linux-4.4.3/fs/read_write.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/fs/read_write.c 2016-03-02 17:59:37.377498803 +0200 +@@ -494,6 +494,28 @@ ssize_t __vfs_write(struct file *file, c } EXPORT_SYMBOL(__vfs_write); @@ -33472,10 +33465,9 @@ index 819ef3f..fd0414e 100644 ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos) { mm_segment_t old_fs; -diff --git a/fs/splice.c b/fs/splice.c -index 4cf700d..30a091d 100644 ---- a/fs/splice.c -+++ b/fs/splice.c +diff -Nurp linux-4.4.3/fs/splice.c linux-4.4.3-aufs/fs/splice.c +--- linux-4.4.3/fs/splice.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/fs/splice.c 2016-03-02 17:59:37.377498803 +0200 @@ -1110,8 +1110,8 @@ EXPORT_SYMBOL(generic_splice_sendpage); /* * Attempt to initiate a splice from pipe to file. @@ -33487,7 +33479,7 @@ index 4cf700d..30a091d 100644 { ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); -@@ -1127,9 +1127,9 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, +@@ -1127,9 +1127,9 @@ static long do_splice_from(struct pipe_i /* * Attempt to initiate a splice from a file to a pipe. */ @@ -33500,10 +33492,9 @@ index 4cf700d..30a091d 100644 { ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); -diff --git a/include/linux/file.h b/include/linux/file.h -index f87d308..9a290b3 100644 ---- a/include/linux/file.h -+++ b/include/linux/file.h +diff -Nurp linux-4.4.3/include/linux/file.h linux-4.4.3-aufs/include/linux/file.h +--- linux-4.4.3/include/linux/file.h 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/include/linux/file.h 2016-03-02 17:59:37.377498803 +0200 @@ -19,6 +19,7 @@ struct dentry; struct path; extern struct file *alloc_file(struct path *, fmode_t mode, @@ -33512,11 +33503,26 @@ index f87d308..9a290b3 100644 static inline void fput_light(struct file *file, int fput_needed) { -diff --git a/include/linux/fs.h b/include/linux/fs.h -index 3aa5142..8d48506 100644 ---- a/include/linux/fs.h -+++ b/include/linux/fs.h -@@ -1672,6 +1672,12 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, +diff -Nurp linux-4.4.3/include/linux/fs.h linux-4.4.3-aufs/include/linux/fs.h +--- linux-4.4.3/include/linux/fs.h 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/include/linux/fs.h 2016-03-02 17:59:37.378498810 +0200 +@@ -1233,6 +1233,7 @@ extern void fasync_free(struct fasync_st + /* 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 void f_setown(struct file *filp, unsigned long arg, int force); + extern void f_delown(struct file *filp); +@@ -1619,6 +1620,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); +@@ -1672,6 +1674,12 @@ ssize_t rw_copy_check_uvector(int type, struct iovec *fast_pointer, struct iovec **ret_pointer); @@ -33529,11 +33535,10 @@ index 3aa5142..8d48506 100644 extern ssize_t __vfs_read(struct file *, char __user *, size_t, loff_t *); extern ssize_t __vfs_write(struct file *, const char __user *, size_t, loff_t *); extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *); -diff --git a/include/linux/mm.h b/include/linux/mm.h -index 00bad77..cc616b0 100644 ---- a/include/linux/mm.h -+++ b/include/linux/mm.h -@@ -1183,6 +1183,28 @@ static inline int fixup_user_fault(struct task_struct *tsk, +diff -Nurp linux-4.4.3/include/linux/mm.h linux-4.4.3-aufs/include/linux/mm.h +--- linux-4.4.3/include/linux/mm.h 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/include/linux/mm.h 2016-03-02 17:59:37.378498810 +0200 +@@ -1183,6 +1183,28 @@ static inline int fixup_user_fault(struc } #endif @@ -33562,10 +33567,9 @@ index 00bad77..cc616b0 100644 extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write); extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, void *buf, int len, int write); -diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h -index f8d1492..c3a3760 100644 ---- a/include/linux/mm_types.h -+++ b/include/linux/mm_types.h +diff -Nurp linux-4.4.3/include/linux/mm_types.h linux-4.4.3-aufs/include/linux/mm_types.h +--- linux-4.4.3/include/linux/mm_types.h 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/include/linux/mm_types.h 2016-03-02 17:59:37.378498810 +0200 @@ -272,6 +272,7 @@ struct vm_region { unsigned long vm_top; /* region allocated to here */ unsigned long vm_pgoff; /* the offset in vm_file corresponding to vm_start */ @@ -33582,11 +33586,10 @@ index f8d1492..c3a3760 100644 void * vm_private_data; /* was vm_pte (shared mem) */ #ifndef CONFIG_MMU -diff --git a/include/linux/splice.h b/include/linux/splice.h -index da2751d..2e0fca6 100644 ---- a/include/linux/splice.h -+++ b/include/linux/splice.h -@@ -83,4 +83,10 @@ extern void splice_shrink_spd(struct splice_pipe_desc *); +diff -Nurp linux-4.4.3/include/linux/splice.h linux-4.4.3-aufs/include/linux/splice.h +--- linux-4.4.3/include/linux/splice.h 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/include/linux/splice.h 2016-03-02 17:59:37.378498810 +0200 +@@ -83,4 +83,10 @@ extern void splice_shrink_spd(struct spl extern void spd_release_page(struct splice_pipe_desc *, unsigned int); extern const struct pipe_buf_operations page_cache_pipe_buf_ops; @@ -33597,26 +33600,12 @@ index da2751d..2e0fca6 100644 + struct pipe_inode_info *pipe, size_t len, + unsigned int flags); #endif -diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild -index 628e6e6..6dd5765 100644 ---- a/include/uapi/linux/Kbuild -+++ b/include/uapi/linux/Kbuild -@@ -59,6 +59,7 @@ header-y += atmsvc.h - header-y += atm_tcp.h - header-y += atm_zatm.h - header-y += audit.h -+header-y += aufs_type.h - header-y += auto_fs4.h - header-y += auto_fs.h - header-y += auxvec.h -diff --git a/include/uapi/linux/aufs_type.h b/include/uapi/linux/aufs_type.h -new file mode 100644 -index 0000000..a06c985 ---- /dev/null -+++ b/include/uapi/linux/aufs_type.h +diff -Nurp linux-4.4.3/include/uapi/linux/aufs_type.h linux-4.4.3-aufs/include/uapi/linux/aufs_type.h +--- linux-4.4.3/include/uapi/linux/aufs_type.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/include/uapi/linux/aufs_type.h 2016-03-02 17:59:37.378498810 +0200 @@ -0,0 +1,406 @@ +/* -+ * Copyright (C) 2005-2015 Junjiro R. Okajima ++ * Copyright (C) 2005-2016 Junjiro R. Okajima + */ + +#ifndef __AUFS_TYPE_H__ @@ -33643,7 +33632,7 @@ index 0000000..a06c985 + +#include + -+#define AUFS_VERSION "4.x-rcN" ++#define AUFS_VERSION "4.4" + +/* todo? move this to linux-2.6.19/include/magic.h */ +#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') @@ -34021,11 +34010,21 @@ index 0000000..a06c985 +#define AUFS_CTL_FHSM_FD _IOW(AuCtlType, AuCtl_FHSM_FD, int) + +#endif /* __AUFS_TYPE_H__ */ -diff --git a/kernel/fork.c b/kernel/fork.c -index fce002e..2230a0f 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -464,7 +464,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) +diff -Nurp linux-4.4.3/include/uapi/linux/Kbuild linux-4.4.3-aufs/include/uapi/linux/Kbuild +--- linux-4.4.3/include/uapi/linux/Kbuild 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/include/uapi/linux/Kbuild 2016-03-02 17:59:37.378498810 +0200 +@@ -59,6 +59,7 @@ header-y += atmsvc.h + header-y += atm_tcp.h + header-y += atm_zatm.h + header-y += audit.h ++header-y += aufs_type.h + header-y += auto_fs4.h + header-y += auto_fs.h + header-y += auxvec.h +diff -Nurp linux-4.4.3/kernel/fork.c linux-4.4.3-aufs/kernel/fork.c +--- linux-4.4.3/kernel/fork.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/kernel/fork.c 2016-03-02 17:59:37.379498817 +0200 +@@ -465,7 +465,7 @@ static int dup_mmap(struct mm_struct *mm struct inode *inode = file_inode(file); struct address_space *mapping = file->f_mapping; @@ -34034,24 +34033,33 @@ index fce002e..2230a0f 100644 if (tmp->vm_flags & VM_DENYWRITE) atomic_dec(&inode->i_writecount); i_mmap_lock_write(mapping); -diff --git a/mm/Makefile b/mm/Makefile -index 2ed4319..e3a53f5 100644 ---- a/mm/Makefile -+++ b/mm/Makefile -@@ -21,7 +21,7 @@ obj-y := filemap.o mempool.o oom_kill.o \ - mm_init.o mmu_context.o percpu.o slab_common.o \ - compaction.o vmacache.o \ - interval_tree.o list_lru.o workingset.o \ -- debug.o $(mmu-y) -+ prfile.o debug.o $(mmu-y) +diff -Nurp linux-4.4.3/MAINTAINERS linux-4.4.3-aufs/MAINTAINERS +--- linux-4.4.3/MAINTAINERS 2016-03-02 17:42:59.404713024 +0200 ++++ linux-4.4.3-aufs/MAINTAINERS 2016-03-02 17:59:37.360498681 +0200 +@@ -2029,6 +2029,19 @@ F: include/linux/audit.h + F: include/uapi/linux/audit.h + F: kernel/audit* - obj-y += init-mm.o - -diff --git a/mm/filemap.c b/mm/filemap.c -index 1bb0076..8eaece8 100644 ---- a/mm/filemap.c -+++ b/mm/filemap.c -@@ -2128,7 +2128,7 @@ int filemap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ++AUFS (advanced multi layered unification filesystem) FILESYSTEM ++M: "J. R. Okajima" ++L: linux-unionfs@vger.kernel.org ++L: aufs-users@lists.sourceforge.net (members only) ++W: http://aufs.sourceforge.net ++T: git://github.com/sfjro/aufs4-linux.git ++S: Supported ++F: Documentation/filesystems/aufs/ ++F: Documentation/ABI/testing/debugfs-aufs ++F: Documentation/ABI/testing/sysfs-aufs ++F: fs/aufs/ ++F: include/uapi/linux/aufs_type.h ++ + AUXILIARY DISPLAY DRIVERS + M: Miguel Ojeda Sandonis + W: http://miguelojeda.es/auxdisplay.htm +diff -Nurp linux-4.4.3/mm/filemap.c linux-4.4.3-aufs/mm/filemap.c +--- linux-4.4.3/mm/filemap.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/mm/filemap.c 2016-03-02 17:59:37.379498817 +0200 +@@ -2128,7 +2128,7 @@ int filemap_page_mkwrite(struct vm_area_ int ret = VM_FAULT_LOCKED; sb_start_pagefault(inode->i_sb); @@ -34060,11 +34068,22 @@ index 1bb0076..8eaece8 100644 lock_page(page); if (page->mapping != inode->i_mapping) { unlock_page(page); -diff --git a/mm/memory.c b/mm/memory.c -index c387430..d434404 100644 ---- a/mm/memory.c -+++ b/mm/memory.c -@@ -2035,7 +2035,7 @@ static inline int wp_page_reuse(struct mm_struct *mm, +diff -Nurp linux-4.4.3/mm/Makefile linux-4.4.3-aufs/mm/Makefile +--- linux-4.4.3/mm/Makefile 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/mm/Makefile 2016-03-02 17:59:37.379498817 +0200 +@@ -21,7 +21,7 @@ obj-y := filemap.o mempool.o oom_kill. + mm_init.o mmu_context.o percpu.o slab_common.o \ + compaction.o vmacache.o \ + interval_tree.o list_lru.o workingset.o \ +- debug.o $(mmu-y) ++ prfile.o debug.o $(mmu-y) + + obj-y += init-mm.o + +diff -Nurp linux-4.4.3/mm/memory.c linux-4.4.3-aufs/mm/memory.c +--- linux-4.4.3/mm/memory.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/mm/memory.c 2016-03-02 17:59:37.379498817 +0200 +@@ -2035,7 +2035,7 @@ static inline int wp_page_reuse(struct m } if (!page_mkwrite) @@ -34073,11 +34092,10 @@ index c387430..d434404 100644 } return VM_FAULT_WRITE; -diff --git a/mm/mmap.c b/mm/mmap.c -index 2ce04a6..f555c0a 100644 ---- a/mm/mmap.c -+++ b/mm/mmap.c -@@ -275,7 +275,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma) +diff -Nurp linux-4.4.3/mm/mmap.c linux-4.4.3-aufs/mm/mmap.c +--- linux-4.4.3/mm/mmap.c 2016-03-02 17:42:59.457713370 +0200 ++++ linux-4.4.3-aufs/mm/mmap.c 2016-03-02 17:59:37.380498824 +0200 +@@ -275,7 +275,7 @@ static struct vm_area_struct *remove_vma if (vma->vm_ops && vma->vm_ops->close) vma->vm_ops->close(vma); if (vma->vm_file) @@ -34086,7 +34104,7 @@ index 2ce04a6..f555c0a 100644 mpol_put(vma_policy(vma)); kmem_cache_free(vm_area_cachep, vma); return next; -@@ -887,7 +887,7 @@ again: remove_next = 1 + (end > next->vm_end); +@@ -891,7 +891,7 @@ again: remove_next = 1 + (end > next-> if (remove_next) { if (file) { uprobe_munmap(next, next->vm_start, next->vm_end); @@ -34095,7 +34113,7 @@ index 2ce04a6..f555c0a 100644 } if (next->anon_vma) anon_vma_merge(vma, next); -@@ -1681,8 +1681,8 @@ out: +@@ -1685,8 +1685,8 @@ out: return addr; unmap_and_free_vma: @@ -34105,7 +34123,7 @@ index 2ce04a6..f555c0a 100644 /* Undo any partial mapping done by a device driver. */ unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end); -@@ -2488,7 +2488,7 @@ static int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, +@@ -2483,7 +2483,7 @@ static int __split_vma(struct mm_struct goto out_free_mpol; if (new->vm_file) @@ -34114,7 +34132,7 @@ index 2ce04a6..f555c0a 100644 if (new->vm_ops && new->vm_ops->open) new->vm_ops->open(new); -@@ -2507,7 +2507,7 @@ static int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, +@@ -2502,7 +2502,7 @@ static int __split_vma(struct mm_struct if (new->vm_ops && new->vm_ops->close) new->vm_ops->close(new); if (new->vm_file) @@ -34123,7 +34141,7 @@ index 2ce04a6..f555c0a 100644 unlink_anon_vmas(new); out_free_mpol: mpol_put(vma_policy(new)); -@@ -2649,7 +2649,6 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, +@@ -2644,7 +2644,6 @@ SYSCALL_DEFINE5(remap_file_pages, unsign struct vm_area_struct *vma; unsigned long populate = 0; unsigned long ret = -EINVAL; @@ -34131,8 +34149,8 @@ index 2ce04a6..f555c0a 100644 pr_warn_once("%s (%d) uses deprecated remap_file_pages() syscall. " "See Documentation/vm/remap_file_pages.txt.\n", -@@ -2693,10 +2692,10 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, - munlock_vma_pages_range(vma, start, start + size); +@@ -2712,10 +2711,10 @@ SYSCALL_DEFINE5(remap_file_pages, unsign + } } - file = get_file(vma->vm_file); @@ -34144,7 +34162,7 @@ index 2ce04a6..f555c0a 100644 out: up_write(&mm->mmap_sem); if (populate) -@@ -2966,7 +2965,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, +@@ -2985,7 +2984,7 @@ struct vm_area_struct *copy_vma(struct v if (anon_vma_clone(new_vma, vma)) goto out_free_mempol; if (new_vma->vm_file) @@ -34153,11 +34171,10 @@ index 2ce04a6..f555c0a 100644 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 92be862..29179f7 100644 ---- a/mm/nommu.c -+++ b/mm/nommu.c -@@ -671,7 +671,7 @@ static void __put_nommu_region(struct vm_region *region) +diff -Nurp linux-4.4.3/mm/nommu.c linux-4.4.3-aufs/mm/nommu.c +--- linux-4.4.3/mm/nommu.c 2016-01-11 01:01:32.000000000 +0200 ++++ linux-4.4.3-aufs/mm/nommu.c 2016-03-02 17:59:37.380498824 +0200 +@@ -671,7 +671,7 @@ static void __put_nommu_region(struct vm up_write(&nommu_region_sem); if (region->vm_file) @@ -34166,7 +34183,7 @@ index 92be862..29179f7 100644 /* IO memory and memory shared directly out of the pagecache * from ramfs/tmpfs mustn't be released here */ -@@ -829,7 +829,7 @@ static void delete_vma(struct mm_struct *mm, struct vm_area_struct *vma) +@@ -829,7 +829,7 @@ static void delete_vma(struct mm_struct if (vma->vm_ops && vma->vm_ops->close) vma->vm_ops->close(vma); if (vma->vm_file) @@ -34197,11 +34214,9 @@ index 92be862..29179f7 100644 kmem_cache_free(vm_area_cachep, vma); return ret; -diff --git a/mm/prfile.c b/mm/prfile.c -new file mode 100644 -index 0000000..b323b8a ---- /dev/null -+++ b/mm/prfile.c +diff -Nurp linux-4.4.3/mm/prfile.c linux-4.4.3-aufs/mm/prfile.c +--- linux-4.4.3/mm/prfile.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.4.3-aufs/mm/prfile.c 2016-03-02 17:59:37.380498824 +0200 @@ -0,0 +1,86 @@ +/* + * Mainly for aufs which mmap(2) diffrent file and wants to print different path diff --git a/kernel/kernel/files/patches/mageia/fs-ovl-allow-zero-size-xattr.patch b/kernel/kernel/files/patches/mageia/fs-ovl-allow-zero-size-xattr.patch deleted file mode 100644 index e506728f..00000000 --- a/kernel/kernel/files/patches/mageia/fs-ovl-allow-zero-size-xattr.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 97daf8b97ad6f913a34c82515be64dc9ac08d63e Mon Sep 17 00:00:00 2001 -From: Miklos Szeredi -Date: Tue, 10 Nov 2015 17:08:41 +0100 -Subject: [PATCH 1/6] ovl: allow zero size xattr - -When ovl_copy_xattr() encountered a zero size xattr no more xattrs were -copied and the function returned success. This is clearly not the desired -behavior. - -Signed-off-by: Miklos Szeredi -Cc: ---- - fs/overlayfs/copy_up.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c -index 871fcb6..394e87f 100644 ---- a/fs/overlayfs/copy_up.c -+++ b/fs/overlayfs/copy_up.c -@@ -54,7 +54,7 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new) - - for (name = buf; name < (buf + list_size); name += strlen(name) + 1) { - size = vfs_getxattr(old, name, value, XATTR_SIZE_MAX); -- if (size <= 0) { -+ if (size < 0) { - error = size; - goto out_free_value; - } --- -2.7.0 - diff --git a/kernel/kernel/files/patches/mageia/fs-ovl-check-dentry-positiveness-in-ovl_cleanup_whiteou.patch b/kernel/kernel/files/patches/mageia/fs-ovl-check-dentry-positiveness-in-ovl_cleanup_whiteou.patch deleted file mode 100644 index d2c30236..00000000 --- a/kernel/kernel/files/patches/mageia/fs-ovl-check-dentry-positiveness-in-ovl_cleanup_whiteou.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 84889d49335627bc770b32787c1ef9ebad1da232 Mon Sep 17 00:00:00 2001 -From: Konstantin Khlebnikov -Date: Mon, 16 Nov 2015 18:44:11 +0300 -Subject: [PATCH 6/6] ovl: check dentry positiveness in ovl_cleanup_whiteouts() - -This patch fixes kernel crash at removing directory which contains -whiteouts from lower layers. - -Cache of directory content passed as "list" contains entries from all -layers, including whiteouts from lower layers. So, lookup in upper dir -(moved into work at this stage) will return negative entry. Plus this -cache is filled long before and we can race with external removal. - -Example: - mkdir -p lower0/dir lower1/dir upper work overlay - touch lower0/dir/a lower0/dir/b - mknod lower1/dir/a c 0 0 - mount -t overlay none overlay -o lowerdir=lower1:lower0,upperdir=upper,workdir=work - rm -fr overlay/dir - -Signed-off-by: Konstantin Khlebnikov -Signed-off-by: Miklos Szeredi -Cc: # 3.18+ ---- - fs/overlayfs/readdir.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c -index 70e9af5..adcb139 100644 ---- a/fs/overlayfs/readdir.c -+++ b/fs/overlayfs/readdir.c -@@ -571,7 +571,8 @@ void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list) - (int) PTR_ERR(dentry)); - continue; - } -- ovl_cleanup(upper->d_inode, dentry); -+ if (dentry->d_inode) -+ ovl_cleanup(upper->d_inode, dentry); - dput(dentry); - } - mutex_unlock(&upper->d_inode->i_mutex); --- -2.7.0 - diff --git a/kernel/kernel/files/patches/mageia/fs-ovl-root-copy-attr.patch b/kernel/kernel/files/patches/mageia/fs-ovl-root-copy-attr.patch deleted file mode 100644 index 73613b7e..00000000 --- a/kernel/kernel/files/patches/mageia/fs-ovl-root-copy-attr.patch +++ /dev/null @@ -1,33 +0,0 @@ -From ed06e069775ad9236087594a1c1667367e983fb5 Mon Sep 17 00:00:00 2001 -From: Miklos Szeredi -Date: Wed, 9 Dec 2015 16:11:59 +0100 -Subject: [PATCH 4/6] ovl: root: copy attr - -We copy i_uid and i_gid of underlying inode into overlayfs inode. Except -for the root inode. - -Fix this omission. - -Signed-off-by: Miklos Szeredi -Cc: ---- - fs/overlayfs/super.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c -index 32f3124..ec31711 100644 ---- a/fs/overlayfs/super.c -+++ b/fs/overlayfs/super.c -@@ -1079,6 +1079,9 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) - - root_dentry->d_fsdata = oe; - -+ ovl_copyattr(ovl_dentry_real(root_dentry)->d_inode, -+ root_dentry->d_inode); -+ - sb->s_magic = OVERLAYFS_SUPER_MAGIC; - sb->s_op = &ovl_super_operations; - sb->s_root = root_dentry; --- -2.7.0 - diff --git a/kernel/kernel/files/patches/mageia/fs-ovl-setattr-check-permissions-before-copy-up.patch b/kernel/kernel/files/patches/mageia/fs-ovl-setattr-check-permissions-before-copy-up.patch deleted file mode 100644 index 91014154..00000000 --- a/kernel/kernel/files/patches/mageia/fs-ovl-setattr-check-permissions-before-copy-up.patch +++ /dev/null @@ -1,65 +0,0 @@ -From cf9a6784f7c1b5ee2b9159a1246e327c331c5697 Mon Sep 17 00:00:00 2001 -From: Miklos Szeredi -Date: Fri, 11 Dec 2015 16:30:49 +0100 -Subject: [PATCH 5/6] ovl: setattr: check permissions before copy-up - -Without this copy-up of a file can be forced, even without actually being -allowed to do anything on the file. - -[Arnd Bergmann] include for PAGE_CACHE_SIZE (used by -MAX_LFS_FILESIZE definition). - -Signed-off-by: Miklos Szeredi -Cc: ---- - fs/overlayfs/inode.c | 13 +++++++++++++ - fs/overlayfs/super.c | 2 ++ - 2 files changed, 15 insertions(+) - -diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c -index 7654631..213a726 100644 ---- a/fs/overlayfs/inode.c -+++ b/fs/overlayfs/inode.c -@@ -45,6 +45,19 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr) - int err; - struct dentry *upperdentry; - -+ /* -+ * Check for permissions before trying to copy-up. This is redundant -+ * since it will be rechecked later by ->setattr() on upper dentry. But -+ * without this, copy-up can be triggered by just about anybody. -+ * -+ * We don't initialize inode->size, which just means that -+ * inode_newsize_ok() will always check against MAX_LFS_FILESIZE and not -+ * check for a swapfile (which this won't be anyway). -+ */ -+ err = inode_change_ok(dentry->d_inode, attr); -+ if (err) -+ return err; -+ - err = ovl_want_write(dentry); - if (err) - goto out; -diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c -index ec31711..b08bf4d 100644 ---- a/fs/overlayfs/super.c -+++ b/fs/overlayfs/super.c -@@ -9,6 +9,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -936,6 +937,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) - } - - sb->s_stack_depth = 0; -+ sb->s_maxbytes = MAX_LFS_FILESIZE; - if (ufs->config.upperdir) { - if (!ufs->config.workdir) { - pr_err("overlayfs: missing 'workdir'\n"); --- -2.7.0 - diff --git a/kernel/kernel/files/patches/mageia/fs-ovl-use-a-minimal-buffer-in-ovl_copy_xattr.patch b/kernel/kernel/files/patches/mageia/fs-ovl-use-a-minimal-buffer-in-ovl_copy_xattr.patch deleted file mode 100644 index 59eb828b..00000000 --- a/kernel/kernel/files/patches/mageia/fs-ovl-use-a-minimal-buffer-in-ovl_copy_xattr.patch +++ /dev/null @@ -1,89 +0,0 @@ -From e4ad29fa0d224d05e08b2858e65f112fd8edd4fe Mon Sep 17 00:00:00 2001 -From: Vito Caputo -Date: Sat, 24 Oct 2015 07:19:46 -0500 -Subject: [PATCH 2/6] ovl: use a minimal buffer in ovl_copy_xattr - -Rather than always allocating the high-order XATTR_SIZE_MAX buffer -which is costly and prone to failure, only allocate what is needed and -realloc if necessary. - -Fixes https://github.com/coreos/bugs/issues/489 - -Signed-off-by: Miklos Szeredi -Cc: ---- - fs/overlayfs/copy_up.c | 39 +++++++++++++++++++++++++-------------- - 1 file changed, 25 insertions(+), 14 deletions(-) - -diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c -index 394e87f..758012b 100644 ---- a/fs/overlayfs/copy_up.c -+++ b/fs/overlayfs/copy_up.c -@@ -22,9 +22,9 @@ - - int ovl_copy_xattr(struct dentry *old, struct dentry *new) - { -- ssize_t list_size, size; -- char *buf, *name, *value; -- int error; -+ ssize_t list_size, size, value_size = 0; -+ char *buf, *name, *value = NULL; -+ int uninitialized_var(error); - - if (!old->d_inode->i_op->getxattr || - !new->d_inode->i_op->getxattr) -@@ -41,29 +41,40 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new) - if (!buf) - return -ENOMEM; - -- error = -ENOMEM; -- value = kmalloc(XATTR_SIZE_MAX, GFP_KERNEL); -- if (!value) -- goto out; -- - list_size = vfs_listxattr(old, buf, list_size); - if (list_size <= 0) { - error = list_size; -- goto out_free_value; -+ goto out; - } - - for (name = buf; name < (buf + list_size); name += strlen(name) + 1) { -- size = vfs_getxattr(old, name, value, XATTR_SIZE_MAX); -+retry: -+ size = vfs_getxattr(old, name, value, value_size); -+ if (size == -ERANGE) -+ size = vfs_getxattr(old, name, NULL, 0); -+ - if (size < 0) { - error = size; -- goto out_free_value; -+ break; -+ } -+ -+ if (size > value_size) { -+ void *new; -+ -+ new = krealloc(value, size, GFP_KERNEL); -+ if (!new) { -+ error = -ENOMEM; -+ break; -+ } -+ value = new; -+ value_size = size; -+ goto retry; - } -+ - error = vfs_setxattr(new, name, value, size, 0); - if (error) -- goto out_free_value; -+ break; - } -- --out_free_value: - kfree(value); - out: - kfree(buf); --- -2.7.0 - diff --git a/kernel/kernel/files/patches/mageia/fs-xfs-Revert-xfs-clear-PF_NOFREEZE-for-xfsaild-kthread.patch b/kernel/kernel/files/patches/mageia/fs-xfs-Revert-xfs-clear-PF_NOFREEZE-for-xfsaild-kthread.patch deleted file mode 100644 index 5c483f7f..00000000 --- a/kernel/kernel/files/patches/mageia/fs-xfs-Revert-xfs-clear-PF_NOFREEZE-for-xfsaild-kthread.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 3e85286e75224fa3f08bdad20e78c8327742634e Mon Sep 17 00:00:00 2001 -From: Dave Chinner -Date: Tue, 19 Jan 2016 08:21:46 +1100 -Subject: [PATCH] Revert "xfs: clear PF_NOFREEZE for xfsaild kthread" - -This reverts commit 24ba16bb3d499c49974669cd8429c3e4138ab102 as it -prevents machines from suspending. This regression occurs when the -xfsaild is idle on entry to suspend, and so there s no activity to -wake it from it's idle sleep and hence see that it is supposed to -freeze. Hence the freezer times out waiting for it and suspend is -cancelled. - -There is no obvious fix for this short of freezing the filesystem -properly, so revert this change for now. - -cc: # 4.4 -Signed-off-by: Dave Chinner -Acked-by: Jiri Kosina -Reviewed-by: Brian Foster -Signed-off-by: Dave Chinner ---- - fs/xfs/xfs_trans_ail.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c -index aa67339..4f18fd9 100644 ---- a/fs/xfs/xfs_trans_ail.c -+++ b/fs/xfs/xfs_trans_ail.c -@@ -497,7 +497,6 @@ xfsaild( - long tout = 0; /* milliseconds */ - - current->flags |= PF_MEMALLOC; -- set_freezable(); - - while (!kthread_should_stop()) { - if (tout && tout <= 20) --- -2.7.1 - diff --git a/kernel/kernel/files/patches/mageia/gpu-drm-Fix-drm_vblank_pre_post_modeset-regression-from-Linux-4.4.patch b/kernel/kernel/files/patches/mageia/gpu-drm-Fix-drm_vblank_pre_post_modeset-regression-from-Linux-4.4.patch deleted file mode 100644 index df761c07..00000000 --- a/kernel/kernel/files/patches/mageia/gpu-drm-Fix-drm_vblank_pre_post_modeset-regression-from-Linux-4.4.patch +++ /dev/null @@ -1,82 +0,0 @@ -From: Mario Kleiner -Subject: [PATCH 3/6] drm: Fix drm_vblank_pre/post_modeset regression from Linux 4.4 -Date: Fri, 12 Feb 2016 20:30:29 +0100 - -Changes to drm_update_vblank_count() in Linux 4.4 broke the -behaviour of the pre/post modeset functions as the new update -code doesn't deal with hw vblank counter resets inbetween calls -to drm_vblank_pre_modeset an drm_vblank_post_modeset, as it -should. - -This causes mistreatment of such hw counter resets as counter -wraparound, and thereby large forward jumps of the software -vblank counter which in turn cause vblank event dispatching -and vblank waits to fail/hang --> userspace clients hang. - -This symptom was reported on radeon-kms to cause a infinite -hang of KDE Plasma 5 shell's login procedure, preventing users -from logging in. - -Fix this by detecting when drm_update_vblank_count() is called -inside a pre->post modeset interval. If so, clamp valid vblank -increments to the safe values 0 and 1, pretty much restoring -the update behavior of the old update code of Linux 4.3 and -earlier. Also reset the last recorded hw vblank count at call -to drm_vblank_post_modeset() to be safe against hw that after -modesetting, dpms on etc. only fires its first vblank irq after -drm_vblank_post_modeset() was already called. - -Reported-by: Vlastimil Babka -Signed-off-by: Mario Kleiner -Reviewed-by: Daniel Vetter -Tested-by: Vlastimil Babka - -Cc: # 4.4+ -Cc: michel@daenzer.net -Cc: vbabka@suse.cz -Cc: ville.syrjala@linux.intel.com -Cc: daniel.vetter@ffwll.ch -Cc: dri-devel@lists.freedesktop.org -Cc: alexander.deucher@amd.com -Cc: christian.koenig@amd.com ---- - drivers/gpu/drm/drm_irq.c | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c -index 92ad62f..055b0fa 100644 ---- a/drivers/gpu/drm/drm_irq.c -+++ b/drivers/gpu/drm/drm_irq.c -@@ -222,6 +222,21 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, - } - - /* -+ * Within a drm_vblank_pre_modeset - drm_vblank_post_modeset -+ * interval? If so then vblank irqs keep running and it will likely -+ * happen that the hardware vblank counter is not trustworthy as it -+ * might reset at some point in that interval and vblank timestamps -+ * are not trustworthy either in that interval. Iow. this can result -+ * in a bogus diff >> 1 which must be avoided as it would cause -+ * random large forward jumps of the software vblank counter. -+ */ -+ if (diff > 1 && (vblank->inmodeset & 0x2)) { -+ DRM_DEBUG_VBL("clamping vblank bump to 1 on crtc %u: diffr=%u" -+ " due to pre-modeset.\n", pipe, diff); -+ diff = 1; -+ } -+ -+ /* - * FIMXE: Need to replace this hack with proper seqlocks. - * - * Restrict the bump of the software vblank counter to a safe maximum -@@ -1575,6 +1590,7 @@ void drm_vblank_post_modeset(struct drm_device *dev, unsigned int pipe) - if (vblank->inmodeset) { - spin_lock_irqsave(&dev->vbl_lock, irqflags); - dev->vblank_disable_allowed = true; -+ drm_reset_vblank_timestamp(dev, pipe); - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - - if (vblank->inmodeset & 0x2) --- -1.9.1 - diff --git a/kernel/kernel/files/patches/mageia/gpu-drm-Fix-treatment-of-drm_vblank_offdelay-in-drm_vblank_on-v2.patch b/kernel/kernel/files/patches/mageia/gpu-drm-Fix-treatment-of-drm_vblank_offdelay-in-drm_vblank_on-v2.patch deleted file mode 100644 index 246229bd..00000000 --- a/kernel/kernel/files/patches/mageia/gpu-drm-Fix-treatment-of-drm_vblank_offdelay-in-drm_vblank_on-v2.patch +++ /dev/null @@ -1,64 +0,0 @@ -From: Mario Kleiner -Subject: [PATCH 4/6] drm: Fix treatment of drm_vblank_offdelay in drm_vblank_on() (v2) -Date: Fri, 12 Feb 2016 20:30:30 +0100 - -drm_vblank_offdelay can have three different types of values: - -< 0 is to be always treated the same as dev->vblank_disable_immediate -= 0 is to be treated as "never disable vblanks" -> 0 is to be treated as disable immediate if kms driver wants it - that way via dev->vblank_disable_immediate. Otherwise it is - a disable timeout in msecs. - -This got broken in Linux 3.18+ for the implementation of -drm_vblank_on. If the user specified a value of zero which should -always reenable vblank irqs in this function, a kms driver could -override the users choice by setting vblank_disable_immediate -to true. This patch fixes the regression and keeps the user in -control. - -v2: Only reenable vblank if there are clients left or the user - requested to "never disable vblanks" via offdelay 0. Enabling - vblanks even in the "delayed disable" case (offdelay > 0) was - specifically added by Ville in commit cd19e52aee922 - ("drm: Kick start vblank interrupts at drm_vblank_on()"), - but after discussion it turns out that this was done by accident. - - Citing Ville: "I think it just ended up as a mess due to changing - some of the semantics of offdelay<0 vs. offdelay==0 vs. - disable_immediate during the review of the series. So yeah, given - how drm_vblank_put() works now, I'd just make this check for - offdelay==0." - -Signed-off-by: Mario Kleiner -Reviewed-by: Daniel Vetter - -Cc: # 3.18+ -Cc: michel@daenzer.net -Cc: vbabka@suse.cz -Cc: ville.syrjala@linux.intel.com -Cc: daniel.vetter@ffwll.ch -Cc: dri-devel@lists.freedesktop.org -Cc: alexander.deucher@amd.com -Cc: christian.koenig@amd.com ---- - drivers/gpu/drm/drm_irq.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c -index 055b0fa..8090989 100644 ---- a/drivers/gpu/drm/drm_irq.c -+++ b/drivers/gpu/drm/drm_irq.c -@@ -1494,8 +1494,7 @@ void drm_vblank_on(struct drm_device *dev, unsigned int pipe) - * re-enable interrupts if there are users left, or the - * user wishes vblank interrupts to be enabled all the time. - */ -- if (atomic_read(&vblank->refcount) != 0 || -- (!dev->vblank_disable_immediate && drm_vblank_offdelay == 0)) -+ if (atomic_read(&vblank->refcount) != 0 || drm_vblank_offdelay == 0) - WARN_ON(drm_vblank_enable(dev, pipe)); - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - } --- -1.9.1 - diff --git a/kernel/kernel/files/patches/mageia/gpu-drm-No-Op-redundant-calls-to-drm_vblank_off-v2.patch b/kernel/kernel/files/patches/mageia/gpu-drm-No-Op-redundant-calls-to-drm_vblank_off-v2.patch deleted file mode 100644 index 480c88ba..00000000 --- a/kernel/kernel/files/patches/mageia/gpu-drm-No-Op-redundant-calls-to-drm_vblank_off-v2.patch +++ /dev/null @@ -1,76 +0,0 @@ -From: Mario Kleiner -Subject: [PATCH 1/6] drm: No-Op redundant calls to drm_vblank_off() (v2) -Date: Fri, 12 Feb 2016 20:30:27 +0100 - -Otherwise if a kms driver calls into drm_vblank_off() more than once -before calling drm_vblank_on() again, the redundant calls to -vblank_disable_and_save() will call drm_update_vblank_count() -while hw vblank counters and vblank timestamping are in a undefined -state during modesets, dpms off etc. - -At least with the legacy drm helpers it is not unusual to -get multiple calls to drm_vblank_off and drm_vblank_on, e.g., -half a dozen calls to drm_vblank_off and two calls to drm_vblank_on -were observed on radeon-kms during dpms-off -> dpms-on transition. - -We don't no-op calls from atomic modesetting drivers, as they -should do a proper job of tracking hw state. - -Fixes large jumps of the software maintained vblank counter due to -the hardware vblank counter resetting to zero during dpms off or -modeset, e.g., if radeon-kms is modified to use drm_vblank_off/on -instead of drm_vblank_pre/post_modeset(). - -This fixes a regression caused by the changes made to -drm_update_vblank_count() in Linux 4.4. - -v2: Don't no-op on atomic modesetting drivers, per suggestion - of Daniel Vetter. - -Signed-off-by: Mario Kleiner -Reviewed-by: Daniel Vetter - -Cc: # 4.4+ -Cc: michel@daenzer.net -Cc: vbabka@suse.cz -Cc: ville.syrjala@linux.intel.com -Cc: daniel.vetter@ffwll.ch -Cc: dri-devel@lists.freedesktop.org -Cc: alexander.deucher@amd.com -Cc: christian.koenig@amd.com ---- - drivers/gpu/drm/drm_irq.c | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c -index 607f493..1a18033 100644 ---- a/drivers/gpu/drm/drm_irq.c -+++ b/drivers/gpu/drm/drm_irq.c -@@ -1313,7 +1313,13 @@ void drm_vblank_off(struct drm_device *dev, unsigned int pipe) - spin_lock_irqsave(&dev->event_lock, irqflags); - - spin_lock(&dev->vbl_lock); -- vblank_disable_and_save(dev, pipe); -+ DRM_DEBUG_VBL("crtc %d, vblank enabled %d, inmodeset %d\n", -+ pipe, vblank->enabled, vblank->inmodeset); -+ -+ /* Avoid redundant vblank disables without previous drm_vblank_on(). */ -+ if (drm_core_check_feature(dev, DRIVER_ATOMIC) || !vblank->inmodeset) -+ vblank_disable_and_save(dev, pipe); -+ - wake_up(&vblank->queue); - - /* -@@ -1415,6 +1421,9 @@ void drm_vblank_on(struct drm_device *dev, unsigned int pipe) - return; - - spin_lock_irqsave(&dev->vbl_lock, irqflags); -+ DRM_DEBUG_VBL("crtc %d, vblank enabled %d, inmodeset %d\n", -+ pipe, vblank->enabled, vblank->inmodeset); -+ - /* Drop our private "prevent drm_vblank_get" refcount */ - if (vblank->inmodeset) { - atomic_dec(&vblank->refcount); --- -1.9.1 - diff --git a/kernel/kernel/files/patches/mageia/gpu-drm-Prevent-vblank-counter-bumps-1-with-active-vblank-clients-v2.patch b/kernel/kernel/files/patches/mageia/gpu-drm-Prevent-vblank-counter-bumps-1-with-active-vblank-clients-v2.patch deleted file mode 100644 index c65efe96..00000000 --- a/kernel/kernel/files/patches/mageia/gpu-drm-Prevent-vblank-counter-bumps-1-with-active-vblank-clients-v2.patch +++ /dev/null @@ -1,120 +0,0 @@ -From: Mario Kleiner -Subject: [PATCH 2/6] drm: Prevent vblank counter bumps > 1 with active vblank clients. (v2) -Date: Fri, 12 Feb 2016 20:30:28 +0100 - -This fixes a regression introduced by the new drm_update_vblank_count() -implementation in Linux 4.4: - -Restrict the bump of the software vblank counter in drm_update_vblank_count() -to a safe maximum value of +1 whenever there is the possibility that -concurrent readers of vblank timestamps could be active at the moment, -as the current implementation of the timestamp caching and updating is -not safe against concurrent readers for calls to store_vblank() with a -bump of anything but +1. A bump != 1 would very likely return corrupted -timestamps to userspace, because the same slot in the cache could -be concurrently written by store_vblank() and read by one of those -readers in a non-atomic fashion and without the read-retry logic -detecting this collision. - -Concurrent readers can exist while drm_update_vblank_count() is called -from the drm_vblank_off() or drm_vblank_on() functions or other non-vblank- -irq callers. However, all those calls are happening with the vbl_lock -locked thereby preventing a drm_vblank_get(), so the vblank refcount -can't increase while drm_update_vblank_count() is executing. Therefore -a zero vblank refcount during execution of that function signals that -is safe for arbitrary counter bumps if called from outside vblank irq, -whereas a non-zero count is not safe. - -Whenever the function is called from vblank irq, we have to assume concurrent -readers could show up any time during its execution, even if the refcount -is currently zero, as vblank irqs are usually only enabled due to the -presence of readers, and because when it is called from vblank irq it -can't hold the vbl_lock to protect it from sudden bumps in vblank refcount. -Therefore also restrict bumps to +1 when the function is called from vblank -irq. - -Such bumps of more than +1 can happen at other times than reenabling -vblank irqs, e.g., when regular vblank interrupts get delayed by more -than 1 frame due to long held locks, long irq off periods, realtime -preemption on RT kernels, or system management interrupts. - -A better solution would be to rewrite the timestamp caching to use -full seqlocks to allow concurrent writes and reads for arbitrary -vblank counter increments. - -v2: Add code comment that this is essentially a hack and should - be replaced by a full seqlock implementation for caching of - timestamps. - -Signed-off-by: Mario Kleiner -Reviewed-by: Daniel Vetter - -Cc: # 4.4+ -Cc: michel@daenzer.net -Cc: vbabka@suse.cz -Cc: ville.syrjala@linux.intel.com -Cc: daniel.vetter@ffwll.ch -Cc: dri-devel@lists.freedesktop.org -Cc: alexander.deucher@amd.com -Cc: christian.koenig@amd.com ---- - drivers/gpu/drm/drm_irq.c | 43 +++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 43 insertions(+) - -diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c -index 1a18033..92ad62f 100644 ---- a/drivers/gpu/drm/drm_irq.c -+++ b/drivers/gpu/drm/drm_irq.c -@@ -221,6 +221,49 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, - diff = (flags & DRM_CALLED_FROM_VBLIRQ) != 0; - } - -+ /* -+ * FIMXE: Need to replace this hack with proper seqlocks. -+ * -+ * Restrict the bump of the software vblank counter to a safe maximum -+ * value of +1 whenever there is the possibility that concurrent readers -+ * of vblank timestamps could be active at the moment, as the current -+ * implementation of the timestamp caching and updating is not safe -+ * against concurrent readers for calls to store_vblank() with a bump -+ * of anything but +1. A bump != 1 would very likely return corrupted -+ * timestamps to userspace, because the same slot in the cache could -+ * be concurrently written by store_vblank() and read by one of those -+ * readers without the read-retry logic detecting the collision. -+ * -+ * Concurrent readers can exist when we are called from the -+ * drm_vblank_off() or drm_vblank_on() functions and other non-vblank- -+ * irq callers. However, all those calls to us are happening with the -+ * vbl_lock locked to prevent drm_vblank_get(), so the vblank refcount -+ * can't increase while we are executing. Therefore a zero refcount at -+ * this point is safe for arbitrary counter bumps if we are called -+ * outside vblank irq, a non-zero count is not 100% safe. Unfortunately -+ * we must also accept a refcount of 1, as whenever we are called from -+ * drm_vblank_get() -> drm_vblank_enable() the refcount will be 1 and -+ * we must let that one pass through in order to not lose vblank counts -+ * during vblank irq off - which would completely defeat the whole -+ * point of this routine. -+ * -+ * Whenever we are called from vblank irq, we have to assume concurrent -+ * readers exist or can show up any time during our execution, even if -+ * the refcount is currently zero, as vblank irqs are usually only -+ * enabled due to the presence of readers, and because when we are called -+ * from vblank irq we can't hold the vbl_lock to protect us from sudden -+ * bumps in vblank refcount. Therefore also restrict bumps to +1 when -+ * called from vblank irq. -+ */ -+ if ((diff > 1) && (atomic_read(&vblank->refcount) > 1 || -+ (flags & DRM_CALLED_FROM_VBLIRQ))) { -+ DRM_DEBUG_VBL("clamping vblank bump to 1 on crtc %u: diffr=%u " -+ "refcount %u, vblirq %u\n", pipe, diff, -+ atomic_read(&vblank->refcount), -+ (flags & DRM_CALLED_FROM_VBLIRQ) != 0); -+ diff = 1; -+ } -+ - DRM_DEBUG_VBL("updating vblank count on crtc %u:" - " current=%u, diff=%u, hw=%u hw_last=%u\n", - pipe, vblank->count, diff, cur_vblank, vblank->last); --- -1.9.1 - diff --git a/kernel/kernel/files/patches/mageia/gpu-drm_nouveau_display-Enable-vblank-irqs-after-display-engine-is-on-again.patch b/kernel/kernel/files/patches/mageia/gpu-drm_nouveau_display-Enable-vblank-irqs-after-display-engine-is-on-again.patch deleted file mode 100644 index 1db4ce1c..00000000 --- a/kernel/kernel/files/patches/mageia/gpu-drm_nouveau_display-Enable-vblank-irqs-after-display-engine-is-on-again.patch +++ /dev/null @@ -1,57 +0,0 @@ -From: Mario Kleiner -Subject: [PATCH 6/6] drm/nouveau/display: Enable vblank irqs after display engine is on again. -Date: Fri, 12 Feb 2016 20:30:32 +0100 - -In the display resume path, move the calls to drm_vblank_on() -after the point when the display engine is running again. - -Since changes were made to drm_update_vblank_count() in Linux 4.4+ -to emulate hw vblank counters via vblank timestamping, the function -drm_vblank_on() now needs working high precision vblank timestamping -and therefore working scanout position queries at time of call. -These don't work before the display engine gets restarted, causing -miscalculation of vblank counter increments and thereby large forward -jumps in vblank count at display resume. These jumps can cause client -hangs on resume, or desktop hangs in the case of composited desktops. - -Fix this Linux 4.4 regression by reordering calls accordingly. - -Signed-off-by: Mario Kleiner -Cc: # 4.4+ -Cc: Ben Skeggs -Cc: ville.syrjala@linux.intel.com -Cc: daniel.vetter@ffwll.ch -Cc: dri-devel@lists.freedesktop.org ---- - drivers/gpu/drm/nouveau/nouveau_display.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c -index 18676b8..1f8e51b 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_display.c -+++ b/drivers/gpu/drm/nouveau/nouveau_display.c -@@ -634,10 +634,6 @@ nouveau_display_resume(struct drm_device *dev, bool runtime) - nv_crtc->lut.depth = 0; - } - -- /* Make sure that drm and hw vblank irqs get resumed if needed. */ -- for (head = 0; head < dev->mode_config.num_crtc; head++) -- drm_vblank_on(dev, head); -- - /* This should ensure we don't hit a locking problem when someone - * wakes us up via a connector. We should never go into suspend - * while the display is on anyways. -@@ -647,6 +643,10 @@ nouveau_display_resume(struct drm_device *dev, bool runtime) - - drm_helper_resume_force_mode(dev); - -+ /* Make sure that drm and hw vblank irqs get resumed if needed. */ -+ for (head = 0; head < dev->mode_config.num_crtc; head++) -+ drm_vblank_on(dev, head); -+ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - --- -1.9.1 - diff --git a/kernel/kernel/files/patches/mageia/libata-Align-ata_device-s-id-on-a-cacheline.patch b/kernel/kernel/files/patches/mageia/libata-Align-ata_device-s-id-on-a-cacheline.patch new file mode 100644 index 00000000..2892b5f1 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/libata-Align-ata_device-s-id-on-a-cacheline.patch @@ -0,0 +1,39 @@ +From 4ee34ea3a12396f35b26d90a094c75db95080baa Mon Sep 17 00:00:00 2001 +From: Harvey Hunt +Date: Wed, 24 Feb 2016 15:16:43 +0000 +Subject: [PATCH] libata: Align ata_device's id on a cacheline + +The id buffer in ata_device is a DMA target, but it isn't explicitly +cacheline aligned. Due to this, adjacent fields can be overwritten with +stale data from memory on non coherent architectures. As a result, the +kernel is sometimes unable to communicate with an ATA device. + +Fix this by ensuring that the id buffer is cacheline aligned. + +This issue is similar to that fixed by Commit 84bda12af31f +("libata: align ap->sector_buf"). + +Signed-off-by: Harvey Hunt +Cc: linux-kernel@vger.kernel.org +Cc: # 2.6.18 +Signed-off-by: Tejun Heo +--- + include/linux/libata.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/libata.h b/include/linux/libata.h +index bec2abb..2c4ebef 100644 +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -720,7 +720,7 @@ struct ata_device { + union { + u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ + u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */ +- }; ++ } ____cacheline_aligned; + + /* DEVSLP Timing Variables from Identify Device Data Log */ + u8 devslp_timing[ATA_LOG_DEVSLP_SIZE]; +-- +2.7.2 + diff --git a/kernel/kernel/files/patches/mageia/libata-fix-HDIO_GET_32BIT-ioctl.patch b/kernel/kernel/files/patches/mageia/libata-fix-HDIO_GET_32BIT-ioctl.patch new file mode 100644 index 00000000..b6a453cf --- /dev/null +++ b/kernel/kernel/files/patches/mageia/libata-fix-HDIO_GET_32BIT-ioctl.patch @@ -0,0 +1,98 @@ +From 287e6611ab1eac76c2c5ebf6e345e04c80ca9c61 Mon Sep 17 00:00:00 2001 +From: Arnd Bergmann +Date: Thu, 11 Feb 2016 14:16:27 +0100 +Subject: [PATCH] libata: fix HDIO_GET_32BIT ioctl + +As reported by Soohoon Lee, the HDIO_GET_32BIT ioctl does not +work correctly in compat mode with libata. + +I have investigated the issue further and found multiple problems +that all appeared with the same commit that originally introduced +HDIO_GET_32BIT handling in libata back in linux-2.6.8 and presumably +also linux-2.4, as the code uses "copy_to_user(arg, &val, 1)" to copy +a 'long' variable containing either 0 or 1 to user space. + +The problems with this are: + +* On big-endian machines, this will always write a zero because it + stores the wrong byte into user space. + +* In compat mode, the upper three bytes of the variable are updated + by the compat_hdio_ioctl() function, but they now contain + uninitialized stack data. + +* The hdparm tool calling this ioctl uses a 'static long' variable + to store the result. This means at least the upper bytes are + initialized to zero, but calling another ioctl like HDIO_GET_MULTCOUNT + would fill them with data that remains stale when the low byte + is overwritten. Fortunately libata doesn't implement any of the + affected ioctl commands, so this would only happen when we query + both an IDE and an ATA device in the same command such as + "hdparm -N -c /dev/hda /dev/sda" + +* The libata code for unknown reasons started using ATA_IOC_GET_IO32 + and ATA_IOC_SET_IO32 as aliases for HDIO_GET_32BIT and HDIO_SET_32BIT, + while the ioctl commands that were added later use the normal + HDIO_* names. This is harmless but rather confusing. + +This addresses all four issues by changing the code to use put_user() +on an 'unsigned long' variable in HDIO_GET_32BIT, like the IDE subsystem +does, and by clarifying the names of the ioctl commands. + +Signed-off-by: Arnd Bergmann +Reported-by: Soohoon Lee +Tested-by: Soohoon Lee +Cc: stable@vger.kernel.org +Signed-off-by: Tejun Heo +--- + drivers/ata/libata-scsi.c | 11 +++++------ + include/linux/ata.h | 4 ++-- + 2 files changed, 7 insertions(+), 8 deletions(-) + +diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c +index 7e959f9..e417e1a 100644 +--- a/drivers/ata/libata-scsi.c ++++ b/drivers/ata/libata-scsi.c +@@ -675,19 +675,18 @@ static int ata_ioc32(struct ata_port *ap) + int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev, + int cmd, void __user *arg) + { +- int val = -EINVAL, rc = -EINVAL; ++ unsigned long val; ++ int rc = -EINVAL; + unsigned long flags; + + switch (cmd) { +- case ATA_IOC_GET_IO32: ++ case HDIO_GET_32BIT: + spin_lock_irqsave(ap->lock, flags); + val = ata_ioc32(ap); + spin_unlock_irqrestore(ap->lock, flags); +- if (copy_to_user(arg, &val, 1)) +- return -EFAULT; +- return 0; ++ return put_user(val, (unsigned long __user *)arg); + +- case ATA_IOC_SET_IO32: ++ case HDIO_SET_32BIT: + val = (unsigned long) arg; + rc = 0; + spin_lock_irqsave(ap->lock, flags); +diff --git a/include/linux/ata.h b/include/linux/ata.h +index d2992bf..c1a2f34 100644 +--- a/include/linux/ata.h ++++ b/include/linux/ata.h +@@ -487,8 +487,8 @@ enum ata_tf_protocols { + }; + + enum ata_ioctls { +- ATA_IOC_GET_IO32 = 0x309, +- ATA_IOC_SET_IO32 = 0x324, ++ ATA_IOC_GET_IO32 = 0x309, /* HDIO_GET_32BIT */ ++ ATA_IOC_SET_IO32 = 0x324, /* HDIO_SET_32BIT */ + }; + + /* core structures */ +-- +2.7.2 + diff --git a/kernel/kernel/files/patches/mageia/series b/kernel/kernel/files/patches/mageia/series index 331e7847..9a73c795 100644 --- a/kernel/kernel/files/patches/mageia/series +++ b/kernel/kernel/files/patches/mageia/series @@ -14,6 +14,27 @@ ### ### Stable Queue ### +stable-use-d_seq-to-get-coherency-between-d_inode-and-d_flags.patch +stable-drivers-sh-restore-legacy-clock-domain-on-superh-platforms.patch +stable-btrfs-fix-deadlock-running-delayed-iputs-at-transaction-commit-time.patch +stable-btrfs-fix-no_space-in-write-and-rm-loop.patch +stable-btrfs-async-thread-fix-a-use-after-free-error-for-trace.patch +stable-drm-amdgpu-mask-out-wc-from-bo-on-unsupported-arches.patch +stable-block-initialize-max_dev_sectors-to-0.patch +stable-pci-keystone-fix-msi-code-that-retrieves-struct-pcie_port-pointer.patch +stable-parisc-fix-ptrace-syscall-number-and-return-value-modification.patch +stable-mips-kvm-fix-ioctl-error-handling.patch +stable-kvm-x86-update-tsc-multiplier-on-change.patch +stable-fbcon-set-a-default-value-to-blink-interval.patch +stable-cifs-fix-out-of-bounds-access-in-lease-parsing.patch +stable-cifs-fix-smb2-interim-response-processing-for-read-requests.patch +stable-fix-cifs_uniqueid_to_ino_t-function-for-s390x.patch +stable-vfio-fix-ioctl-error-handling.patch +stable-kvm-x86-fix-root-cause-for-missed-hardware-breakpoints.patch +stable-arm-arm64-kvm-fix-ioctl-error-handling.patch +stable-iommu-amd-apply-workaround-for-ats-write-permission-check.patch +stable-iommu-amd-fix-boot-warning-when-device-00-00.0-is-not-iommu-covered.patch +stable-iommu-vt-d-use-bus_notify_removed_device-in-hotplug-path.patch ### ### Arch x86 @@ -121,6 +142,14 @@ block-Make-CFQ-default-to-IOPS-mode-on-SSDs.patch # ahci ids ahci-add-new-Intel-device-IDs.patch +ata-Adding-Intel-Lewisburg-device-IDs-for-SATA.patch + +# fix unwanted automounting of partitions +ata-ahci-don-t-mark-HotPlugCapable-Ports-as-external.patch + +# libata fixes +libata-Align-ata_device-s-id-on-a-cacheline.patch +libata-fix-HDIO_GET_32BIT-ioctl.patch ### ### File-system @@ -131,15 +160,7 @@ fs-aufs-4.4.patch fs-aufs-4.4-modular.patch # ovl fixes -fs-ovl-allow-zero-size-xattr.patch -fs-ovl-use-a-minimal-buffer-in-ovl_copy_xattr.patch fs-ovl-move-super-block-magic-number-to-magic.h.patch -fs-ovl-root-copy-attr.patch -fs-ovl-setattr-check-permissions-before-copy-up.patch -fs-ovl-check-dentry-positiveness-in-ovl_cleanup_whiteou.patch - -# xfs trace fix (mga#17489) -fs-xfs-Revert-xfs-clear-PF_NOFREEZE-for-xfsaild-kthread.patch ### ### FireWire @@ -200,13 +221,6 @@ gpu-drm-0109-drm-vc4-Add-an-interface-for-capturing-the-GPU-state.patch gpu-drm-radeon-Update-radeon_get_vblank_counter_kms.patch gpu-drm-radeon-Drop-unnecessary-unsigned-int-0-check.patch -# vblank fixes -gpu-drm-No-Op-redundant-calls-to-drm_vblank_off-v2.patch -gpu-drm-Prevent-vblank-counter-bumps-1-with-active-vblank-clients-v2.patch -gpu-drm-Fix-drm_vblank_pre_post_modeset-regression-from-Linux-4.4.patch -gpu-drm-Fix-treatment-of-drm_vblank_offdelay-in-drm_vblank_on-v2.patch -gpu-drm_nouveau_display-Enable-vblank-irqs-after-display-engine-is-on-again.patch - ### ### Hardware Monitoring ### @@ -402,3 +416,7 @@ arm-0032-ARM-bcm2835-enable-auxiliary-spi-driver-in-defconfig.patch ### ### Tools ### + +### +### UAPI +### diff --git a/kernel/kernel/files/patches/mageia/stable-arm-arm64-kvm-fix-ioctl-error-handling.patch b/kernel/kernel/files/patches/mageia/stable-arm-arm64-kvm-fix-ioctl-error-handling.patch new file mode 100644 index 00000000..507fd847 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-arm-arm64-kvm-fix-ioctl-error-handling.patch @@ -0,0 +1,51 @@ +From 4cad67fca3fc952d6f2ed9e799621f07666a560f Mon Sep 17 00:00:00 2001 +From: "Michael S. Tsirkin" +Date: Sun, 28 Feb 2016 17:32:07 +0200 +Subject: arm/arm64: KVM: Fix ioctl error handling + +From: Michael S. Tsirkin + +commit 4cad67fca3fc952d6f2ed9e799621f07666a560f upstream. + +Calling return copy_to_user(...) in an ioctl will not +do the right thing if there's a pagefault: +copy_to_user returns the number of bytes not copied +in this case. + +Fix up kvm to do + return copy_to_user(...)) ? -EFAULT : 0; + +everywhere. + +Acked-by: Christoffer Dall +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Marc Zyngier +Signed-off-by: Greg Kroah-Hartman + +--- + arch/arm/kvm/guest.c | 2 +- + arch/arm64/kvm/guest.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/arm/kvm/guest.c ++++ b/arch/arm/kvm/guest.c +@@ -155,7 +155,7 @@ static int get_timer_reg(struct kvm_vcpu + u64 val; + + val = kvm_arm_timer_get_reg(vcpu, reg->id); +- return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)); ++ return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0; + } + + static unsigned long num_core_regs(void) +--- a/arch/arm64/kvm/guest.c ++++ b/arch/arm64/kvm/guest.c +@@ -186,7 +186,7 @@ static int get_timer_reg(struct kvm_vcpu + u64 val; + + val = kvm_arm_timer_get_reg(vcpu, reg->id); +- return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)); ++ return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0; + } + + /** diff --git a/kernel/kernel/files/patches/mageia/stable-block-initialize-max_dev_sectors-to-0.patch b/kernel/kernel/files/patches/mageia/stable-block-initialize-max_dev_sectors-to-0.patch new file mode 100644 index 00000000..9546bf7a --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-block-initialize-max_dev_sectors-to-0.patch @@ -0,0 +1,36 @@ +From 5f009d3f8e6685fe8c6215082c1696a08b411220 Mon Sep 17 00:00:00 2001 +From: Keith Busch +Date: Wed, 10 Feb 2016 16:52:47 -0700 +Subject: block: Initialize max_dev_sectors to 0 + +From: Keith Busch + +commit 5f009d3f8e6685fe8c6215082c1696a08b411220 upstream. + +The new queue limit is not used by the majority of block drivers, and +should be initialized to 0 for the driver's requested settings to be used. + +Signed-off-by: Keith Busch +Acked-by: Martin K. Petersen +Reviewed-by: Sagi Grimberg +Reviewed-by: Christoph Hellwig +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman + +--- + block/blk-settings.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/block/blk-settings.c ++++ b/block/blk-settings.c +@@ -91,8 +91,8 @@ void blk_set_default_limits(struct queue + lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK; + lim->virt_boundary_mask = 0; + lim->max_segment_size = BLK_MAX_SEGMENT_SIZE; +- lim->max_sectors = lim->max_dev_sectors = lim->max_hw_sectors = +- BLK_SAFE_MAX_SECTORS; ++ lim->max_sectors = lim->max_hw_sectors = BLK_SAFE_MAX_SECTORS; ++ lim->max_dev_sectors = 0; + lim->chunk_sectors = 0; + lim->max_write_same_sectors = 0; + lim->max_discard_sectors = 0; diff --git a/kernel/kernel/files/patches/mageia/stable-btrfs-async-thread-fix-a-use-after-free-error-for-trace.patch b/kernel/kernel/files/patches/mageia/stable-btrfs-async-thread-fix-a-use-after-free-error-for-trace.patch new file mode 100644 index 00000000..25c4845c --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-btrfs-async-thread-fix-a-use-after-free-error-for-trace.patch @@ -0,0 +1,36 @@ +From 0a95b851370b84a4b9d92ee6d1fa0926901d0454 Mon Sep 17 00:00:00 2001 +From: Qu Wenruo +Date: Fri, 22 Jan 2016 09:28:38 +0800 +Subject: btrfs: async-thread: Fix a use-after-free error for trace + +From: Qu Wenruo + +commit 0a95b851370b84a4b9d92ee6d1fa0926901d0454 upstream. + +Parameter of trace_btrfs_work_queued() can be freed in its workqueue. +So no one use use that pointer after queue_work(). + +Fix the user-after-free bug by move the trace line before queue_work(). + +Reported-by: Dave Jones +Signed-off-by: Qu Wenruo +Reviewed-by: David Sterba +Signed-off-by: Chris Mason +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/async-thread.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/btrfs/async-thread.c ++++ b/fs/btrfs/async-thread.c +@@ -328,8 +328,8 @@ static inline void __btrfs_queue_work(st + list_add_tail(&work->ordered_list, &wq->ordered_list); + spin_unlock_irqrestore(&wq->list_lock, flags); + } +- queue_work(wq->normal_wq, &work->normal_work); + trace_btrfs_work_queued(work); ++ queue_work(wq->normal_wq, &work->normal_work); + } + + void btrfs_queue_work(struct btrfs_workqueue *wq, diff --git a/kernel/kernel/files/patches/mageia/stable-btrfs-fix-deadlock-running-delayed-iputs-at-transaction-commit-time.patch b/kernel/kernel/files/patches/mageia/stable-btrfs-fix-deadlock-running-delayed-iputs-at-transaction-commit-time.patch new file mode 100644 index 00000000..2519f320 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-btrfs-fix-deadlock-running-delayed-iputs-at-transaction-commit-time.patch @@ -0,0 +1,238 @@ +From c2d6cb1636d235257086f939a8194ef0bf93af6e Mon Sep 17 00:00:00 2001 +From: Filipe Manana +Date: Fri, 15 Jan 2016 11:05:12 +0000 +Subject: Btrfs: fix deadlock running delayed iputs at transaction commit time + +From: Filipe Manana + +commit c2d6cb1636d235257086f939a8194ef0bf93af6e upstream. + +While running a stress test I ran into a deadlock when running the delayed +iputs at transaction time, which produced the following report and trace: + +[ 886.399989] ============================================= +[ 886.400871] [ INFO: possible recursive locking detected ] +[ 886.401663] 4.4.0-rc6-btrfs-next-18+ #1 Not tainted +[ 886.402384] --------------------------------------------- +[ 886.403182] fio/8277 is trying to acquire lock: +[ 886.403568] (&fs_info->delayed_iput_sem){++++..}, at: [] btrfs_run_delayed_iputs+0x36/0xbf [btrfs] +[ 886.403568] +[ 886.403568] but task is already holding lock: +[ 886.403568] (&fs_info->delayed_iput_sem){++++..}, at: [] btrfs_run_delayed_iputs+0x36/0xbf [btrfs] +[ 886.403568] +[ 886.403568] other info that might help us debug this: +[ 886.403568] Possible unsafe locking scenario: +[ 886.403568] +[ 886.403568] CPU0 +[ 886.403568] ---- +[ 886.403568] lock(&fs_info->delayed_iput_sem); +[ 886.403568] lock(&fs_info->delayed_iput_sem); +[ 886.403568] +[ 886.403568] *** DEADLOCK *** +[ 886.403568] +[ 886.403568] May be due to missing lock nesting notation +[ 886.403568] +[ 886.403568] 3 locks held by fio/8277: +[ 886.403568] #0: (sb_writers#11){.+.+.+}, at: [] __sb_start_write+0x5f/0xb0 +[ 886.403568] #1: (&sb->s_type->i_mutex_key#15){+.+.+.}, at: [] btrfs_file_write_iter+0x73/0x408 [btrfs] +[ 886.403568] #2: (&fs_info->delayed_iput_sem){++++..}, at: [] btrfs_run_delayed_iputs+0x36/0xbf [btrfs] +[ 886.403568] +[ 886.403568] stack backtrace: +[ 886.403568] CPU: 6 PID: 8277 Comm: fio Not tainted 4.4.0-rc6-btrfs-next-18+ #1 +[ 886.403568] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS by qemu-project.org 04/01/2014 +[ 886.403568] 0000000000000000 ffff88009f80f770 ffffffff8125d4fd ffffffff82af1fc0 +[ 886.403568] ffff88009f80f830 ffffffff8108e5f9 0000000200000000 ffff88009fd92290 +[ 886.403568] 0000000000000000 ffffffff82af1fc0 ffffffff829cfb01 00042b216d008804 +[ 886.403568] Call Trace: +[ 886.403568] [] dump_stack+0x4e/0x79 +[ 886.403568] [] __lock_acquire+0xd42/0xf0b +[ 886.403568] [] ? __module_address+0xdf/0x108 +[ 886.403568] [] lock_acquire+0x10d/0x194 +[ 886.403568] [] ? lock_acquire+0x10d/0x194 +[ 886.403568] [] ? btrfs_run_delayed_iputs+0x36/0xbf [btrfs] +[ 886.489542] [] down_read+0x3e/0x4d +[ 886.489542] [] ? btrfs_run_delayed_iputs+0x36/0xbf [btrfs] +[ 886.489542] [] btrfs_run_delayed_iputs+0x36/0xbf [btrfs] +[ 886.489542] [] btrfs_commit_transaction+0x8f5/0x96e [btrfs] +[ 886.489542] [] flush_space+0x435/0x44a [btrfs] +[ 886.489542] [] ? reserve_metadata_bytes+0x26a/0x384 [btrfs] +[ 886.489542] [] reserve_metadata_bytes+0x28d/0x384 [btrfs] +[ 886.489542] [] ? btrfs_block_rsv_refill+0x58/0x96 [btrfs] +[ 886.489542] [] btrfs_block_rsv_refill+0x70/0x96 [btrfs] +[ 886.489542] [] btrfs_evict_inode+0x394/0x55a [btrfs] +[ 886.489542] [] evict+0xa7/0x15c +[ 886.489542] [] iput+0x1d3/0x266 +[ 886.489542] [] btrfs_run_delayed_iputs+0x8f/0xbf [btrfs] +[ 886.489542] [] btrfs_commit_transaction+0x8f5/0x96e [btrfs] +[ 886.489542] [] ? signal_pending_state+0x31/0x31 +[ 886.489542] [] btrfs_alloc_data_chunk_ondemand+0x1d7/0x288 [btrfs] +[ 886.489542] [] btrfs_check_data_free_space+0x40/0x59 [btrfs] +[ 886.489542] [] btrfs_delalloc_reserve_space+0x1e/0x4e [btrfs] +[ 886.489542] [] btrfs_direct_IO+0x10c/0x27e [btrfs] +[ 886.489542] [] generic_file_direct_write+0xb3/0x128 +[ 886.489542] [] btrfs_file_write_iter+0x229/0x408 [btrfs] +[ 886.489542] [] ? __lock_is_held+0x38/0x50 +[ 886.489542] [] __vfs_write+0x7c/0xa5 +[ 886.489542] [] vfs_write+0xa0/0xe4 +[ 886.489542] [] SyS_write+0x50/0x7e +[ 886.489542] [] entry_SYSCALL_64_fastpath+0x12/0x6f +[ 1081.852335] INFO: task fio:8244 blocked for more than 120 seconds. +[ 1081.854348] Not tainted 4.4.0-rc6-btrfs-next-18+ #1 +[ 1081.857560] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. +[ 1081.863227] fio D ffff880213f9bb28 0 8244 8240 0x00000000 +[ 1081.868719] ffff880213f9bb28 00ffffff810fc6b0 ffffffff0000000a ffff88023ed55240 +[ 1081.872499] ffff880206b5d400 ffff880213f9c000 ffff88020a4d5318 ffff880206b5d400 +[ 1081.876834] ffffffff00000001 ffff880206b5d400 ffff880213f9bb40 ffffffff81482ba4 +[ 1081.880782] Call Trace: +[ 1081.881793] [] schedule+0x7f/0x97 +[ 1081.883340] [] rwsem_down_write_failed+0x2d5/0x325 +[ 1081.895525] [] ? trace_hardirqs_on_caller+0x16/0x1ab +[ 1081.897419] [] call_rwsem_down_write_failed+0x13/0x20 +[ 1081.899251] [] ? call_rwsem_down_write_failed+0x13/0x20 +[ 1081.901063] [] ? __down_write_nested.isra.0+0x1f/0x21 +[ 1081.902365] [] down_write+0x43/0x57 +[ 1081.903846] [] ? btrfs_alloc_data_chunk_ondemand+0x1f6/0x288 [btrfs] +[ 1081.906078] [] btrfs_alloc_data_chunk_ondemand+0x1f6/0x288 [btrfs] +[ 1081.908846] [] ? mark_held_locks+0x56/0x6c +[ 1081.910409] [] btrfs_check_data_free_space+0x40/0x59 [btrfs] +[ 1081.912482] [] btrfs_delalloc_reserve_space+0x1e/0x4e [btrfs] +[ 1081.914597] [] btrfs_direct_IO+0x10c/0x27e [btrfs] +[ 1081.919037] [] generic_file_direct_write+0xb3/0x128 +[ 1081.920754] [] btrfs_file_write_iter+0x229/0x408 [btrfs] +[ 1081.922496] [] ? __lock_is_held+0x38/0x50 +[ 1081.923922] [] __vfs_write+0x7c/0xa5 +[ 1081.925275] [] vfs_write+0xa0/0xe4 +[ 1081.926584] [] SyS_write+0x50/0x7e +[ 1081.927968] [] entry_SYSCALL_64_fastpath+0x12/0x6f +[ 1081.985293] INFO: lockdep is turned off. +[ 1081.986132] INFO: task fio:8249 blocked for more than 120 seconds. +[ 1081.987434] Not tainted 4.4.0-rc6-btrfs-next-18+ #1 +[ 1081.988534] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. +[ 1081.990147] fio D ffff880218febbb8 0 8249 8240 0x00000000 +[ 1081.991626] ffff880218febbb8 00ffffff81486b8e ffff88020000000b ffff88023ed75240 +[ 1081.993258] ffff8802120a9a00 ffff880218fec000 ffff88020a4d5318 ffff8802120a9a00 +[ 1081.994850] ffffffff00000001 ffff8802120a9a00 ffff880218febbd0 ffffffff81482ba4 +[ 1081.996485] Call Trace: +[ 1081.997037] [] schedule+0x7f/0x97 +[ 1081.998017] [] rwsem_down_write_failed+0x2d5/0x325 +[ 1081.999241] [] ? finish_wait+0x6d/0x76 +[ 1082.000306] [] call_rwsem_down_write_failed+0x13/0x20 +[ 1082.001533] [] ? call_rwsem_down_write_failed+0x13/0x20 +[ 1082.002776] [] ? __down_write_nested.isra.0+0x1f/0x21 +[ 1082.003995] [] down_write+0x43/0x57 +[ 1082.005000] [] ? btrfs_alloc_data_chunk_ondemand+0x1f6/0x288 [btrfs] +[ 1082.007403] [] btrfs_alloc_data_chunk_ondemand+0x1f6/0x288 [btrfs] +[ 1082.008988] [] btrfs_fallocate+0x7c1/0xc2f [btrfs] +[ 1082.010193] [] ? percpu_down_read+0x4e/0x77 +[ 1082.011280] [] ? __sb_start_write+0x5f/0xb0 +[ 1082.012265] [] ? __sb_start_write+0x5f/0xb0 +[ 1082.013021] [] vfs_fallocate+0x170/0x1ff +[ 1082.013738] [] ioctl_preallocate+0x89/0x9b +[ 1082.014778] [] do_vfs_ioctl+0x40a/0x4ea +[ 1082.015778] [] ? SYSC_newfstat+0x25/0x2e +[ 1082.016806] [] ? __fget_light+0x4d/0x71 +[ 1082.017789] [] SyS_ioctl+0x57/0x79 +[ 1082.018706] [] entry_SYSCALL_64_fastpath+0x12/0x6f + +This happens because we can recursively acquire the semaphore +fs_info->delayed_iput_sem when attempting to allocate space to satisfy +a file write request as shown in the first trace above - when committing +a transaction we acquire (down_read) the semaphore before running the +delayed iputs, and when running a delayed iput() we can end up calling +an inode's eviction handler, which in turn commits another transaction +and attempts to acquire (down_read) again the semaphore to run more +delayed iput operations. +This results in a deadlock because if a task acquires multiple times a +semaphore it should invoke down_read_nested() with a different lockdep +class for each level of recursion. + +Fix this by simplifying the implementation and use a mutex instead that +is acquired by the cleaner kthread before it runs the delayed iputs +instead of always acquiring a semaphore before delayed references are +run from anywhere. + +Fixes: d7c151717a1e (btrfs: Fix NO_SPACE bug caused by delayed-iput) +Signed-off-by: Filipe Manana +Signed-off-by: Chris Mason +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/ctree.h | 2 +- + fs/btrfs/disk-io.c | 5 ++++- + fs/btrfs/extent-tree.c | 9 +++++---- + fs/btrfs/inode.c | 4 ---- + 4 files changed, 10 insertions(+), 10 deletions(-) + +--- a/fs/btrfs/ctree.h ++++ b/fs/btrfs/ctree.h +@@ -1572,7 +1572,7 @@ struct btrfs_fs_info { + + spinlock_t delayed_iput_lock; + struct list_head delayed_iputs; +- struct rw_semaphore delayed_iput_sem; ++ struct mutex cleaner_delayed_iput_mutex; + + /* this protects tree_mod_seq_list */ + spinlock_t tree_mod_seq_lock; +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -1796,7 +1796,10 @@ static int cleaner_kthread(void *arg) + goto sleep; + } + ++ mutex_lock(&root->fs_info->cleaner_delayed_iput_mutex); + btrfs_run_delayed_iputs(root); ++ mutex_unlock(&root->fs_info->cleaner_delayed_iput_mutex); ++ + again = btrfs_clean_one_deleted_snapshot(root); + mutex_unlock(&root->fs_info->cleaner_mutex); + +@@ -2556,8 +2559,8 @@ int open_ctree(struct super_block *sb, + mutex_init(&fs_info->delete_unused_bgs_mutex); + mutex_init(&fs_info->reloc_mutex); + mutex_init(&fs_info->delalloc_root_mutex); ++ mutex_init(&fs_info->cleaner_delayed_iput_mutex); + seqlock_init(&fs_info->profiles_lock); +- init_rwsem(&fs_info->delayed_iput_sem); + + INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots); + INIT_LIST_HEAD(&fs_info->space_info); +--- a/fs/btrfs/extent-tree.c ++++ b/fs/btrfs/extent-tree.c +@@ -4100,11 +4100,12 @@ commit_trans: + if (ret) + return ret; + /* +- * make sure that all running delayed iput are +- * done ++ * The cleaner kthread might still be doing iput ++ * operations. Wait for it to finish so that ++ * more space is released. + */ +- down_write(&root->fs_info->delayed_iput_sem); +- up_write(&root->fs_info->delayed_iput_sem); ++ mutex_lock(&root->fs_info->cleaner_delayed_iput_mutex); ++ mutex_unlock(&root->fs_info->cleaner_delayed_iput_mutex); + goto again; + } else { + btrfs_end_transaction(trans, root); +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -3142,8 +3142,6 @@ void btrfs_run_delayed_iputs(struct btrf + if (empty) + return; + +- down_read(&fs_info->delayed_iput_sem); +- + spin_lock(&fs_info->delayed_iput_lock); + list_splice_init(&fs_info->delayed_iputs, &list); + spin_unlock(&fs_info->delayed_iput_lock); +@@ -3154,8 +3152,6 @@ void btrfs_run_delayed_iputs(struct btrf + iput(delayed->inode); + kfree(delayed); + } +- +- up_read(&root->fs_info->delayed_iput_sem); + } + + /* diff --git a/kernel/kernel/files/patches/mageia/stable-btrfs-fix-no_space-in-write-and-rm-loop.patch b/kernel/kernel/files/patches/mageia/stable-btrfs-fix-no_space-in-write-and-rm-loop.patch new file mode 100644 index 00000000..6197e535 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-btrfs-fix-no_space-in-write-and-rm-loop.patch @@ -0,0 +1,47 @@ +From e1746e8381cd2af421f75557b5cae3604fc18b35 Mon Sep 17 00:00:00 2001 +From: Zhao Lei +Date: Tue, 1 Dec 2015 18:39:40 +0800 +Subject: btrfs: Fix no_space in write and rm loop + +From: Zhao Lei + +commit e1746e8381cd2af421f75557b5cae3604fc18b35 upstream. + +I see no_space in v4.4-rc1 again in xfstests generic/102. +It happened randomly in some node only. +(one of 4 phy-node, and a kvm with non-virtio block driver) + +By bisect, we can found the first-bad is: + commit bdced438acd8 ("block: setup bi_phys_segments after splitting")' +But above patch only triggered the bug by making bio operation +faster(or slower). + +Main reason is in our space_allocating code, we need to commit +page writeback before wait it complish, this patch fixed above +bug. + +BTW, there is another reason for generic/102 fail, caused by +disable default mixed-blockgroup, I'll fix it in xfstests. + +Signed-off-by: Zhao Lei +Signed-off-by: Chris Mason +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/extent-tree.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/fs/btrfs/extent-tree.c ++++ b/fs/btrfs/extent-tree.c +@@ -4086,8 +4086,10 @@ commit_trans: + !atomic_read(&root->fs_info->open_ioctl_trans)) { + need_commit--; + +- if (need_commit > 0) ++ if (need_commit > 0) { ++ btrfs_start_delalloc_roots(fs_info, 0, -1); + btrfs_wait_ordered_roots(fs_info, -1); ++ } + + trans = btrfs_join_transaction(root); + if (IS_ERR(trans)) diff --git a/kernel/kernel/files/patches/mageia/stable-cifs-fix-out-of-bounds-access-in-lease-parsing.patch b/kernel/kernel/files/patches/mageia/stable-cifs-fix-out-of-bounds-access-in-lease-parsing.patch new file mode 100644 index 00000000..f29a9f19 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-cifs-fix-out-of-bounds-access-in-lease-parsing.patch @@ -0,0 +1,104 @@ +From deb7deff2f00bdbbcb3d560dad2a89ef37df837d Mon Sep 17 00:00:00 2001 +From: Justin Maggard +Date: Tue, 9 Feb 2016 15:52:08 -0800 +Subject: cifs: fix out-of-bounds access in lease parsing + +From: Justin Maggard + +commit deb7deff2f00bdbbcb3d560dad2a89ef37df837d upstream. + +When opening a file, SMB2_open() attempts to parse the lease state from the +SMB2 CREATE Response. However, the parsing code was not careful to ensure +that the create contexts are not empty or invalid, which can lead to out- +of-bounds memory access. This can be seen easily by trying +to read a file from a OSX 10.11 SMB3 server. Here is sample crash output: + +BUG: unable to handle kernel paging request at ffff8800a1a77cc6 +IP: [] SMB2_open+0x804/0x960 +PGD 8f77067 PUD 0 +Oops: 0000 [#1] SMP +Modules linked in: +CPU: 3 PID: 2876 Comm: cp Not tainted 4.5.0-rc3.x86_64.1+ #14 +Hardware name: NETGEAR ReadyNAS 314 /ReadyNAS 314 , BIOS 4.6.5 10/11/2012 +task: ffff880073cdc080 ti: ffff88005b31c000 task.ti: ffff88005b31c000 +RIP: 0010:[] [] SMB2_open+0x804/0x960 +RSP: 0018:ffff88005b31fa08 EFLAGS: 00010282 +RAX: 0000000000000015 RBX: 0000000000000000 RCX: 0000000000000006 +RDX: 0000000000000000 RSI: 0000000000000246 RDI: ffff88007eb8c8b0 +RBP: ffff88005b31fad8 R08: 666666203d206363 R09: 6131613030383866 +R10: 3030383866666666 R11: 00000000000002b0 R12: ffff8800660fd800 +R13: ffff8800a1a77cc2 R14: 00000000424d53fe R15: ffff88005f5a28c0 +FS: 00007f7c8a2897c0(0000) GS:ffff88007eb80000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b +CR2: ffff8800a1a77cc6 CR3: 000000005b281000 CR4: 00000000000006e0 +Stack: + ffff88005b31fa70 ffffffff88278789 00000000000001d3 ffff88005f5a2a80 + ffffffff00000003 ffff88005d029d00 ffff88006fde05a0 0000000000000000 + ffff88005b31fc78 ffff88006fde0780 ffff88005b31fb2f 0000000100000fe0 +Call Trace: + [] ? cifsConvertToUTF16+0x159/0x2d0 + [] smb2_open_file+0x98/0x210 + [] ? __kmalloc+0x1c/0xe0 + [] cifs_open+0x2a4/0x720 + [] do_dentry_open+0x1ff/0x310 + [] ? cifsFileInfo_get+0x30/0x30 + [] vfs_open+0x52/0x60 + [] path_openat+0x170/0xf70 + [] ? remove_wait_queue+0x48/0x50 + [] do_filp_open+0x79/0xd0 + [] ? __alloc_fd+0x3a/0x170 + [] do_sys_open+0x114/0x1e0 + [] SyS_open+0x19/0x20 + [] entry_SYSCALL_64_fastpath+0x12/0x6a +Code: 4d 8d 6c 07 04 31 c0 4c 89 ee e8 47 6f e5 ff 31 c9 41 89 ce 44 89 f1 48 c7 c7 28 b1 bd 88 31 c0 49 01 cd 4c 89 ee e8 2b 6f e5 ff <45> 0f b7 75 04 48 c7 c7 31 b1 bd 88 31 c0 4d 01 ee 4c 89 f6 e8 +RIP [] SMB2_open+0x804/0x960 + RSP +CR2: ffff8800a1a77cc6 +---[ end trace d9f69ba64feee469 ]--- + +Signed-off-by: Justin Maggard +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman + +--- + fs/cifs/smb2pdu.c | 24 ++++++++++++++---------- + 1 file changed, 14 insertions(+), 10 deletions(-) + +--- a/fs/cifs/smb2pdu.c ++++ b/fs/cifs/smb2pdu.c +@@ -1109,21 +1109,25 @@ parse_lease_state(struct TCP_Server_Info + { + char *data_offset; + struct create_context *cc; +- unsigned int next = 0; ++ unsigned int next; ++ unsigned int remaining; + char *name; + + data_offset = (char *)rsp + 4 + le32_to_cpu(rsp->CreateContextsOffset); ++ remaining = le32_to_cpu(rsp->CreateContextsLength); + cc = (struct create_context *)data_offset; +- do { +- cc = (struct create_context *)((char *)cc + next); ++ while (remaining >= sizeof(struct create_context)) { + name = le16_to_cpu(cc->NameOffset) + (char *)cc; +- if (le16_to_cpu(cc->NameLength) != 4 || +- strncmp(name, "RqLs", 4)) { +- next = le32_to_cpu(cc->Next); +- continue; +- } +- return server->ops->parse_lease_buf(cc, epoch); +- } while (next != 0); ++ if (le16_to_cpu(cc->NameLength) == 4 && ++ strncmp(name, "RqLs", 4) == 0) ++ return server->ops->parse_lease_buf(cc, epoch); ++ ++ next = le32_to_cpu(cc->Next); ++ if (!next) ++ break; ++ remaining -= next; ++ cc = (struct create_context *)((char *)cc + next); ++ } + + return 0; + } diff --git a/kernel/kernel/files/patches/mageia/stable-cifs-fix-smb2-interim-response-processing-for-read-requests.patch b/kernel/kernel/files/patches/mageia/stable-cifs-fix-smb2-interim-response-processing-for-read-requests.patch new file mode 100644 index 00000000..49789516 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-cifs-fix-smb2-interim-response-processing-for-read-requests.patch @@ -0,0 +1,72 @@ +From 6cc3b24235929b54acd5ecc987ef11a425bd209e Mon Sep 17 00:00:00 2001 +From: Pavel Shilovsky +Date: Sat, 27 Feb 2016 11:58:18 +0300 +Subject: CIFS: Fix SMB2+ interim response processing for read requests + +From: Pavel Shilovsky + +commit 6cc3b24235929b54acd5ecc987ef11a425bd209e upstream. + +For interim responses we only need to parse a header and update +a number credits. Now it is done for all SMB2+ command except +SMB2_READ which is wrong. Fix this by adding such processing. + +Signed-off-by: Pavel Shilovsky +Tested-by: Shirish Pargaonkar +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman + +--- + fs/cifs/cifssmb.c | 21 ++++++++++++++++++--- + 1 file changed, 18 insertions(+), 3 deletions(-) + +--- a/fs/cifs/cifssmb.c ++++ b/fs/cifs/cifssmb.c +@@ -1396,11 +1396,10 @@ openRetry: + * current bigbuf. + */ + static int +-cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) ++discard_remaining_data(struct TCP_Server_Info *server) + { + unsigned int rfclen = get_rfc1002_length(server->smallbuf); + int remaining = rfclen + 4 - server->total_read; +- struct cifs_readdata *rdata = mid->callback_data; + + while (remaining > 0) { + int length; +@@ -1414,10 +1413,20 @@ cifs_readv_discard(struct TCP_Server_Inf + remaining -= length; + } + +- dequeue_mid(mid, rdata->result); + return 0; + } + ++static int ++cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) ++{ ++ int length; ++ struct cifs_readdata *rdata = mid->callback_data; ++ ++ length = discard_remaining_data(server); ++ dequeue_mid(mid, rdata->result); ++ return length; ++} ++ + int + cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) + { +@@ -1446,6 +1455,12 @@ cifs_readv_receive(struct TCP_Server_Inf + return length; + server->total_read += length; + ++ if (server->ops->is_status_pending && ++ server->ops->is_status_pending(buf, server, 0)) { ++ discard_remaining_data(server); ++ return -1; ++ } ++ + /* Was the SMB read successful? */ + rdata->result = server->ops->map_error(buf, false); + if (rdata->result != 0) { diff --git a/kernel/kernel/files/patches/mageia/stable-drivers-sh-restore-legacy-clock-domain-on-superh-platforms.patch b/kernel/kernel/files/patches/mageia/stable-drivers-sh-restore-legacy-clock-domain-on-superh-platforms.patch new file mode 100644 index 00000000..e0f47f2d --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-drivers-sh-restore-legacy-clock-domain-on-superh-platforms.patch @@ -0,0 +1,39 @@ +From 0378ba4899d5fbd8494ed6580cbc81d7b44dbac6 Mon Sep 17 00:00:00 2001 +From: Geert Uytterhoeven +Date: Wed, 24 Feb 2016 09:43:23 +0100 +Subject: drivers: sh: Restore legacy clock domain on SuperH platforms + +From: Geert Uytterhoeven + +commit 0378ba4899d5fbd8494ed6580cbc81d7b44dbac6 upstream. + +CONFIG_ARCH_SHMOBILE is not only enabled for Renesas ARM platforms +(which are DT based and multi-platform), but also on a select set of +Renesas SuperH platforms (SH7722/SH7723/SH7724/SH7343/SH7366). Hence +since commit 0ba58de231066e47 ("drivers: sh: Get rid of +CONFIG_ARCH_SHMOBILE_MULTI"), the legacy clock domain is no longer +installed on these SuperH platforms, and module clocks may not be +enabled when needed, leading to driver failures. + +To fix this, add an additional check for CONFIG_OF. + +Fixes: 0ba58de231066e47 ("drivers: sh: Get rid of CONFIG_ARCH_SHMOBILE_MULTI"). +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Simon Horman +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/sh/pm_runtime.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/sh/pm_runtime.c ++++ b/drivers/sh/pm_runtime.c +@@ -34,7 +34,7 @@ static struct pm_clk_notifier_block plat + + static int __init sh_pm_runtime_init(void) + { +- if (IS_ENABLED(CONFIG_ARCH_SHMOBILE)) { ++ if (IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_ARCH_SHMOBILE)) { + if (!of_find_compatible_node(NULL, NULL, + "renesas,cpg-mstp-clocks")) + return 0; diff --git a/kernel/kernel/files/patches/mageia/stable-drm-amdgpu-mask-out-wc-from-bo-on-unsupported-arches.patch b/kernel/kernel/files/patches/mageia/stable-drm-amdgpu-mask-out-wc-from-bo-on-unsupported-arches.patch new file mode 100644 index 00000000..fedcd4e3 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-drm-amdgpu-mask-out-wc-from-bo-on-unsupported-arches.patch @@ -0,0 +1,46 @@ +From a187f17f0e15a046aa5d7263b35df55230d92779 Mon Sep 17 00:00:00 2001 +From: Oded Gabbay +Date: Sat, 30 Jan 2016 07:59:34 +0200 +Subject: drm/amdgpu: mask out WC from BO on unsupported arches +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Oded Gabbay + +commit a187f17f0e15a046aa5d7263b35df55230d92779 upstream. + +Reviewed-by: Christian König +Reviewed-by: Michel Dänzer +Signed-off-by: Oded Gabbay +Signed-off-by: Alex Deucher +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include "amdgpu.h" + #include "amdgpu_trace.h" + +@@ -261,6 +262,13 @@ int amdgpu_bo_create_restricted(struct a + AMDGPU_GEM_DOMAIN_OA); + + bo->flags = flags; ++ ++ /* For architectures that don't support WC memory, ++ * mask out the WC flag from the BO ++ */ ++ if (!drm_arch_can_wc_memory()) ++ bo->flags &= ~AMDGPU_GEM_CREATE_CPU_GTT_USWC; ++ + amdgpu_fill_placement_to_bo(bo, placement); + /* Kernel allocation are uninterruptible */ + r = ttm_bo_init(&adev->mman.bdev, &bo->tbo, size, type, diff --git a/kernel/kernel/files/patches/mageia/stable-fbcon-set-a-default-value-to-blink-interval.patch b/kernel/kernel/files/patches/mageia/stable-fbcon-set-a-default-value-to-blink-interval.patch new file mode 100644 index 00000000..4f006707 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-fbcon-set-a-default-value-to-blink-interval.patch @@ -0,0 +1,66 @@ +From a1e533ec07d583d01349ef13c0c965b8633e1b91 Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Mon, 15 Feb 2016 18:41:33 +0000 +Subject: fbcon: set a default value to blink interval + +From: Jean-Philippe Brucker + +commit a1e533ec07d583d01349ef13c0c965b8633e1b91 upstream. + +Since commit 27a4c827c34ac4256a190cc9d24607f953c1c459 + fbcon: use the cursor blink interval provided by vt + +two attempts have been made at fixing a possible hang caused by +cursor_timer_handler. That function registers a timer to be triggered at +"jiffies + fbcon_ops.cur_blink_jiffies". + +A new case had been encountered during initialisation of clcd-pl11x: + + fbcon_fb_registered + do_fbcon_takeover + + -> do_register_con_driver + fbcon_startup + (A) add_cursor_timer (with cur_blink_jiffies = 0) + + -> do_bind_con_driver + visual_init + fbcon_init + (B) cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); + +If we take an softirq anywhere between A and B (and we do), +cursor_timer_handler executes indefinitely. + +Instead of patching all possible paths that lead to this case one at a +time, fix the issue at the source and initialise cur_blink_jiffies to +200ms when allocating fbcon_ops. This was its default value before +aforesaid commit. fbcon_cursor or fbcon_init will refine this value +downstream. + +Signed-off-by: Jean-Philippe Brucker +Tested-by: Scot Doyle +Signed-off-by: Tomi Valkeinen +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/video/console/fbcon.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/video/console/fbcon.c ++++ b/drivers/video/console/fbcon.c +@@ -709,6 +709,7 @@ static int con2fb_acquire_newinfo(struct + } + + if (!err) { ++ ops->cur_blink_jiffies = HZ / 5; + info->fbcon_par = ops; + + if (vc) +@@ -956,6 +957,7 @@ static const char *fbcon_startup(void) + ops->currcon = -1; + ops->graphics = 1; + ops->cur_rotate = -1; ++ ops->cur_blink_jiffies = HZ / 5; + info->fbcon_par = ops; + p->con_rotate = initial_rotation; + set_blitting_type(vc, info); diff --git a/kernel/kernel/files/patches/mageia/stable-fix-cifs_uniqueid_to_ino_t-function-for-s390x.patch b/kernel/kernel/files/patches/mageia/stable-fix-cifs_uniqueid_to_ino_t-function-for-s390x.patch new file mode 100644 index 00000000..966e1f1f --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-fix-cifs_uniqueid_to_ino_t-function-for-s390x.patch @@ -0,0 +1,63 @@ +From 1ee9f4bd1a97026a7b2d7ae9f1f74b45680d0003 Mon Sep 17 00:00:00 2001 +From: Yadan Fan +Date: Mon, 29 Feb 2016 14:44:57 +0800 +Subject: Fix cifs_uniqueid_to_ino_t() function for s390x + +From: Yadan Fan + +commit 1ee9f4bd1a97026a7b2d7ae9f1f74b45680d0003 upstream. + +This issue is caused by commit 02323db17e3a7 ("cifs: fix +cifs_uniqueid_to_ino_t not to ever return 0"), when BITS_PER_LONG +is 64 on s390x, the corresponding cifs_uniqueid_to_ino_t() +function will cast 64-bit fileid to 32-bit by using (ino_t)fileid, +because ino_t (typdefed __kernel_ino_t) is int type. + +It's defined in arch/s390/include/uapi/asm/posix_types.h + + #ifndef __s390x__ + + typedef unsigned long __kernel_ino_t; + ... + #else /* __s390x__ */ + + typedef unsigned int __kernel_ino_t; + +So the #ifdef condition is wrong for s390x, we can just still use +one cifs_uniqueid_to_ino_t() function with comparing sizeof(ino_t) +and sizeof(u64) to choose the correct execution accordingly. + +Signed-off-by: Yadan Fan +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman + +--- + fs/cifs/cifsfs.h | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +--- a/fs/cifs/cifsfs.h ++++ b/fs/cifs/cifsfs.h +@@ -31,19 +31,15 @@ + * so that it will fit. We use hash_64 to convert the value to 31 bits, and + * then add 1, to ensure that we don't end up with a 0 as the value. + */ +-#if BITS_PER_LONG == 64 + static inline ino_t + cifs_uniqueid_to_ino_t(u64 fileid) + { ++ if ((sizeof(ino_t)) < (sizeof(u64))) ++ return (ino_t)hash_64(fileid, (sizeof(ino_t) * 8) - 1) + 1; ++ + return (ino_t)fileid; ++ + } +-#else +-static inline ino_t +-cifs_uniqueid_to_ino_t(u64 fileid) +-{ +- return (ino_t)hash_64(fileid, (sizeof(ino_t) * 8) - 1) + 1; +-} +-#endif + + extern struct file_system_type cifs_fs_type; + extern const struct address_space_operations cifs_addr_ops; diff --git a/kernel/kernel/files/patches/mageia/stable-iommu-amd-apply-workaround-for-ats-write-permission-check.patch b/kernel/kernel/files/patches/mageia/stable-iommu-amd-apply-workaround-for-ats-write-permission-check.patch new file mode 100644 index 00000000..2b6ca214 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-iommu-amd-apply-workaround-for-ats-write-permission-check.patch @@ -0,0 +1,78 @@ +From 358875fd52ab8f00f66328cbf1a1d2486f265829 Mon Sep 17 00:00:00 2001 +From: Jay Cornwall +Date: Wed, 10 Feb 2016 15:48:01 -0600 +Subject: iommu/amd: Apply workaround for ATS write permission check + +From: Jay Cornwall + +commit 358875fd52ab8f00f66328cbf1a1d2486f265829 upstream. + +The AMD Family 15h Models 30h-3Fh (Kaveri) BIOS and Kernel Developer's +Guide omitted part of the BIOS IOMMU L2 register setup specification. +Without this setup the IOMMU L2 does not fully respect write permissions +when handling an ATS translation request. + +The IOMMU L2 will set PTE dirty bit when handling an ATS translation with +write permission request, even when PTE RW bit is clear. This may occur by +direct translation (which would cause a PPR) or by prefetch request from +the ATC. + +This is observed in practice when the IOMMU L2 modifies a PTE which maps a +pagecache page. The ext4 filesystem driver BUGs when asked to writeback +these (non-modified) pages. + +Enable ATS write permission check in the Kaveri IOMMU L2 if BIOS has not. + +Signed-off-by: Jay Cornwall +Signed-off-by: Joerg Roedel +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/iommu/amd_iommu_init.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +--- a/drivers/iommu/amd_iommu_init.c ++++ b/drivers/iommu/amd_iommu_init.c +@@ -1016,6 +1016,34 @@ static void amd_iommu_erratum_746_workar + } + + /* ++ * Family15h Model 30h-3fh (IOMMU Mishandles ATS Write Permission) ++ * Workaround: ++ * BIOS should enable ATS write permission check by setting ++ * L2_DEBUG_3[AtsIgnoreIWDis](D0F2xF4_x47[0]) = 1b ++ */ ++static void amd_iommu_ats_write_check_workaround(struct amd_iommu *iommu) ++{ ++ u32 value; ++ ++ if ((boot_cpu_data.x86 != 0x15) || ++ (boot_cpu_data.x86_model < 0x30) || ++ (boot_cpu_data.x86_model > 0x3f)) ++ return; ++ ++ /* Test L2_DEBUG_3[AtsIgnoreIWDis] == 1 */ ++ value = iommu_read_l2(iommu, 0x47); ++ ++ if (value & BIT(0)) ++ return; ++ ++ /* Set L2_DEBUG_3[AtsIgnoreIWDis] = 1 */ ++ iommu_write_l2(iommu, 0x47, value | BIT(0)); ++ ++ pr_info("AMD-Vi: Applying ATS write check workaround for IOMMU at %s\n", ++ dev_name(&iommu->dev->dev)); ++} ++ ++/* + * This function clues the initialization function for one IOMMU + * together and also allocates the command buffer and programs the + * hardware. It does NOT enable the IOMMU. This is done afterwards. +@@ -1284,6 +1312,7 @@ static int iommu_init_pci(struct amd_iom + } + + amd_iommu_erratum_746_workaround(iommu); ++ amd_iommu_ats_write_check_workaround(iommu); + + iommu->iommu_dev = iommu_device_create(&iommu->dev->dev, iommu, + amd_iommu_groups, "ivhd%d", diff --git a/kernel/kernel/files/patches/mageia/stable-iommu-amd-fix-boot-warning-when-device-00-00.0-is-not-iommu-covered.patch b/kernel/kernel/files/patches/mageia/stable-iommu-amd-fix-boot-warning-when-device-00-00.0-is-not-iommu-covered.patch new file mode 100644 index 00000000..3d0cee23 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-iommu-amd-fix-boot-warning-when-device-00-00.0-is-not-iommu-covered.patch @@ -0,0 +1,92 @@ +From 38e45d02ea9f194b89d6bf41e52ccafc8e2c2b47 Mon Sep 17 00:00:00 2001 +From: Suravee Suthikulpanit +Date: Tue, 23 Feb 2016 13:03:30 +0100 +Subject: iommu/amd: Fix boot warning when device 00:00.0 is not iommu covered + +From: Suravee Suthikulpanit + +commit 38e45d02ea9f194b89d6bf41e52ccafc8e2c2b47 upstream. + +The setup code for the performance counters in the AMD IOMMU driver +tests whether the counters can be written. It tests to setup a counter +for device 00:00.0, which fails on systems where this particular device +is not covered by the IOMMU. + +Fix this by not relying on device 00:00.0 but only on the IOMMU being +present. + +Signed-off-by: Suravee Suthikulpanit +Signed-off-by: Joerg Roedel +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/iommu/amd_iommu_init.c | 34 ++++++++++++++++++++++------------ + 1 file changed, 22 insertions(+), 12 deletions(-) + +--- a/drivers/iommu/amd_iommu_init.c ++++ b/drivers/iommu/amd_iommu_init.c +@@ -228,6 +228,10 @@ static int amd_iommu_enable_interrupts(v + static int __init iommu_go_to_state(enum iommu_init_state state); + static void init_device_table_dma(void); + ++static int iommu_pc_get_set_reg_val(struct amd_iommu *iommu, ++ u8 bank, u8 cntr, u8 fxn, ++ u64 *value, bool is_write); ++ + static inline void update_last_devid(u16 devid) + { + if (devid > amd_iommu_last_bdf) +@@ -1170,8 +1174,8 @@ static void init_iommu_perf_ctr(struct a + amd_iommu_pc_present = true; + + /* Check if the performance counters can be written to */ +- if ((0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val, true)) || +- (0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val2, false)) || ++ if ((0 != iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val, true)) || ++ (0 != iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val2, false)) || + (val != val2)) { + pr_err("AMD-Vi: Unable to write to IOMMU perf counter.\n"); + amd_iommu_pc_present = false; +@@ -2312,22 +2316,15 @@ u8 amd_iommu_pc_get_max_counters(u16 dev + } + EXPORT_SYMBOL(amd_iommu_pc_get_max_counters); + +-int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn, ++static int iommu_pc_get_set_reg_val(struct amd_iommu *iommu, ++ u8 bank, u8 cntr, u8 fxn, + u64 *value, bool is_write) + { +- struct amd_iommu *iommu; + u32 offset; + u32 max_offset_lim; + +- /* Make sure the IOMMU PC resource is available */ +- if (!amd_iommu_pc_present) +- return -ENODEV; +- +- /* Locate the iommu associated with the device ID */ +- iommu = amd_iommu_rlookup_table[devid]; +- + /* Check for valid iommu and pc register indexing */ +- if (WARN_ON((iommu == NULL) || (fxn > 0x28) || (fxn & 7))) ++ if (WARN_ON((fxn > 0x28) || (fxn & 7))) + return -ENODEV; + + offset = (u32)(((0x40|bank) << 12) | (cntr << 8) | fxn); +@@ -2351,3 +2348,16 @@ int amd_iommu_pc_get_set_reg_val(u16 dev + return 0; + } + EXPORT_SYMBOL(amd_iommu_pc_get_set_reg_val); ++ ++int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn, ++ u64 *value, bool is_write) ++{ ++ struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; ++ ++ /* Make sure the IOMMU PC resource is available */ ++ if (!amd_iommu_pc_present || iommu == NULL) ++ return -ENODEV; ++ ++ return iommu_pc_get_set_reg_val(iommu, bank, cntr, fxn, ++ value, is_write); ++} diff --git a/kernel/kernel/files/patches/mageia/stable-iommu-vt-d-use-bus_notify_removed_device-in-hotplug-path.patch b/kernel/kernel/files/patches/mageia/stable-iommu-vt-d-use-bus_notify_removed_device-in-hotplug-path.patch new file mode 100644 index 00000000..9250c977 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-iommu-vt-d-use-bus_notify_removed_device-in-hotplug-path.patch @@ -0,0 +1,68 @@ +From e6a8c9b337eed56eb481e1b4dd2180c25a1e5310 Mon Sep 17 00:00:00 2001 +From: Joerg Roedel +Date: Mon, 29 Feb 2016 23:49:47 +0100 +Subject: iommu/vt-d: Use BUS_NOTIFY_REMOVED_DEVICE in hotplug path + +From: Joerg Roedel + +commit e6a8c9b337eed56eb481e1b4dd2180c25a1e5310 upstream. + +In the PCI hotplug path of the Intel IOMMU driver, replace +the usage of the BUS_NOTIFY_DEL_DEVICE notifier, which is +executed before the driver is unbound from the device, with +BUS_NOTIFY_REMOVED_DEVICE, which runs after that. + +This fixes a kernel BUG being triggered in the VT-d code +when the device driver tries to unmap DMA buffers and the +VT-d driver already destroyed all mappings. + +Reported-by: Stefani Seibold +Signed-off-by: Joerg Roedel +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/iommu/dmar.c | 5 +++-- + drivers/iommu/intel-iommu.c | 4 ++-- + 2 files changed, 5 insertions(+), 4 deletions(-) + +--- a/drivers/iommu/dmar.c ++++ b/drivers/iommu/dmar.c +@@ -329,7 +329,8 @@ static int dmar_pci_bus_notifier(struct + /* Only care about add/remove events for physical functions */ + if (pdev->is_virtfn) + return NOTIFY_DONE; +- if (action != BUS_NOTIFY_ADD_DEVICE && action != BUS_NOTIFY_DEL_DEVICE) ++ if (action != BUS_NOTIFY_ADD_DEVICE && ++ action != BUS_NOTIFY_REMOVED_DEVICE) + return NOTIFY_DONE; + + info = dmar_alloc_pci_notify_info(pdev, action); +@@ -339,7 +340,7 @@ static int dmar_pci_bus_notifier(struct + down_write(&dmar_global_lock); + if (action == BUS_NOTIFY_ADD_DEVICE) + dmar_pci_bus_add_dev(info); +- else if (action == BUS_NOTIFY_DEL_DEVICE) ++ else if (action == BUS_NOTIFY_REMOVED_DEVICE) + dmar_pci_bus_del_dev(info); + up_write(&dmar_global_lock); + +--- a/drivers/iommu/intel-iommu.c ++++ b/drivers/iommu/intel-iommu.c +@@ -4367,7 +4367,7 @@ int dmar_iommu_notify_scope_dev(struct d + rmrru->devices_cnt); + if(ret < 0) + return ret; +- } else if (info->event == BUS_NOTIFY_DEL_DEVICE) { ++ } else if (info->event == BUS_NOTIFY_REMOVED_DEVICE) { + dmar_remove_dev_scope(info, rmrr->segment, + rmrru->devices, rmrru->devices_cnt); + } +@@ -4387,7 +4387,7 @@ int dmar_iommu_notify_scope_dev(struct d + break; + else if(ret < 0) + return ret; +- } else if (info->event == BUS_NOTIFY_DEL_DEVICE) { ++ } else if (info->event == BUS_NOTIFY_REMOVED_DEVICE) { + if (dmar_remove_dev_scope(info, atsr->segment, + atsru->devices, atsru->devices_cnt)) + break; diff --git a/kernel/kernel/files/patches/mageia/stable-kvm-x86-fix-root-cause-for-missed-hardware-breakpoints.patch b/kernel/kernel/files/patches/mageia/stable-kvm-x86-fix-root-cause-for-missed-hardware-breakpoints.patch new file mode 100644 index 00000000..19c33135 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-kvm-x86-fix-root-cause-for-missed-hardware-breakpoints.patch @@ -0,0 +1,56 @@ +From 70e4da7a8ff62f2775337b705f45c804bb450454 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Fri, 26 Feb 2016 12:28:40 +0100 +Subject: KVM: x86: fix root cause for missed hardware breakpoints + +From: Paolo Bonzini + +commit 70e4da7a8ff62f2775337b705f45c804bb450454 upstream. + +Commit 172b2386ed16 ("KVM: x86: fix missed hardware breakpoints", +2016-02-10) worked around a case where the debug registers are not loaded +correctly on preemption and on the first entry to KVM_RUN. + +However, Xiao Guangrong pointed out that the root cause must be that +KVM_DEBUGREG_BP_ENABLED is not being set correctly. This can indeed +happen due to the lazy debug exit mechanism, which does not call +kvm_update_dr7. Fix it by replacing the existing loop (more or less +equivalent to kvm_update_dr0123) with calls to all the kvm_update_dr* +functions. + +Fixes: 172b2386ed16a9143d9a456aae5ec87275c61489 +Reviewed-by: Xiao Guangrong +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kvm/x86.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -2736,7 +2736,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu + } + + kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu); +- vcpu->arch.switch_db_regs |= KVM_DEBUGREG_RELOAD; + } + + void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) +@@ -6545,12 +6544,12 @@ static int vcpu_enter_guest(struct kvm_v + * KVM_DEBUGREG_WONT_EXIT again. + */ + if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)) { +- int i; +- + WARN_ON(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP); + kvm_x86_ops->sync_dirty_debug_regs(vcpu); +- for (i = 0; i < KVM_NR_DB_REGS; i++) +- vcpu->arch.eff_db[i] = vcpu->arch.db[i]; ++ kvm_update_dr0123(vcpu); ++ kvm_update_dr6(vcpu); ++ kvm_update_dr7(vcpu); ++ vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_RELOAD; + } + + /* diff --git a/kernel/kernel/files/patches/mageia/stable-kvm-x86-update-tsc-multiplier-on-change.patch b/kernel/kernel/files/patches/mageia/stable-kvm-x86-update-tsc-multiplier-on-change.patch new file mode 100644 index 00000000..ea436218 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-kvm-x86-update-tsc-multiplier-on-change.patch @@ -0,0 +1,56 @@ +From 2680d6da455b636dd006636780c0f235c6561d70 Mon Sep 17 00:00:00 2001 +From: Owen Hofmann +Date: Tue, 1 Mar 2016 13:36:13 -0800 +Subject: kvm: x86: Update tsc multiplier on change. + +From: Owen Hofmann + +commit 2680d6da455b636dd006636780c0f235c6561d70 upstream. + +vmx.c writes the TSC_MULTIPLIER field in vmx_vcpu_load, but only when a +vcpu has migrated physical cpus. Record the last value written and +update in vmx_vcpu_load on any change, otherwise a cpu migration must +occur for TSC frequency scaling to take effect. + +Fixes: ff2c3a1803775cc72dc6f624b59554956396b0ee +Signed-off-by: Owen Hofmann +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kvm/vmx.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -595,6 +595,8 @@ struct vcpu_vmx { + /* Support for PML */ + #define PML_ENTITY_NUM 512 + struct page *pml_pg; ++ ++ u64 current_tsc_ratio; + }; + + enum segment_cache_field { +@@ -2062,14 +2064,16 @@ static void vmx_vcpu_load(struct kvm_vcp + rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp); + vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */ + +- /* Setup TSC multiplier */ +- if (cpu_has_vmx_tsc_scaling()) +- vmcs_write64(TSC_MULTIPLIER, +- vcpu->arch.tsc_scaling_ratio); +- + vmx->loaded_vmcs->cpu = cpu; + } + ++ /* Setup TSC multiplier */ ++ if (kvm_has_tsc_control && ++ vmx->current_tsc_ratio != vcpu->arch.tsc_scaling_ratio) { ++ vmx->current_tsc_ratio = vcpu->arch.tsc_scaling_ratio; ++ vmcs_write64(TSC_MULTIPLIER, vmx->current_tsc_ratio); ++ } ++ + vmx_vcpu_pi_load(vcpu, cpu); + } + diff --git a/kernel/kernel/files/patches/mageia/stable-mips-kvm-fix-ioctl-error-handling.patch b/kernel/kernel/files/patches/mageia/stable-mips-kvm-fix-ioctl-error-handling.patch new file mode 100644 index 00000000..aa79661b --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-mips-kvm-fix-ioctl-error-handling.patch @@ -0,0 +1,49 @@ +From 0178fd7dcc4451fcb90bec5e91226586962478d2 Mon Sep 17 00:00:00 2001 +From: "Michael S. Tsirkin" +Date: Sun, 28 Feb 2016 17:35:59 +0200 +Subject: mips/kvm: fix ioctl error handling + +From: Michael S. Tsirkin + +commit 0178fd7dcc4451fcb90bec5e91226586962478d2 upstream. + +Returning directly whatever copy_to_user(...) or copy_from_user(...) +returns may not do the right thing if there's a pagefault: +copy_to_user/copy_from_user return the number of bytes not copied in +this case, but ioctls need to return -EFAULT instead. + +Fix up kvm on mips to do + return copy_to_user(...)) ? -EFAULT : 0; +and + return copy_from_user(...)) ? -EFAULT : 0; + +everywhere. + +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman + +--- + arch/mips/kvm/mips.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/mips/kvm/mips.c ++++ b/arch/mips/kvm/mips.c +@@ -702,7 +702,7 @@ static int kvm_mips_get_reg(struct kvm_v + } else if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U128) { + void __user *uaddr = (void __user *)(long)reg->addr; + +- return copy_to_user(uaddr, vs, 16); ++ return copy_to_user(uaddr, vs, 16) ? -EFAULT : 0; + } else { + return -EINVAL; + } +@@ -732,7 +732,7 @@ static int kvm_mips_set_reg(struct kvm_v + } else if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U128) { + void __user *uaddr = (void __user *)(long)reg->addr; + +- return copy_from_user(vs, uaddr, 16); ++ return copy_from_user(vs, uaddr, 16) ? -EFAULT : 0; + } else { + return -EINVAL; + } diff --git a/kernel/kernel/files/patches/mageia/stable-parisc-fix-ptrace-syscall-number-and-return-value-modification.patch b/kernel/kernel/files/patches/mageia/stable-parisc-fix-ptrace-syscall-number-and-return-value-modification.patch new file mode 100644 index 00000000..ef7b3cca --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-parisc-fix-ptrace-syscall-number-and-return-value-modification.patch @@ -0,0 +1,94 @@ +From 98e8b6c9ac9d1b1e9d1122dfa6783d5d566bb8f7 Mon Sep 17 00:00:00 2001 +From: Helge Deller +Date: Tue, 19 Jan 2016 16:08:49 +0100 +Subject: parisc: Fix ptrace syscall number and return value modification + +From: Helge Deller + +commit 98e8b6c9ac9d1b1e9d1122dfa6783d5d566bb8f7 upstream. + +Mike Frysinger reported that his ptrace testcase showed strange +behaviour on parisc: It was not possible to avoid a syscall and the +return value of a syscall couldn't be changed. + +To modify a syscall number, we were missing to save the new syscall +number to gr20 which is then picked up later in assembly again. + +The effect that the return value couldn't be changed is a side-effect of +another bug in the assembly code. When a process is ptraced, userspace +expects each syscall to report entrance and exit of a syscall. If a +syscall number was given which doesn't exist, we jumped to the normal +syscall exit code instead of informing userspace that the (non-existant) +syscall exits. This unexpected behaviour confuses userspace and thus the +bug was misinterpreted as if we can't change the return value. + +This patch fixes both problems and was tested on 64bit kernel with +32bit userspace. + +Signed-off-by: Helge Deller +Cc: Mike Frysinger +Tested-by: Mike Frysinger +Signed-off-by: Greg Kroah-Hartman + +--- + arch/parisc/kernel/ptrace.c | 16 +++++++++++----- + arch/parisc/kernel/syscall.S | 5 ++++- + 2 files changed, 15 insertions(+), 6 deletions(-) + +--- a/arch/parisc/kernel/ptrace.c ++++ b/arch/parisc/kernel/ptrace.c +@@ -269,14 +269,19 @@ long compat_arch_ptrace(struct task_stru + + long do_syscall_trace_enter(struct pt_regs *regs) + { +- long ret = 0; +- + /* Do the secure computing check first. */ + secure_computing_strict(regs->gr[20]); + + if (test_thread_flag(TIF_SYSCALL_TRACE) && +- tracehook_report_syscall_entry(regs)) +- ret = -1L; ++ tracehook_report_syscall_entry(regs)) { ++ /* ++ * Tracing decided this syscall should not happen or the ++ * debugger stored an invalid system call number. Skip ++ * the system call and the system call restart handling. ++ */ ++ regs->gr[20] = -1UL; ++ goto out; ++ } + + #ifdef CONFIG_64BIT + if (!is_compat_task()) +@@ -290,7 +295,8 @@ long do_syscall_trace_enter(struct pt_re + regs->gr[24] & 0xffffffff, + regs->gr[23] & 0xffffffff); + +- return ret ? : regs->gr[20]; ++out: ++ return regs->gr[20]; + } + + void do_syscall_trace_exit(struct pt_regs *regs) +--- a/arch/parisc/kernel/syscall.S ++++ b/arch/parisc/kernel/syscall.S +@@ -343,7 +343,7 @@ tracesys_next: + #endif + + comiclr,>>= __NR_Linux_syscalls, %r20, %r0 +- b,n .Lsyscall_nosys ++ b,n .Ltracesys_nosys + + LDREGX %r20(%r19), %r19 + +@@ -359,6 +359,9 @@ tracesys_next: + be 0(%sr7,%r19) + ldo R%tracesys_exit(%r2),%r2 + ++.Ltracesys_nosys: ++ ldo -ENOSYS(%r0),%r28 /* set errno */ ++ + /* Do *not* call this function on the gateway page, because it + makes a direct call to syscall_trace. */ + diff --git a/kernel/kernel/files/patches/mageia/stable-pci-keystone-fix-msi-code-that-retrieves-struct-pcie_port-pointer.patch b/kernel/kernel/files/patches/mageia/stable-pci-keystone-fix-msi-code-that-retrieves-struct-pcie_port-pointer.patch new file mode 100644 index 00000000..e598869f --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-pci-keystone-fix-msi-code-that-retrieves-struct-pcie_port-pointer.patch @@ -0,0 +1,78 @@ +From 79e3f4a853ed161cd4c06d84b50beebf961a47c6 Mon Sep 17 00:00:00 2001 +From: Murali Karicheri +Date: Mon, 29 Feb 2016 17:18:22 -0600 +Subject: PCI: keystone: Fix MSI code that retrieves struct pcie_port pointer + +From: Murali Karicheri + +commit 79e3f4a853ed161cd4c06d84b50beebf961a47c6 upstream. + +Commit cbce7900598c ("PCI: designware: Make driver arch-agnostic") changed +the host bridge sysdata pointer from the ARM pci_sys_data to the DesignWare +pcie_port structure, and changed pcie-designware.c to reflect that. But it +did not change the corresponding code in pci-keystone-dw.c, so it caused +crashes on Keystone: + + Unable to handle kernel NULL pointer dereference at virtual address 00000030 + pgd = c0003000 + [00000030] *pgd=80000800004003, *pmd=00000000 + Internal error: Oops: 206 [#1] PREEMPT SMP ARM + CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.4.2-00139-gb74f926 #2 + Hardware name: Keystone + PC is at ks_dw_pcie_msi_irq_unmask+0x24/0x58 + +Change pci-keystone-dw.c to expect sysdata to be the struct pcie_port +pointer. + +[bhelgaas: changelog] +Fixes: cbce7900598c ("PCI: designware: Make driver arch-agnostic") +Signed-off-by: Murali Karicheri +Signed-off-by: Bjorn Helgaas +CC: Zhou Wang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/pci/host/pci-keystone-dw.c | 11 +++-------- + 1 file changed, 3 insertions(+), 8 deletions(-) + +--- a/drivers/pci/host/pci-keystone-dw.c ++++ b/drivers/pci/host/pci-keystone-dw.c +@@ -58,11 +58,6 @@ + + #define to_keystone_pcie(x) container_of(x, struct keystone_pcie, pp) + +-static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) +-{ +- return sys->private_data; +-} +- + static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset, + u32 *bit_pos) + { +@@ -108,7 +103,7 @@ static void ks_dw_pcie_msi_irq_ack(struc + struct pcie_port *pp; + + msi = irq_data_get_msi_desc(d); +- pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi)); ++ pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi); + ks_pcie = to_keystone_pcie(pp); + offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); + update_reg_offset_bit_pos(offset, ®_offset, &bit_pos); +@@ -146,7 +141,7 @@ static void ks_dw_pcie_msi_irq_mask(stru + u32 offset; + + msi = irq_data_get_msi_desc(d); +- pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi)); ++ pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi); + ks_pcie = to_keystone_pcie(pp); + offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); + +@@ -167,7 +162,7 @@ static void ks_dw_pcie_msi_irq_unmask(st + u32 offset; + + msi = irq_data_get_msi_desc(d); +- pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi)); ++ pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi); + ks_pcie = to_keystone_pcie(pp); + offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); + diff --git a/kernel/kernel/files/patches/mageia/stable-use-d_seq-to-get-coherency-between-d_inode-and-d_flags.patch b/kernel/kernel/files/patches/mageia/stable-use-d_seq-to-get-coherency-between-d_inode-and-d_flags.patch new file mode 100644 index 00000000..b68d85b9 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-use-d_seq-to-get-coherency-between-d_inode-and-d_flags.patch @@ -0,0 +1,100 @@ +From a528aca7f359f4b0b1d72ae406097e491a5ba9ea Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Mon, 29 Feb 2016 12:12:46 -0500 +Subject: use ->d_seq to get coherency between ->d_inode and ->d_flags + +From: Al Viro + +commit a528aca7f359f4b0b1d72ae406097e491a5ba9ea upstream. + +Games with ordering and barriers are way too brittle. Just +bump ->d_seq before and after updating ->d_inode and ->d_flags +type bits, so that verifying ->d_seq would guarantee they are +coherent. + +Signed-off-by: Al Viro +Signed-off-by: Greg Kroah-Hartman + +--- + fs/dcache.c | 20 +++++--------------- + include/linux/dcache.h | 4 +--- + 2 files changed, 6 insertions(+), 18 deletions(-) + +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -269,9 +269,6 @@ static inline int dname_external(const s + return dentry->d_name.name != dentry->d_iname; + } + +-/* +- * Make sure other CPUs see the inode attached before the type is set. +- */ + static inline void __d_set_inode_and_type(struct dentry *dentry, + struct inode *inode, + unsigned type_flags) +@@ -279,28 +276,18 @@ static inline void __d_set_inode_and_typ + unsigned flags; + + dentry->d_inode = inode; +- smp_wmb(); + flags = READ_ONCE(dentry->d_flags); + flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU); + flags |= type_flags; + WRITE_ONCE(dentry->d_flags, flags); + } + +-/* +- * Ideally, we want to make sure that other CPUs see the flags cleared before +- * the inode is detached, but this is really a violation of RCU principles +- * since the ordering suggests we should always set inode before flags. +- * +- * We should instead replace or discard the entire dentry - but that sucks +- * performancewise on mass deletion/rename. +- */ + static inline void __d_clear_type_and_inode(struct dentry *dentry) + { + unsigned flags = READ_ONCE(dentry->d_flags); + + flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU); + WRITE_ONCE(dentry->d_flags, flags); +- smp_wmb(); + dentry->d_inode = NULL; + } + +@@ -370,9 +357,11 @@ static void dentry_unlink_inode(struct d + __releases(dentry->d_inode->i_lock) + { + struct inode *inode = dentry->d_inode; ++ ++ raw_write_seqcount_begin(&dentry->d_seq); + __d_clear_type_and_inode(dentry); + hlist_del_init(&dentry->d_u.d_alias); +- dentry_rcuwalk_invalidate(dentry); ++ raw_write_seqcount_end(&dentry->d_seq); + spin_unlock(&dentry->d_lock); + spin_unlock(&inode->i_lock); + if (!inode->i_nlink) +@@ -1757,8 +1746,9 @@ static void __d_instantiate(struct dentr + spin_lock(&dentry->d_lock); + if (inode) + hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry); ++ raw_write_seqcount_begin(&dentry->d_seq); + __d_set_inode_and_type(dentry, inode, add_flags); +- dentry_rcuwalk_invalidate(dentry); ++ raw_write_seqcount_end(&dentry->d_seq); + spin_unlock(&dentry->d_lock); + fsnotify_d_instantiate(dentry, inode); + } +--- a/include/linux/dcache.h ++++ b/include/linux/dcache.h +@@ -409,9 +409,7 @@ static inline bool d_mountpoint(const st + */ + static inline unsigned __d_entry_type(const struct dentry *dentry) + { +- unsigned type = READ_ONCE(dentry->d_flags); +- smp_rmb(); +- return type & DCACHE_ENTRY_TYPE; ++ return dentry->d_flags & DCACHE_ENTRY_TYPE; + } + + static inline bool d_is_miss(const struct dentry *dentry) diff --git a/kernel/kernel/files/patches/mageia/stable-vfio-fix-ioctl-error-handling.patch b/kernel/kernel/files/patches/mageia/stable-vfio-fix-ioctl-error-handling.patch new file mode 100644 index 00000000..9b803d1e --- /dev/null +++ b/kernel/kernel/files/patches/mageia/stable-vfio-fix-ioctl-error-handling.patch @@ -0,0 +1,116 @@ +From 8160c4e455820d5008a1116d2dca35f0363bb062 Mon Sep 17 00:00:00 2001 +From: "Michael S. Tsirkin" +Date: Sun, 28 Feb 2016 16:31:39 +0200 +Subject: vfio: fix ioctl error handling + +From: Michael S. Tsirkin + +commit 8160c4e455820d5008a1116d2dca35f0363bb062 upstream. + +Calling return copy_to_user(...) in an ioctl will not +do the right thing if there's a pagefault: +copy_to_user returns the number of bytes not copied +in this case. + +Fix up vfio to do + return copy_to_user(...)) ? + -EFAULT : 0; + +everywhere. + +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Alex Williamson +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/vfio/pci/vfio_pci.c | 9 ++++++--- + drivers/vfio/platform/vfio_platform_common.c | 9 ++++++--- + drivers/vfio/vfio_iommu_type1.c | 6 ++++-- + 3 files changed, 16 insertions(+), 8 deletions(-) + +--- a/drivers/vfio/pci/vfio_pci.c ++++ b/drivers/vfio/pci/vfio_pci.c +@@ -446,7 +446,8 @@ static long vfio_pci_ioctl(void *device_ + info.num_regions = VFIO_PCI_NUM_REGIONS; + info.num_irqs = VFIO_PCI_NUM_IRQS; + +- return copy_to_user((void __user *)arg, &info, minsz); ++ return copy_to_user((void __user *)arg, &info, minsz) ? ++ -EFAULT : 0; + + } else if (cmd == VFIO_DEVICE_GET_REGION_INFO) { + struct pci_dev *pdev = vdev->pdev; +@@ -520,7 +521,8 @@ static long vfio_pci_ioctl(void *device_ + return -EINVAL; + } + +- return copy_to_user((void __user *)arg, &info, minsz); ++ return copy_to_user((void __user *)arg, &info, minsz) ? ++ -EFAULT : 0; + + } else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) { + struct vfio_irq_info info; +@@ -555,7 +557,8 @@ static long vfio_pci_ioctl(void *device_ + else + info.flags |= VFIO_IRQ_INFO_NORESIZE; + +- return copy_to_user((void __user *)arg, &info, minsz); ++ return copy_to_user((void __user *)arg, &info, minsz) ? ++ -EFAULT : 0; + + } else if (cmd == VFIO_DEVICE_SET_IRQS) { + struct vfio_irq_set hdr; +--- a/drivers/vfio/platform/vfio_platform_common.c ++++ b/drivers/vfio/platform/vfio_platform_common.c +@@ -219,7 +219,8 @@ static long vfio_platform_ioctl(void *de + info.num_regions = vdev->num_regions; + info.num_irqs = vdev->num_irqs; + +- return copy_to_user((void __user *)arg, &info, minsz); ++ return copy_to_user((void __user *)arg, &info, minsz) ? ++ -EFAULT : 0; + + } else if (cmd == VFIO_DEVICE_GET_REGION_INFO) { + struct vfio_region_info info; +@@ -240,7 +241,8 @@ static long vfio_platform_ioctl(void *de + info.size = vdev->regions[info.index].size; + info.flags = vdev->regions[info.index].flags; + +- return copy_to_user((void __user *)arg, &info, minsz); ++ return copy_to_user((void __user *)arg, &info, minsz) ? ++ -EFAULT : 0; + + } else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) { + struct vfio_irq_info info; +@@ -259,7 +261,8 @@ static long vfio_platform_ioctl(void *de + info.flags = vdev->irqs[info.index].flags; + info.count = vdev->irqs[info.index].count; + +- return copy_to_user((void __user *)arg, &info, minsz); ++ return copy_to_user((void __user *)arg, &info, minsz) ? ++ -EFAULT : 0; + + } else if (cmd == VFIO_DEVICE_SET_IRQS) { + struct vfio_irq_set hdr; +--- a/drivers/vfio/vfio_iommu_type1.c ++++ b/drivers/vfio/vfio_iommu_type1.c +@@ -999,7 +999,8 @@ static long vfio_iommu_type1_ioctl(void + + info.iova_pgsizes = vfio_pgsize_bitmap(iommu); + +- return copy_to_user((void __user *)arg, &info, minsz); ++ return copy_to_user((void __user *)arg, &info, minsz) ? ++ -EFAULT : 0; + + } else if (cmd == VFIO_IOMMU_MAP_DMA) { + struct vfio_iommu_type1_dma_map map; +@@ -1032,7 +1033,8 @@ static long vfio_iommu_type1_ioctl(void + if (ret) + return ret; + +- return copy_to_user((void __user *)arg, &unmap, minsz); ++ return copy_to_user((void __user *)arg, &unmap, minsz) ? ++ -EFAULT : 0; + } + + return -ENOTTY; diff --git a/kernel/kernel/pspec.xml b/kernel/kernel/pspec.xml index 1d4be546..206e09f8 100644 --- a/kernel/kernel/pspec.xml +++ b/kernel/kernel/pspec.xml @@ -28,10 +28,35 @@ - patches/linux/patch-4.4.2.xz - + patches/linux/patch-4.4.4.xz + + patches/mageia/stable-use-d_seq-to-get-coherency-between-d_inode-and-d_flags.patch + patches/mageia/stable-drivers-sh-restore-legacy-clock-domain-on-superh-platforms.patch + patches/mageia/stable-btrfs-fix-deadlock-running-delayed-iputs-at-transaction-commit-time.patch + patches/mageia/stable-btrfs-fix-no_space-in-write-and-rm-loop.patch + patches/mageia/stable-btrfs-async-thread-fix-a-use-after-free-error-for-trace.patch + patches/mageia/stable-drm-amdgpu-mask-out-wc-from-bo-on-unsupported-arches.patch + patches/mageia/stable-block-initialize-max_dev_sectors-to-0.patch + patches/mageia/stable-pci-keystone-fix-msi-code-that-retrieves-struct-pcie_port-pointer.patch + patches/mageia/stable-parisc-fix-ptrace-syscall-number-and-return-value-modification.patch + patches/mageia/stable-mips-kvm-fix-ioctl-error-handling.patch + patches/mageia/stable-kvm-x86-update-tsc-multiplier-on-change.patch + patches/mageia/stable-fbcon-set-a-default-value-to-blink-interval.patch + patches/mageia/stable-cifs-fix-out-of-bounds-access-in-lease-parsing.patch + patches/mageia/stable-cifs-fix-smb2-interim-response-processing-for-read-requests.patch + patches/mageia/stable-fix-cifs_uniqueid_to_ino_t-function-for-s390x.patch + patches/mageia/stable-vfio-fix-ioctl-error-handling.patch + patches/mageia/stable-kvm-x86-fix-root-cause-for-missed-hardware-breakpoints.patch + patches/mageia/stable-arm-arm64-kvm-fix-ioctl-error-handling.patch + patches/mageia/stable-iommu-amd-apply-workaround-for-ats-write-permission-check.patch + patches/mageia/stable-iommu-amd-fix-boot-warning-when-device-00-00.0-is-not-iommu-covered.patch + patches/mageia/stable-iommu-vt-d-use-bus_notify_removed_device-in-hotplug-path.patch + patches/mageia/ata-Adding-Intel-Lewisburg-device-IDs-for-SATA.patch + patches/mageia/ata-ahci-don-t-mark-HotPlugCapable-Ports-as-external.patch + patches/mageia/libata-Align-ata_device-s-id-on-a-cacheline.patch + patches/mageia/libata-fix-HDIO_GET_32BIT-ioctl.patch patches/mageia/x86-pci-toshiba-equium-a60-assign-busses.patch patches/mageia/x86-boot-video-80x25-if-break.patch patches/mageia/x86-default_poweroff_up_machines.patch @@ -59,13 +84,7 @@ patches/mageia/block-Make-CFQ-default-to-IOPS-mode-on-SSDs.patch patches/mageia/fs-aufs-4.4.patch patches/mageia/fs-aufs-4.4-modular.patch - patches/mageia/fs-ovl-allow-zero-size-xattr.patch - patches/mageia/fs-ovl-use-a-minimal-buffer-in-ovl_copy_xattr.patch patches/mageia/fs-ovl-move-super-block-magic-number-to-magic.h.patch - patches/mageia/fs-ovl-root-copy-attr.patch - patches/mageia/fs-ovl-setattr-check-permissions-before-copy-up.patch - patches/mageia/fs-ovl-check-dentry-positiveness-in-ovl_cleanup_whiteou.patch - patches/mageia/fs-xfs-Revert-xfs-clear-PF_NOFREEZE-for-xfsaild-kthread.patch patches/mageia/firewire-ieee1394-module-aliases.patch patches/mageia/char-agp-intel-new-Q57-id.patch patches/mageia/gpu-drm-mach64.patch @@ -103,11 +122,6 @@ patches/mageia/gpu-drm-0109-drm-vc4-Add-an-interface-for-capturing-the-GPU-state.patch patches/mageia/gpu-drm-radeon-Update-radeon_get_vblank_counter_kms.patch patches/mageia/gpu-drm-radeon-Drop-unnecessary-unsigned-int-0-check.patch - patches/mageia/gpu-drm-No-Op-redundant-calls-to-drm_vblank_off-v2.patch - patches/mageia/gpu-drm-Prevent-vblank-counter-bumps-1-with-active-vblank-clients-v2.patch - patches/mageia/gpu-drm-Fix-drm_vblank_pre_post_modeset-regression-from-Linux-4.4.patch - patches/mageia/gpu-drm-Fix-treatment-of-drm_vblank_offdelay-in-drm_vblank_on-v2.patch - patches/mageia/gpu-drm_nouveau_display-Enable-vblank-irqs-after-display-engine-is-on-again.patch patches/mageia/input-i8042-quirks-for-Fujitsu-Lifebook-A544-and-Lif.patch patches/mageia/net-sis190-fix-list-usage.patch patches/mageia/net-netfilter-IFWLOG.patch @@ -224,9 +238,9 @@ - 2016-02-18 - 4.4.2 - Version bump to 4.4.2 https://www.kernel.org/pub/linux/kernel/v4.x/ChangeLog-4.4.2 + 2016-03-06 + 4.4.4 + Version bump to 4.4.4 https://www.kernel.org/pub/linux/kernel/v4.x/ChangeLog-4.4.4 security systemRestart