From: Arkadiusz Miƛkiewicz Date: Thu, 14 Aug 2014 09:39:10 +0000 (+0200) Subject: - up to 3.16.1 (builds on x86_64; not tested runtime) X-Git-Tag: auto/th/kernel-3.16.1-1~1 X-Git-Url: http://git.pld-linux.org/gitweb.cgi?a=commitdiff_plain;h=076b876ecc3a67cef4a0595132374ac1bea1d0be;p=packages%2Fkernel.git - up to 3.16.1 (builds on x86_64; not tested runtime) --- diff --git a/kernel-aufs3.patch b/kernel-aufs3.patch index 0a5f5a3e..2edef241 100644 --- a/kernel-aufs3.patch +++ b/kernel-aufs3.patch @@ -1,4 +1,4 @@ -aufs3.15 kbuild patch +aufs3.16 kbuild patch diff --git a/fs/Kconfig b/fs/Kconfig index 312393f..78632ed 100644 @@ -13,16 +13,16 @@ index 312393f..78632ed 100644 endif # MISC_FILESYSTEMS diff --git a/fs/Makefile b/fs/Makefile -index f9cb987..a0c580f 100644 +index 4030cbf..5bd169a 100644 --- a/fs/Makefile +++ b/fs/Makefile -@@ -126,3 +126,4 @@ obj-y += exofs/ # Multiple modules +@@ -125,3 +125,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/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild -index 6929571..351ca48 100644 +index 24e9033..fe9a8d4 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -56,6 +56,7 @@ header-y += atmppp.h @@ -33,10 +33,10 @@ index 6929571..351ca48 100644 header-y += auto_fs.h header-y += auto_fs4.h header-y += auxvec.h -aufs3.15 base patch +aufs3.16 base patch diff --git a/drivers/block/loop.c b/drivers/block/loop.c -index f70a230..138104b 100644 +index 6cb1beb..30efd68 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -692,6 +692,24 @@ static inline int is_loop_device(struct file *file) @@ -65,7 +65,7 @@ index f70a230..138104b 100644 static ssize_t loop_attr_show(struct device *dev, char *page, diff --git a/fs/inode.c b/fs/inode.c -index f96d2a6..2d72083 100644 +index 6eecb7f..b225c0f 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1496,7 +1496,7 @@ static int relatime_need_update(struct vfsmount *mnt, struct inode *inode, @@ -78,10 +78,10 @@ index f96d2a6..2d72083 100644 if (inode->i_op->update_time) return inode->i_op->update_time(inode, time, flags); diff --git a/fs/splice.c b/fs/splice.c -index e246954..4797013 100644 +index f5cb9ba..9ba380c 100644 --- a/fs/splice.c +++ b/fs/splice.c -@@ -1103,8 +1103,8 @@ EXPORT_SYMBOL(generic_splice_sendpage); +@@ -1114,8 +1114,8 @@ EXPORT_SYMBOL(generic_splice_sendpage); /* * Attempt to initiate a splice from pipe to file. */ @@ -92,7 +92,7 @@ index e246954..4797013 100644 { ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); -@@ -1120,9 +1120,9 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, +@@ -1131,9 +1131,9 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, /* * Attempt to initiate a splice from a file to a pipe. */ @@ -106,10 +106,10 @@ index e246954..4797013 100644 ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); diff --git a/include/linux/fs.h b/include/linux/fs.h -index 8780312..3ff3e89 100644 +index e11d60c..2f32b35 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h -@@ -2606,6 +2606,7 @@ extern int inode_change_ok(const struct inode *, struct iattr *); +@@ -2618,6 +2618,7 @@ extern int inode_change_ok(const struct inode *, struct iattr *); extern int inode_newsize_ok(const struct inode *, loff_t offset); extern void setattr_copy(struct inode *inode, const struct iattr *attr); @@ -118,10 +118,10 @@ index 8780312..3ff3e89 100644 extern int generic_show_options(struct seq_file *m, struct dentry *root); diff --git a/include/linux/splice.h b/include/linux/splice.h -index 0e43906..304169e 100644 +index da2751d..2e0fca6 100644 --- a/include/linux/splice.h +++ b/include/linux/splice.h -@@ -93,4 +93,10 @@ extern void splice_shrink_spd(struct splice_pipe_desc *); +@@ -83,4 +83,10 @@ extern void splice_shrink_spd(struct splice_pipe_desc *); extern void spd_release_page(struct splice_pipe_desc *, unsigned int); extern const struct pipe_buf_operations page_cache_pipe_buf_ops; @@ -132,13 +132,13 @@ index 0e43906..304169e 100644 + struct pipe_inode_info *pipe, size_t len, + unsigned int flags); #endif -aufs3.15 mmap patch +aufs3.16 mmap patch diff --git a/fs/buffer.c b/fs/buffer.c -index 9ddb9fc..1059a0b 100644 +index eba6e4f..31f0b2d 100644 --- a/fs/buffer.c +++ b/fs/buffer.c -@@ -2448,7 +2448,7 @@ int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, +@@ -2460,7 +2460,7 @@ int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, * Update file times before taking page lock. We may end up failing the * fault so this update may be superfluous but who really cares... */ @@ -148,162 +148,97 @@ index 9ddb9fc..1059a0b 100644 ret = __block_page_mkwrite(vma, vmf, get_block); sb_end_pagefault(sb); diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c -index d4a3574..e44a744 100644 +index d4a3574..1397181 100644 --- a/fs/proc/nommu.c +++ b/fs/proc/nommu.c -@@ -45,7 +45,9 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region) +@@ -45,7 +45,10 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region) file = region->vm_file; if (file) { - struct inode *inode = file_inode(region->vm_file); + struct inode *inode; ++ + file = vmr_pr_or_file(region); + inode = file_inode(file); dev = inode->i_sb->s_dev; ino = inode->i_ino; } diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c -index c4b2646..dc3c0dc 100644 +index cfa63ee..bf4919e 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c -@@ -265,7 +265,9 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) +@@ -265,7 +265,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) const char *name = NULL; if (file) { - struct inode *inode = file_inode(vma->vm_file); + struct inode *inode; ++ + file = vma_pr_or_file(vma); + inode = file_inode(file); dev = inode->i_sb->s_dev; ino = inode->i_ino; pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT; -@@ -1408,6 +1410,7 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid) - seq_printf(m, "%08lx %s", vma->vm_start, buffer); - - if (file) { -+ file = vma_pr_or_file(vma); - seq_printf(m, " file="); - seq_path(m, &file->f_path, "\n\t= "); - } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) { +@@ -1390,7 +1393,7 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid) + struct proc_maps_private *proc_priv = &numa_priv->proc_maps; + struct vm_area_struct *vma = v; + struct numa_maps *md = &numa_priv->md; +- struct file *file = vma->vm_file; ++ struct file *file = vma_pr_or_file(vma); + struct task_struct *task = proc_priv->task; + struct mm_struct *mm = vma->vm_mm; + struct mm_walk walk = {}; diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c -index 678455d..ad0ce45 100644 +index 678455d..0ef7ef4 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c -@@ -141,7 +141,9 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma, +@@ -141,7 +141,10 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma, file = vma->vm_file; if (file) { - struct inode *inode = file_inode(vma->vm_file); + struct inode *inode; ++ + file = vma_pr_or_file(file); + inode = file_inode(file); dev = inode->i_sb->s_dev; ino = inode->i_ino; pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT; diff --git a/include/linux/mm.h b/include/linux/mm.h -index d677706..192e7ac4 100644 +index e03dd29..dd32624 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h -@@ -18,6 +18,9 @@ - #include - #include - #include -+#include -+#include -+#include - - struct mempolicy; - struct anon_vma; -@@ -1173,6 +1176,87 @@ static inline int fixup_user_fault(struct task_struct *tsk, +@@ -1184,6 +1184,28 @@ static inline int fixup_user_fault(struct task_struct *tsk, } #endif -+/* -+ * Mainly for aufs which mmap(2) diffrent file and wants to print different path -+ * in /proc/PID/maps. -+ */ -+/* #define AUFS_DEBUG_MMAP */ -+static inline void aufs_trace(struct file *f, struct file *pr, -+ const char func[], int line, const char func2[]) -+{ -+#ifdef AUFS_DEBUG_MMAP -+ if (pr) -+ pr_info("%s:%d: %s, %p\n", func, line, func2, -+ f ? (char *)f->f_dentry->d_name.name : "(null)"); -+#endif -+} -+ -+static inline struct file *vmr_do_pr_or_file(struct vm_region *region, -+ const char func[], int line) -+{ -+ struct file *f = region->vm_file, *pr = region->vm_prfile; -+ aufs_trace(f, pr, func, line, __func__); -+ return (f && pr) ? pr : f; -+} -+ -+static inline void vmr_do_fput(struct vm_region *region, -+ const char func[], int line) -+{ -+ struct file *f = region->vm_file, *pr = region->vm_prfile; -+ aufs_trace(f, pr, func, line, __func__); -+ fput(f); -+ if (f && pr) -+ fput(pr); -+} -+ -+static inline void vma_do_file_update_time(struct vm_area_struct *vma, -+ const char func[], int line) -+{ -+ struct file *f = vma->vm_file, *pr = vma->vm_prfile; -+ aufs_trace(f, pr, func, line, __func__); -+ file_update_time(f); -+ if (f && pr) -+ file_update_time(pr); -+} -+ -+static inline struct file *vma_do_pr_or_file(struct vm_area_struct *vma, -+ const char func[], int line) -+{ -+ struct file *f = vma->vm_file, *pr = vma->vm_prfile; -+ aufs_trace(f, pr, func, line, __func__); -+ return (f && pr) ? pr : f; -+} -+ -+static inline void vma_do_get_file(struct vm_area_struct *vma, -+ const char func[], int line) -+{ -+ struct file *f = vma->vm_file, *pr = vma->vm_prfile; -+ aufs_trace(f, pr, func, line, __func__); -+ get_file(f); -+ if (f && pr) -+ get_file(pr); -+} -+ -+static inline void vma_do_fput(struct vm_area_struct *vma, -+ const char func[], int line) -+{ -+ struct file *f = vma->vm_file, *pr = vma->vm_prfile; -+ aufs_trace(f, pr, func, line, __func__); -+ fput(f); -+ if (f && pr) -+ fput(pr); -+} ++#ifdef CONFIG_MMU ++extern void vma_do_file_update_time(struct vm_area_struct *, const char[], int); ++extern struct file *vma_do_pr_or_file(struct vm_area_struct *, const char[], ++ int); ++extern void vma_do_get_file(struct vm_area_struct *, const char[], int); ++extern void vma_do_fput(struct vm_area_struct *, const char[], int); + -+#define vmr_pr_or_file(region) vmr_do_pr_or_file(region, __func__, \ -+ __LINE__) -+#define vmr_fput(region) vmr_do_fput(region, __func__, __LINE__) +#define vma_file_update_time(vma) vma_do_file_update_time(vma, __func__, \ + __LINE__) +#define vma_pr_or_file(vma) vma_do_pr_or_file(vma, __func__, \ + __LINE__) +#define vma_get_file(vma) vma_do_get_file(vma, __func__, __LINE__) +#define vma_fput(vma) vma_do_fput(vma, __func__, __LINE__) ++#else ++extern struct file *vmr_do_pr_or_file(struct vm_region *, const char[], int); ++extern void vmr_do_fput(struct vm_region *, const char[], int); ++ ++#define vmr_pr_or_file(region) vmr_do_pr_or_file(region, __func__, \ ++ __LINE__) ++#define vmr_fput(region) vmr_do_fput(region, __func__, __LINE__) ++#endif /* CONFIG_MMU */ + 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 8967e20..a57b589 100644 +index 96c5750..a087ecd 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -232,6 +232,7 @@ struct vm_region { @@ -323,7 +258,7 @@ index 8967e20..a57b589 100644 #ifndef CONFIG_MMU diff --git a/kernel/fork.c b/kernel/fork.c -index 54a8d26..dcf08b6 100644 +index 6a13c46..714302c 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -416,7 +416,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) @@ -335,11 +270,24 @@ index 54a8d26..dcf08b6 100644 if (tmp->vm_flags & VM_DENYWRITE) atomic_dec(&inode->i_writecount); mutex_lock(&mapping->i_mmap_mutex); +diff --git a/mm/Makefile b/mm/Makefile +index 4064f3e..0003fdf 100644 +--- a/mm/Makefile ++++ b/mm/Makefile +@@ -18,7 +18,7 @@ obj-y := filemap.o mempool.o oom_kill.o fadvise.o \ + mm_init.o mmu_context.o percpu.o slab_common.o \ + compaction.o balloon_compaction.o vmacache.o \ + interval_tree.o list_lru.o workingset.o \ +- iov_iter.o $(mmu-y) ++ iov_iter.o prfile.o $(mmu-y) + + obj-y += init-mm.o + diff --git a/mm/filemap.c b/mm/filemap.c -index 088358c..138a88c 100644 +index 900edfa..f4dda0c 100644 --- a/mm/filemap.c +++ b/mm/filemap.c -@@ -2091,7 +2091,7 @@ int filemap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) +@@ -2040,7 +2040,7 @@ int filemap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) int ret = VM_FAULT_LOCKED; sb_start_pagefault(inode->i_sb); @@ -349,10 +297,10 @@ index 088358c..138a88c 100644 if (page->mapping != inode->i_mapping) { unlock_page(page); diff --git a/mm/fremap.c b/mm/fremap.c -index 34feba6..8d6c451 100644 +index 72b8fa3..a00bbf0 100644 --- a/mm/fremap.c +++ b/mm/fremap.c -@@ -223,16 +223,27 @@ get_write_lock: +@@ -224,16 +224,28 @@ get_write_lock: */ if (mapping_cap_account_dirty(mapping)) { unsigned long addr; @@ -373,6 +321,7 @@ index 34feba6..8d6c451 100644 BUG_ON(addr != start); + if (prfile) { + struct vm_area_struct *new_vma; ++ + new_vma = find_vma(mm, addr); + if (!new_vma->vm_prfile) + new_vma->vm_prfile = prfile; @@ -402,10 +351,10 @@ index a402f8f..134e15d 100644 return error; } diff --git a/mm/memory.c b/mm/memory.c -index 037b812..6e7d241 100644 +index 8b44f76..69a72bf 100644 --- a/mm/memory.c +++ b/mm/memory.c -@@ -2805,7 +2805,7 @@ reuse: +@@ -2161,7 +2161,7 @@ reuse: set_page_dirty_balance(dirty_page); /* file_update_time outside page_lock */ if (vma->vm_file) @@ -415,10 +364,10 @@ index 037b812..6e7d241 100644 put_page(dirty_page); if (page_mkwrite) { diff --git a/mm/mmap.c b/mm/mmap.c -index b1202cf..40dd067 100644 +index 129b847..869d1d7 100644 --- a/mm/mmap.c +++ b/mm/mmap.c -@@ -250,7 +250,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma) +@@ -253,7 +253,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma) if (vma->vm_ops && vma->vm_ops->close) vma->vm_ops->close(vma); if (vma->vm_file) @@ -427,7 +376,7 @@ index b1202cf..40dd067 100644 mpol_put(vma_policy(vma)); kmem_cache_free(vm_area_cachep, vma); return next; -@@ -861,7 +861,7 @@ again: remove_next = 1 + (end > next->vm_end); +@@ -863,7 +863,7 @@ again: remove_next = 1 + (end > next->vm_end); if (remove_next) { if (file) { uprobe_munmap(next, next->vm_start, next->vm_end); @@ -436,7 +385,7 @@ index b1202cf..40dd067 100644 } if (next->anon_vma) anon_vma_merge(vma, next); -@@ -1641,8 +1641,8 @@ out: +@@ -1643,8 +1643,8 @@ out: unmap_and_free_vma: if (vm_flags & VM_DENYWRITE) allow_write_access(file); @@ -446,7 +395,7 @@ index b1202cf..40dd067 100644 /* Undo any partial mapping done by a device driver. */ unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end); -@@ -2432,7 +2432,7 @@ static int __split_vma(struct mm_struct * mm, struct vm_area_struct * vma, +@@ -2434,7 +2434,7 @@ static int __split_vma(struct mm_struct * mm, struct vm_area_struct * vma, goto out_free_mpol; if (new->vm_file) @@ -455,7 +404,7 @@ index b1202cf..40dd067 100644 if (new->vm_ops && new->vm_ops->open) new->vm_ops->open(new); -@@ -2451,7 +2451,7 @@ static int __split_vma(struct mm_struct * mm, struct vm_area_struct * vma, +@@ -2453,7 +2453,7 @@ static int __split_vma(struct mm_struct * mm, struct vm_area_struct * vma, if (new->vm_ops && new->vm_ops->close) new->vm_ops->close(new); if (new->vm_file) @@ -464,7 +413,7 @@ index b1202cf..40dd067 100644 unlink_anon_vmas(new); out_free_mpol: mpol_put(vma_policy(new)); -@@ -2840,7 +2840,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, +@@ -2842,7 +2842,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, if (anon_vma_clone(new_vma, vma)) goto out_free_mempol; if (new_vma->vm_file) @@ -474,27 +423,30 @@ index b1202cf..40dd067 100644 new_vma->vm_ops->open(new_vma); vma_link(mm, new_vma, prev, rb_link, rb_parent); diff --git a/mm/msync.c b/mm/msync.c -index 632df45..02d770e 100644 +index 992a167..ce1915b 100644 --- a/mm/msync.c +++ b/mm/msync.c -@@ -80,10 +80,10 @@ SYSCALL_DEFINE3(msync, unsigned long, start, size_t, len, int, flags) +@@ -84,13 +84,13 @@ SYSCALL_DEFINE3(msync, unsigned long, start, size_t, len, int, flags) start = vma->vm_end; if ((flags & MS_SYNC) && file && (vma->vm_flags & VM_SHARED)) { - get_file(file); + vma_get_file(vma); up_read(&mm->mmap_sem); - error = vfs_fsync(file, 0); + if (vma->vm_flags & VM_NONLINEAR) + error = vfs_fsync(file, 1); + else + error = vfs_fsync_range(file, fstart, fend, 1); - fput(file); + vma_fput(vma); if (error || start >= end) goto out; down_read(&mm->mmap_sem); diff --git a/mm/nommu.c b/mm/nommu.c -index 85f8d66..9f471fa 100644 +index 4a852f6..b369644 100644 --- a/mm/nommu.c +++ b/mm/nommu.c -@@ -655,7 +655,7 @@ static void __put_nommu_region(struct vm_region *region) +@@ -658,7 +658,7 @@ static void __put_nommu_region(struct vm_region *region) up_write(&nommu_region_sem); if (region->vm_file) @@ -503,7 +455,7 @@ index 85f8d66..9f471fa 100644 /* IO memory and memory shared directly out of the pagecache * from ramfs/tmpfs mustn't be released here */ -@@ -820,7 +820,7 @@ static void delete_vma(struct mm_struct *mm, struct vm_area_struct *vma) +@@ -823,7 +823,7 @@ static void delete_vma(struct mm_struct *mm, struct vm_area_struct *vma) if (vma->vm_ops && vma->vm_ops->close) vma->vm_ops->close(vma); if (vma->vm_file) @@ -512,7 +464,7 @@ index 85f8d66..9f471fa 100644 put_nommu_region(vma->vm_region); kmem_cache_free(vm_area_cachep, vma); } -@@ -1382,7 +1382,7 @@ unsigned long do_mmap_pgoff(struct file *file, +@@ -1385,7 +1385,7 @@ unsigned long do_mmap_pgoff(struct file *file, goto error_just_free; } } @@ -521,7 +473,7 @@ index 85f8d66..9f471fa 100644 kmem_cache_free(vm_region_jar, region); region = pregion; result = start; -@@ -1458,10 +1458,10 @@ error_just_free: +@@ -1461,10 +1461,10 @@ error_just_free: up_write(&nommu_region_sem); error: if (region->vm_file) @@ -534,10 +486,102 @@ index 85f8d66..9f471fa 100644 kmem_cache_free(vm_area_cachep, vma); kleave(" = %d", ret); return ret; -aufs3.15 standalone patch +diff --git a/mm/prfile.c b/mm/prfile.c +new file mode 100644 +index 0000000..fc708d2 +--- /dev/null ++++ b/mm/prfile.c +@@ -0,0 +1,86 @@ ++/* ++ * Mainly for aufs which mmap(2) diffrent file and wants to print different path ++ * in /proc/PID/maps. ++ * Call these functions via macros defined in linux/mm.h. ++ * ++ * See Documentation/filesystems/aufs/design/06mmap.txt ++ * ++ * Copyright (c) 2014 Junjro R. Okajima ++ * Copyright (c) 2014 Ian Campbell ++ */ ++ ++#include ++#include ++#include ++ ++/* #define PRFILE_TRACE */ ++static inline void prfile_trace(struct file *f, struct file *pr, ++ const char func[], int line, const char func2[]) ++{ ++#ifdef PRFILE_TRACE ++ if (pr) ++ pr_info("%s:%d: %s, %p\n", func, line, func2, ++ f ? (char *)f->f_dentry->d_name.name : "(null)"); ++#endif ++} ++ ++#ifdef CONFIG_MMU ++void vma_do_file_update_time(struct vm_area_struct *vma, const char func[], ++ int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ file_update_time(f); ++ if (f && pr) ++ file_update_time(pr); ++} ++ ++struct file *vma_do_pr_or_file(struct vm_area_struct *vma, const char func[], ++ int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ return (f && pr) ? pr : f; ++} ++ ++void vma_do_get_file(struct vm_area_struct *vma, const char func[], int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ get_file(f); ++ if (f && pr) ++ get_file(pr); ++} ++ ++void vma_do_fput(struct vm_area_struct *vma, const char func[], int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ fput(f); ++ if (f && pr) ++ fput(pr); ++} ++#else ++struct file *vmr_do_pr_or_file(struct vm_region *region, const char func[], ++ int line) ++{ ++ struct file *f = region->vm_file, *pr = region->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ return (f && pr) ? pr : f; ++} ++ ++void vmr_do_fput(struct vm_region *region, const char func[], int line) ++{ ++ struct file *f = region->vm_file, *pr = region->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ fput(f); ++ if (f && pr) ++ fput(pr); ++} ++#endif /* CONFIG_MMU */ +aufs3.16 standalone patch diff --git a/fs/inode.c b/fs/inode.c -index 2d72083..30b69da 100644 +index b225c0f..73259c8 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -57,6 +57,7 @@ static struct hlist_head *inode_hashtable __read_mostly; @@ -613,7 +657,7 @@ index ad19959..adf290d 100644 int fsnotify_fasync(int fd, struct file *file, int on) { diff --git a/fs/notify/mark.c b/fs/notify/mark.c -index 923fe4a..176b435 100644 +index d90deaa..60b4239 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -109,6 +109,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) @@ -649,7 +693,7 @@ index 923fe4a..176b435 100644 static int fsnotify_mark_destroy(void *ignored) { diff --git a/fs/open.c b/fs/open.c -index 9d64679..1aa876a 100644 +index d6fd3ac..5e99d8b 100644 --- a/fs/open.c +++ b/fs/open.c @@ -62,6 +62,7 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, @@ -660,7 +704,7 @@ index 9d64679..1aa876a 100644 long vfs_truncate(struct path *path, loff_t length) { -@@ -299,6 +300,7 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) +@@ -298,6 +299,7 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) sb_end_write(inode->i_sb); return ret; } @@ -669,10 +713,10 @@ index 9d64679..1aa876a 100644 SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len) { diff --git a/fs/splice.c b/fs/splice.c -index 4797013..44b603a 100644 +index 9ba380c..3419932 100644 --- a/fs/splice.c +++ b/fs/splice.c -@@ -1116,6 +1116,7 @@ long do_splice_from(struct pipe_inode_info *pipe, struct file *out, +@@ -1127,6 +1127,7 @@ long do_splice_from(struct pipe_inode_info *pipe, struct file *out, return splice_write(pipe, out, ppos, len, flags); } @@ -680,7 +724,7 @@ index 4797013..44b603a 100644 /* * Attempt to initiate a splice from a file to a pipe. -@@ -1142,6 +1143,7 @@ long do_splice_to(struct file *in, loff_t *ppos, +@@ -1153,6 +1154,7 @@ long do_splice_to(struct file *in, loff_t *ppos, return splice_read(in, ppos, pipe, len, flags); } @@ -705,7 +749,7 @@ index b9d613e..ba3b618 100644 } +EXPORT_SYMBOL(cap_mmap_file); diff --git a/security/device_cgroup.c b/security/device_cgroup.c -index 9134dbf..4d4217a 100644 +index d9d69e6..3f6f471 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -7,6 +7,7 @@ @@ -716,7 +760,7 @@ index 9134dbf..4d4217a 100644 #include #include #include -@@ -856,6 +857,7 @@ int __devcgroup_inode_permission(struct inode *inode, int mask) +@@ -849,6 +850,7 @@ int __devcgroup_inode_permission(struct inode *inode, int mask) return __devcgroup_check_permission(type, imajor(inode), iminor(inode), access); } @@ -725,7 +769,7 @@ index 9134dbf..4d4217a 100644 int devcgroup_inode_mknod(int mode, dev_t dev) { diff --git a/security/security.c b/security/security.c -index 8b774f3..e3190b9 100644 +index 31614e9..b223a66 100644 --- a/security/security.c +++ b/security/security.c @@ -407,6 +407,7 @@ int security_path_rmdir(struct path *dir, struct dentry *dentry) @@ -810,7 +854,7 @@ index 8b774f3..e3190b9 100644 { diff -urN /usr/share/empty/Documentation/ABI/testing/debugfs-aufs linux/Documentation/ABI/testing/debugfs-aufs --- /usr/share/empty/Documentation/ABI/testing/debugfs-aufs 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/ABI/testing/debugfs-aufs 2014-06-24 00:14:06.769385243 +0200 ++++ linux/Documentation/ABI/testing/debugfs-aufs 2014-01-30 21:10:02.794146538 +0100 @@ -0,0 +1,50 @@ +What: /debug/aufs/si_/ +Date: March 2009 @@ -864,7 +908,7 @@ diff -urN /usr/share/empty/Documentation/ABI/testing/debugfs-aufs linux/Document + will be empty. About XINO files, see the aufs manual. diff -urN /usr/share/empty/Documentation/ABI/testing/sysfs-aufs linux/Documentation/ABI/testing/sysfs-aufs --- /usr/share/empty/Documentation/ABI/testing/sysfs-aufs 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/ABI/testing/sysfs-aufs 2014-06-24 00:14:06.769385243 +0200 ++++ linux/Documentation/ABI/testing/sysfs-aufs 2014-01-30 21:10:02.794146538 +0100 @@ -0,0 +1,31 @@ +What: /sys/fs/aufs/si_/ +Date: March 2009 @@ -899,7 +943,7 @@ diff -urN /usr/share/empty/Documentation/ABI/testing/sysfs-aufs linux/Documentat + will be empty. About XINO files, see the aufs manual. diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/01intro.txt linux/Documentation/filesystems/aufs/design/01intro.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/01intro.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/01intro.txt 2014-06-24 00:14:06.772718759 +0200 ++++ linux/Documentation/filesystems/aufs/design/01intro.txt 2014-01-30 21:10:02.807480310 +0100 @@ -0,0 +1,161 @@ + +# Copyright (C) 2005-2014 Junjiro R. Okajima @@ -1064,8 +1108,8 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/01intro.txt lin +about it. But currently I have implemented it in kernel space. diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/02struct.txt linux/Documentation/filesystems/aufs/design/02struct.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/02struct.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/02struct.txt 2014-06-24 00:14:06.772718759 +0200 -@@ -0,0 +1,242 @@ ++++ linux/Documentation/filesystems/aufs/design/02struct.txt 2014-08-14 10:15:45.115275734 +0200 +@@ -0,0 +1,251 @@ + +# Copyright (C) 2005-2014 Junjiro R. Okajima +# @@ -1300,6 +1344,15 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/02struct.txt li +changes something about the file. +"Move-down" is an opposite action of copy-up. Basically this action is +ran manually instead of automatically and internally. ++For desgin and implementation, aufs has to consider these issues. ++- whiteout for the file may exist on the lower branch. ++- ancestor directories may not exist on the lower branch. ++- diropq for the ancestor directories may exist on the upper branch. ++- free space on the lower branch will reduce. ++- another access to the file may happen during moving-down, including ++ UDBA. ++- the file should not be hard-linked nor pseudo-linked. they should be ++ handled by auplink utility later. + +Sometimes users want to move-down a file from the upper writable branch +to the lower readonly or writable branch. For instance, @@ -1310,8 +1363,8 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/02struct.txt li +For this purpose, use "aumvdown" command in aufs-util.git. diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/03lookup.txt linux/Documentation/filesystems/aufs/design/03lookup.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/03lookup.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/03lookup.txt 2014-06-24 00:14:06.772718759 +0200 -@@ -0,0 +1,105 @@ ++++ linux/Documentation/filesystems/aufs/design/03lookup.txt 2014-08-14 10:15:45.118609182 +0200 +@@ -0,0 +1,133 @@ + +# Copyright (C) 2005-2014 Junjiro R. Okajima +# @@ -1354,6 +1407,34 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/03lookup.txt li +"Revalidate Dentry and UDBA" in detail. + + ++Test Only the Highest One for the Directory Permission (dirperm1 option) ++---------------------------------------------------------------------- ++Let's try case study. ++- aufs has two branches, upper readwrite and lower readonly. ++ /au = /rw + /ro ++- "dirA" exists under /ro, but /rw. and its mode is 0700. ++- user invoked "chmod a+rx /au/dirA" ++- the internal copy-up is activated and "/rw/dirA" is created and its ++ permission bits are set to world readble. ++- then "/au/dirA" becomes world readable? ++ ++In this case, /ro/dirA is still 0700 since it exists in readonly branch, ++or it may be a natively readonly filesystem. If aufs respects the lower ++branch, it should not respond readdir request from other users. But user ++allowed it by chmod. Should really aufs rejects showing the entries ++under /ro/dirA? ++ ++To be honest, I don't have a best solution for this case. So aufs ++implements 'dirperm1' and 'nodirperm1' and leave it to users. ++When dirperm1 is specified, aufs checks only the highest one for the ++directory permission, and shows the entries. Otherwise, as usual, checks ++every dir existing on all branches and rejects the request. ++ ++As a side effect, dirperm1 option improves the performance of aufs ++because the number of permission check is reduced when the number of ++branch is many. ++ ++ +Loopback Mount +---------------------------------------------------------------------- +Basically aufs supports any type of filesystem and block device for a @@ -1419,7 +1500,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/03lookup.txt li + by over-mounting something (or another method). diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/04branch.txt linux/Documentation/filesystems/aufs/design/04branch.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/04branch.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/04branch.txt 2014-06-24 00:14:06.772718759 +0200 ++++ linux/Documentation/filesystems/aufs/design/04branch.txt 2014-01-30 21:10:02.807480310 +0100 @@ -0,0 +1,75 @@ + +# Copyright (C) 2005-2014 Junjiro R. Okajima @@ -1498,7 +1579,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/04branch.txt li + same named entry on the upper branch. diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/05wbr_policy.txt linux/Documentation/filesystems/aufs/design/05wbr_policy.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/05wbr_policy.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/05wbr_policy.txt 2014-06-24 00:14:06.772718759 +0200 ++++ linux/Documentation/filesystems/aufs/design/05wbr_policy.txt 2014-01-30 21:10:02.807480310 +0100 @@ -0,0 +1,64 @@ + +# Copyright (C) 2005-2014 Junjiro R. Okajima @@ -1564,9 +1645,133 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/05wbr_policy.tx + 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 -urN /usr/share/empty/Documentation/filesystems/aufs/design/06fhsm.txt linux/Documentation/filesystems/aufs/design/06fhsm.txt +--- /usr/share/empty/Documentation/filesystems/aufs/design/06fhsm.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux/Documentation/filesystems/aufs/design/06fhsm.txt 2014-08-14 10:15:45.118609182 +0200 +@@ -0,0 +1,120 @@ ++ ++# Copyright (C) 2011-2014 Junjiro R. Okajima ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ ++ ++File-based Hierarchical Storage Management (FHSM) ++---------------------------------------------------------------------- ++Hierarchical Storage Management (or HSM) is a well-known feature in the ++storage world. Aufs provides this feature as file-based with multiple ++writable branches, based upon the principle of "Colder-Lower". ++Here the word "colder" means that the less used files, and "lower" means ++that the position in the order of the stacked branches. ++These multiple writable branches are prioritized, ie. the topmost one ++should be the fastest drive and be used heavily. ++ ++o Characters in aufs FHSM story ++- aufs itself and a new branch attribute. ++- a new ioctl interface to move-down and to establish a connection with ++ the daemon ("move-down" is a converse of "copy-up"). ++- userspace tool and daemon. ++ ++The userspace daemon establishes a connection with aufs and waits for ++the notification. The notified information is very similar to struct ++statfs containing the number of consumed blocks and inodes. ++When the consumed blocks/inodes of a branch exceeds the user-specified ++upper watermark, the daemon activates its move-down process until the ++consumed blocks/inodes reaches the user-specified lower watermark. ++ ++The actual move-down is done by aufs based upon the request from ++user-space since we need to maintain the inode number and the internal ++pointer arrays in aufs. ++ ++Currently aufs FHSM handles the regular files only. Additionally they ++must not be hard-linked nor pseudo-linked. ++ ++ ++o Cowork of aufs and the user-space daemon ++ During the userspace daemon established the connection, aufs sends a ++ small notification to it whenever aufs writes something into the ++ writable branch. But it may cost high since aufs issues statfs(2) ++ internally. So user can specify a new option to cache the ++ info. Actually the notification is controlled by these factors. ++ + the specified cache time. ++ + classified as "force" by aufs internally. ++ Until the specified time expires, aufs doesn't send the info ++ except the forced cases. When aufs decide forcing, the info is always ++ notified to userspace. ++ For example, the number of free inodes is generally large enough and ++ the shortage of it happens rarely. So aufs doesn't force the ++ notification when creating a new file, directory and others. This is ++ the typical case which aufs doesn't force. ++ When aufs writes the actual filedata and the files consumes any of new ++ blocks, the aufs forces notifying. ++ ++ ++o Interfaces in aufs ++- New branch attribute. ++ + fhsm ++ Specifies that the branch is managed by FHSM feature. In other word, ++ participant in the FHSM. ++ When nofhsm is set to the branch, it will not be the source/target ++ branch of the move-down operation. This attribute is set ++ independently from coo and moo attributes, and if you want full ++ FHSM, you should specify them as well. ++- New mount option. ++ + fhsm_sec ++ Specifies a second to suppress many less important info to be ++ notified. ++- New ioctl. ++ + AUFS_CTL_FHSM_FD ++ create a new file descriptor which userspace can read the notification ++ (a subset of struct statfs) from aufs. ++- Module parameter 'brs' ++ It has to be set to 1. Otherwise the new mount option 'fhsm' will not ++ be set. ++- mount helpers /sbin/mount.aufs and /sbin/umount.aufs ++ When there are two or more branches with fhsm attributes, ++ /sbin/mount.aufs invokes the user-space daemon and /sbin/umount.aufs ++ terminates it. As a result of remounting and branch-manipulation, the ++ number of branches with fhsm attribute can be one. In this case, ++ /sbin/mount.aufs will terminate the user-space daemon. ++ ++ ++Finally the operation is done as these steps in kernel-space. ++- make sure that, ++ + no one else is using the file. ++ + the file is not hard-linked. ++ + the file is not pseudo-linked. ++ + the file is a regular file. ++ + the parent dir is not opaqued. ++- find the target writable branch. ++- make sure the file is not whiteout-ed by the upper (than the target) ++ branch. ++- make the parent dir on the target branch. ++- mutex lock the inode on the branch. ++- unlink the whiteout on the target branch (if exists). ++- lookup and create the whiteout-ed temporary name on the target branch. ++- copy the file as the whiteout-ed temporary name on the target branch. ++- rename the whiteout-ed temporary name to the original name. ++- unlink the file on the source branch. ++- maintain the internal pointer array and the external inode number ++ table (XINO). ++- maintain the timestamps and other attributes of the parent dir and the ++ file. ++ ++And of course, in every step, an error may happen. So the operation ++should restore the original file state after an error happens. diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/06mmap.txt linux/Documentation/filesystems/aufs/design/06mmap.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/06mmap.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/06mmap.txt 2014-06-24 00:14:06.772718759 +0200 ++++ linux/Documentation/filesystems/aufs/design/06mmap.txt 2014-01-30 21:10:02.807480310 +0100 @@ -0,0 +1,46 @@ + +# Copyright (C) 2005-2014 Junjiro R. Okajima @@ -1616,7 +1821,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/06mmap.txt linu +switching the approach. diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/07export.txt linux/Documentation/filesystems/aufs/design/07export.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/07export.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/07export.txt 2014-06-24 00:14:06.772718759 +0200 ++++ linux/Documentation/filesystems/aufs/design/07export.txt 2014-01-30 21:10:02.807480310 +0100 @@ -0,0 +1,58 @@ + +# Copyright (C) 2005-2014 Junjiro R. Okajima @@ -1678,7 +1883,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/07export.txt li + lookup_one_len(), vfs_getattr(), encode_fh() and others. diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/08shwh.txt linux/Documentation/filesystems/aufs/design/08shwh.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/08shwh.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/08shwh.txt 2014-06-24 00:14:06.772718759 +0200 ++++ linux/Documentation/filesystems/aufs/design/08shwh.txt 2014-01-30 21:10:02.807480310 +0100 @@ -0,0 +1,52 @@ + +# Copyright (C) 2005-2014 Junjiro R. Okajima @@ -1734,7 +1939,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/08shwh.txt linu +initramfs will use it to replace the old one at the next boot. diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/10dynop.txt linux/Documentation/filesystems/aufs/design/10dynop.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/10dynop.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/10dynop.txt 2014-06-24 00:14:06.772718759 +0200 ++++ linux/Documentation/filesystems/aufs/design/10dynop.txt 2014-01-30 21:10:02.807480310 +0100 @@ -0,0 +1,46 @@ + +# Copyright (C) 2010-2014 Junjiro R. Okajima @@ -1784,8 +1989,8 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/10dynop.txt lin +vm_operations_struct for regular files only. diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/99plan.txt linux/Documentation/filesystems/aufs/design/99plan.txt --- /usr/share/empty/Documentation/filesystems/aufs/design/99plan.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/design/99plan.txt 2014-06-24 00:14:06.772718759 +0200 -@@ -0,0 +1,95 @@ ++++ linux/Documentation/filesystems/aufs/design/99plan.txt 2014-08-14 10:15:45.118609182 +0200 +@@ -0,0 +1,58 @@ + +# Copyright (C) 2005-2014 Junjiro R. Okajima +# @@ -1809,32 +2014,6 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/99plan.txt linu +easier to be reviewed. + + -+Test Only the Highest One for the Directory Permission (dirperm1 option) -+---------------------------------------------------------------------- -+Let's try case study. -+- aufs has two branches, upper readwrite and lower readonly. -+ /au = /rw + /ro -+- "dirA" exists under /ro, but /rw. and its mode is 0700. -+- user invoked "chmod a+rx /au/dirA" -+- then "dirA" becomes world readable? -+ -+In this case, /ro/dirA is still 0700 since it exists in readonly branch, -+or it may be a natively readonly filesystem. If aufs respects the lower -+branch, it should not respond readdir request from other users. But user -+allowed it by chmod. Should really aufs rejects showing the entries -+under /ro/dirA? -+ -+To be honest, I don't have a best solution for this case. So I -+implemented 'dirperm1' and 'nodirperm1' option in aufs1, and leave it to -+users. -+When dirperm1 is specified, aufs checks only the highest one for the -+directory permission, and shows the entries. Otherwise, as usual, checks -+every dir existing on all branches and rejects the request. -+ -+As a side effect, dirperm1 option improves the performance of aufs -+because the number of permission check is reduced. -+ -+ +Being Another Aufs's Readonly Branch (robr) +---------------------------------------------------------------------- +Aufs1 allows aufs to be another aufs's readonly branch. @@ -1842,17 +2021,6 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/99plan.txt linu +currecnly. + + -+Copy-up on Open (coo=) -+---------------------------------------------------------------------- -+By default the internal copy-up is executed when it is really necessary. -+It is not done when a file is opened for writing, but when write(2) is -+done. Users who have many (over 100) branches want to know and analyse -+when and what file is copied-up. To insert a new upper branch which -+contains such files only may improve the performance of aufs. -+ -+Aufs1 implemented "coo=none | leaf | all" option. -+ -+ +Refresh the Opened File (refrof) +---------------------------------------------------------------------- +This option is implemented in aufs1 but incomplete. @@ -1883,8 +2051,8 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/design/99plan.txt linu +Otherwise from /new. diff -urN /usr/share/empty/Documentation/filesystems/aufs/README linux/Documentation/filesystems/aufs/README --- /usr/share/empty/Documentation/filesystems/aufs/README 1970-01-01 01:00:00.000000000 +0100 -+++ linux/Documentation/filesystems/aufs/README 2014-06-24 00:14:06.769385243 +0200 -@@ -0,0 +1,368 @@ ++++ linux/Documentation/filesystems/aufs/README 2014-08-14 10:15:45.115275734 +0200 +@@ -0,0 +1,370 @@ + +Aufs3 -- advanced multi layered unification filesystem version 3.x +http://aufs.sf.net @@ -1915,7 +2083,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/README linux/Documenta + 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 @@ -2236,6 +2404,8 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/README linux/Documenta +The Parted Magic Project made a donation (2013/9 and 11). +Pavel Barta made a donation (2013/10). +Nikolay Pertsev made a donation (2014/5). ++James B made a donation (2014/7). ++Stefano Di Biase made a donation (2014/8). + +Thank you very much. +Donations are always, including future donations, very important and @@ -2255,7 +2425,7 @@ diff -urN /usr/share/empty/Documentation/filesystems/aufs/README linux/Documenta +# End: ; diff -urN /usr/share/empty/fs/aufs/aufs.h linux/fs/aufs/aufs.h --- /usr/share/empty/fs/aufs/aufs.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/aufs.h 2014-06-24 00:14:06.776052275 +0200 ++++ linux/fs/aufs/aufs.h 2014-01-30 21:10:02.827480967 +0100 @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -2318,8 +2488,8 @@ diff -urN /usr/share/empty/fs/aufs/aufs.h linux/fs/aufs/aufs.h +#endif /* __AUFS_H__ */ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c --- /usr/share/empty/fs/aufs/branch.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/branch.c 2014-06-24 00:14:06.776052275 +0200 -@@ -0,0 +1,1220 @@ ++++ linux/fs/aufs/branch.c 2014-08-14 10:16:04.512608923 +0200 +@@ -0,0 +1,1447 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -2398,6 +2568,11 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + AuRwDestroy(&wbr->wbr_wh_rwsem); + } + ++ if (br->br_fhsm) { ++ au_br_fhsm_fin(br->br_fhsm); ++ kfree(br->br_fhsm); ++ } ++ + key = br->br_dykey; + for (i = 0; i < AuBrDynOp; i++, key++) + if (*key) @@ -2493,6 +2668,13 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + goto out_hnotify; + } + ++ add_branch->br_fhsm = NULL; ++ if (au_br_fhsm(perm)) { ++ err = au_fhsm_br_alloc(add_branch); ++ if (unlikely(err)) ++ goto out_wbr; ++ } ++ + err = au_sbr_realloc(au_sbi(sb), new_nbranch); + if (!err) + err = au_di_realloc(au_di(root), new_nbranch); @@ -2501,8 +2683,8 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + if (!err) + return add_branch; /* success */ + ++out_wbr: + kfree(add_branch->br_wbr); -+ +out_hnotify: + au_hnotify_fin_br(add_branch); +out_br: @@ -2885,6 +3067,54 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + +/* ---------------------------------------------------------------------- */ + ++static unsigned long long au_farray_cb(void *a, ++ unsigned long long max __maybe_unused, ++ void *arg) ++{ ++ unsigned long long n; ++ struct file **p, *f; ++ struct au_sphlhead *files; ++ struct au_finfo *finfo; ++ struct super_block *sb = arg; ++ ++ n = 0; ++ p = a; ++ files = &au_sbi(sb)->si_files; ++ spin_lock(&files->spin); ++ hlist_for_each_entry(finfo, &files->head, fi_hlist) { ++ f = finfo->fi_file; ++ if (file_count(f) ++ && !special_file(file_inode(f)->i_mode)) { ++ get_file(f); ++ *p++ = f; ++ n++; ++ AuDebugOn(n > max); ++ } ++ } ++ spin_unlock(&files->spin); ++ ++ return n; ++} ++ ++static struct file **au_farray_alloc(struct super_block *sb, ++ unsigned long long *max) ++{ ++ *max = atomic_long_read(&au_sbi(sb)->si_nfiles); ++ return au_array_alloc(max, au_farray_cb, sb); ++} ++ ++static void au_farray_free(struct file **a, unsigned long long max) ++{ ++ unsigned long long ull; ++ ++ for (ull = 0; ull < max; ull++) ++ if (a[ull]) ++ fput(a[ull]); ++ au_array_free(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ +/* + * delete a branch + */ @@ -2991,6 +3221,8 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + AuDbg("b%d\n", bindex); + for (ull = 0; !err && ull < max; ull++) { + i = array[ull]; ++ if (unlikely(!i)) ++ break; + if (i->i_ino == AUFS_ROOT_INO) + continue; + @@ -3045,6 +3277,139 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + return err; +} + ++static int test_dir_busy(struct file *file, aufs_bindex_t br_id, ++ struct file **to_free, int *idx) ++{ ++ int err; ++ unsigned char matched, unmatched; ++ aufs_bindex_t bindex, bend; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ ++ err = 0; ++ matched = 0; ++ unmatched = 0; ++ fidir = au_fi(file)->fi_hdir; ++ AuDebugOn(!fidir); ++ bend = au_fbend_dir(file); ++ for (bindex = au_fbstart(file); bindex <= bend; bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ if (!hfile->hf_file) ++ continue; ++ ++ if (hfile->hf_br->br_id == br_id) ++ matched = 1; ++ else ++ unmatched = 1; ++ if (matched && unmatched) ++ break; ++ } ++ if (!matched) ++ goto out; /* success */ ++ ++ if (unmatched) { ++ get_file(file); ++ to_free[*idx] = file; ++ (*idx)++; ++ } else ++ err = -EBUSY; ++ ++out: ++ return err; ++} ++ ++static int test_file_busy(struct super_block *sb, aufs_bindex_t br_id, ++ struct file **to_free, int opened) ++{ ++ int err, idx; ++ unsigned long long ull, max; ++ aufs_bindex_t bstart; ++ struct file *file, **array; ++ struct inode *inode; ++ struct dentry *root; ++ struct au_hfile *hfile; ++ ++ array = au_farray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ idx = 0; ++ root = sb->s_root; ++ di_write_unlock(root); ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ fi_read_lock(file); ++ bstart = au_fbstart(file); ++ inode = file_inode(file); ++ if (!S_ISDIR(inode->i_mode)) { ++ hfile = &au_fi(file)->fi_htop; ++ if (hfile->hf_br->br_id == br_id) ++ err = -EBUSY; ++ } else ++ err = test_dir_busy(file, br_id, to_free, &idx); ++ fi_read_unlock(file); ++ if (unlikely(err)) ++ break; ++ } ++ di_write_lock_child(root); ++ au_farray_free(array, max); ++ AuDebugOn(idx > opened); ++ ++out: ++ return err; ++} ++ ++static void br_del_file(struct file **to_free, unsigned long long opened, ++ aufs_bindex_t br_id) ++{ ++ unsigned long long ull; ++ aufs_bindex_t bindex, bstart, bend, bfound; ++ struct file *file; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ ++ for (ull = 0; ull < opened; ull++) { ++ file = to_free[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ AuDebugOn(!S_ISDIR(file_inode(file)->i_mode)); ++ bfound = -1; ++ fidir = au_fi(file)->fi_hdir; ++ AuDebugOn(!fidir); ++ fi_write_lock(file); ++ bstart = au_fbstart(file); ++ bend = au_fbend_dir(file); ++ for (bindex = bstart; bindex <= bend; bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ if (!hfile->hf_file) ++ continue; ++ ++ if (hfile->hf_br->br_id == br_id) { ++ bfound = bindex; ++ break; ++ } ++ } ++ AuDebugOn(bfound < 0); ++ au_set_h_fptr(file, bfound, NULL); ++ if (bfound == bstart) { ++ for (bstart++; bstart <= bend; bstart++) ++ if (au_hf_dir(file, bstart)) { ++ au_set_fbstart(file, bstart); ++ break; ++ } ++ } ++ fi_write_unlock(file); ++ } ++} ++ +static void au_br_do_del_brp(struct au_sbinfo *sbinfo, + const aufs_bindex_t bindex, + const aufs_bindex_t bend) @@ -3137,17 +3502,29 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + au_br_do_free(br); +} + ++static unsigned long long empty_cb(void *array, unsigned long long max, ++ void *arg) ++{ ++ return max; ++} ++ +int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) +{ + int err, rerr, i; ++ unsigned long long opened; + unsigned int mnt_flags; + aufs_bindex_t bindex, bend, br_id; + unsigned char do_wh, verbose; + struct au_branch *br; + struct au_wbr *wbr; ++ struct dentry *root; ++ struct file **to_free; + + err = 0; -+ bindex = au_find_dbindex(sb->s_root, del->h_path.dentry); ++ opened = 0; ++ to_free = NULL; ++ root = sb->s_root; ++ bindex = au_find_dbindex(root, del->h_path.dentry); + if (bindex < 0) { + if (remount) + goto out; /* success */ @@ -3167,10 +3544,20 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + } + br = au_sbr(sb, bindex); + AuDebugOn(!path_equal(&br->br_path, &del->h_path)); -+ i = atomic_read(&br->br_count); -+ if (unlikely(i)) { -+ AuVerbose(verbose, "%d file(s) opened\n", i); -+ goto out; ++ ++ br_id = br->br_id; ++ opened = atomic_read(&br->br_count); ++ if (unlikely(opened)) { ++ to_free = au_array_alloc(&opened, empty_cb, NULL); ++ err = PTR_ERR(to_free); ++ if (IS_ERR(to_free)) ++ goto out; ++ ++ err = test_file_busy(sb, br_id, to_free, opened); ++ if (unlikely(err)) { ++ AuVerbose(verbose, "%llu file(s) opened\n", opened); ++ goto out; ++ } + } + + wbr = br->br_wbr; @@ -3184,7 +3571,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + } + } + -+ err = test_children_busy(sb->s_root, bindex, verbose); ++ err = test_children_busy(root, bindex, verbose); + if (unlikely(err)) { + if (do_wh) + goto out_wh; @@ -3192,7 +3579,16 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + } + + err = 0; -+ br_id = br->br_id; ++ if (to_free) { ++ /* ++ * now we confirmed the branch is deletable. ++ * let's free the remaining opened dirs on the branch. ++ */ ++ di_write_unlock(root); ++ br_del_file(to_free, opened, br_id); ++ di_write_lock_child(root); ++ } ++ + if (!remount) + au_br_do_del(sb, bindex, br); + else { @@ -3202,10 +3598,10 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + } + + if (!bindex) { -+ au_cpup_attr_all(sb->s_root->d_inode, /*force*/1); ++ au_cpup_attr_all(root->d_inode, /*force*/1); + sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes; + } else -+ au_sub_nlink(sb->s_root->d_inode, del->h_path.dentry->d_inode); ++ au_sub_nlink(root->d_inode, del->h_path.dentry->d_inode); + if (au_opt_test(mnt_flags, PLINK)) + au_plink_half_refresh(sb, br_id); + @@ -3220,6 +3616,8 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + pr_warn("failed re-creating base whiteout, %s. (%d)\n", + del->pathname, rerr); +out: ++ if (to_free) ++ au_farray_free(to_free, opened); + return err; +} + @@ -3319,52 +3717,6 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + || do_need_sigen_inc(new, old); +} + -+static unsigned long long au_farray_cb(void *a, -+ unsigned long long max __maybe_unused, -+ void *arg) -+{ -+ unsigned long long n; -+ struct file **p, *f; -+ struct au_sphlhead *files; -+ struct au_finfo *finfo; -+ struct super_block *sb = arg; -+ -+ n = 0; -+ p = a; -+ files = &au_sbi(sb)->si_files; -+ spin_lock(&files->spin); -+ hlist_for_each_entry(finfo, &files->head, fi_hlist) { -+ f = finfo->fi_file; -+ if (file_count(f) -+ && !special_file(file_inode(f)->i_mode)) { -+ get_file(f); -+ *p++ = f; -+ n++; -+ AuDebugOn(n > max); -+ } -+ } -+ spin_unlock(&files->spin); -+ -+ return n; -+} -+ -+static struct file **au_farray_alloc(struct super_block *sb, -+ unsigned long long *max) -+{ -+ *max = atomic_long_read(&au_sbi(sb)->si_nfiles); -+ return au_array_alloc(max, au_farray_cb, sb); -+} -+ -+static void au_farray_free(struct file **a, unsigned long long max) -+{ -+ unsigned long long ull; -+ -+ for (ull = 0; ull < max; ull++) -+ if (a[ull]) -+ fput(a[ull]); -+ au_array_free(a); -+} -+ +static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex) +{ + int err, do_warn; @@ -3388,6 +3740,8 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + br_id = au_sbr_id(sb, bindex); + for (ull = 0; ull < max; ull++) { + file = array[ull]; ++ if (unlikely(!file)) ++ break; + + /* AuDbg("%pD\n", file); */ + fi_read_lock(file); @@ -3463,6 +3817,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + aufs_bindex_t bindex; + struct dentry *root; + struct au_branch *br; ++ struct au_br_fhsm *bf; + + root = sb->s_root; + bindex = au_find_dbindex(root, mod->h_root); @@ -3484,11 +3839,21 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + if (br->br_perm == mod->perm) + return 0; /* success */ + ++ /* pre-allocate for non-fhsm --> fhsm */ ++ bf = NULL; ++ if (!au_br_fhsm(br->br_perm) && au_br_fhsm(mod->perm)) { ++ err = au_fhsm_br_alloc(br); ++ if (unlikely(err)) ++ goto out; ++ bf = br->br_fhsm; ++ br->br_fhsm = NULL; ++ } ++ + if (au_br_writable(br->br_perm)) { + /* remove whiteout base */ + err = au_br_init_wh(sb, br, mod->perm); + if (unlikely(err)) -+ goto out; ++ goto out_bf; + + if (!au_br_writable(mod->perm)) { + /* rw --> ro, file might be mmapped */ @@ -3524,26 +3889,58 @@ diff -urN /usr/share/empty/fs/aufs/branch.c linux/fs/aufs/branch.c + } + } + } ++ if (unlikely(err)) ++ goto out_bf; ++ ++ if (au_br_fhsm(br->br_perm)) { ++ if (!au_br_fhsm(mod->perm)) { ++ /* fhsm --> non-fhsm */ ++ au_br_fhsm_fin(br->br_fhsm); ++ kfree(br->br_fhsm); ++ br->br_fhsm = NULL; ++ } ++ } else if (au_br_fhsm(mod->perm)) ++ /* non-fhsm --> fhsm */ ++ br->br_fhsm = bf; ++ ++ if ((br->br_perm & AuBrAttr_UNPIN) ++ && !(mod->perm & AuBrAttr_UNPIN)) ++ au_br_dflags_force(br); ++ else if (!(br->br_perm & AuBrAttr_UNPIN) ++ && (mod->perm & AuBrAttr_UNPIN)) ++ au_br_dflags_restore(br); ++ *do_refresh |= need_sigen_inc(br->br_perm, mod->perm); ++ br->br_perm = mod->perm; ++ goto out; /* success */ + ++out_bf: ++ kfree(bf); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs) ++{ ++ int err; ++ struct kstatfs kstfs; ++ ++ err = vfs_statfs(&br->br_path, &kstfs); + if (!err) { -+ if ((br->br_perm & AuBrAttr_UNPIN) -+ && !(mod->perm & AuBrAttr_UNPIN)) -+ au_br_dflags_force(br); -+ else if (!(br->br_perm & AuBrAttr_UNPIN) -+ && (mod->perm & AuBrAttr_UNPIN)) -+ au_br_dflags_restore(br); -+ *do_refresh |= need_sigen_inc(br->br_perm, mod->perm); -+ br->br_perm = mod->perm; ++ stfs->f_blocks = kstfs.f_blocks; ++ stfs->f_bavail = kstfs.f_bavail; ++ stfs->f_files = kstfs.f_files; ++ stfs->f_ffree = kstfs.f_ffree; + } + -+out: -+ AuTraceErr(err); + return err; +} diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h --- /usr/share/empty/fs/aufs/branch.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/branch.h 2014-06-24 00:14:06.776052275 +0200 -@@ -0,0 +1,264 @@ ++++ linux/fs/aufs/branch.h 2014-08-14 10:15:45.118609182 +0200 +@@ -0,0 +1,268 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -3589,6 +3986,16 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h +#endif +}; + ++/* File-based Hierarchical Storage Management */ ++struct au_br_fhsm { ++#ifdef CONFIG_AUFS_FHSM ++ struct mutex bf_lock; ++ unsigned long bf_jiffy; ++ struct aufs_stfs bf_stfs; ++ int bf_readable; ++#endif ++}; ++ +/* members for writable branch only */ +enum {AuBrWh_BASE, AuBrWh_PLINK, AuBrWh_ORPH, AuBrWh_Last}; +struct au_wbr { @@ -3639,6 +4046,7 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h + atomic_t br_count; + + struct au_wbr *br_wbr; ++ struct au_br_fhsm *br_fhsm; + + /* xino truncation */ + atomic_t br_xino_running; @@ -3670,34 +4078,6 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h + return au_br_mnt(br)->mnt_sb; +} + -+/* branch permissions and attributes */ -+#define AuBrPerm_RW 1 /* writable, hardlinkable wh */ -+#define AuBrPerm_RO (1 << 1) /* readonly */ -+#define AuBrPerm_RR (1 << 2) /* natively readonly */ -+#define AuBrPerm_Mask (AuBrPerm_RW | AuBrPerm_RO | AuBrPerm_RR) -+ -+#define AuBrRAttr_WH (1 << 3) /* whiteout-able */ -+ -+#define AuBrWAttr_NoLinkWH (1 << 4) /* un-hardlinkable whiteouts */ -+ -+#define AuBrAttr_UNPIN (1 << 5) /* rename-able top dir of -+ branch */ -+ -+static inline int au_br_writable(int brperm) -+{ -+ return brperm & AuBrPerm_RW; -+} -+ -+static inline int au_br_whable(int brperm) -+{ -+ return brperm & (AuBrPerm_RW | AuBrRAttr_WH); -+} -+ -+static inline int au_br_wh_linkable(int brperm) -+{ -+ return !(brperm & AuBrWAttr_NoLinkWH); -+} -+ +static inline int au_br_rdonly(struct au_branch *br) +{ + return ((au_br_sb(br)->s_flags & MS_RDONLY) @@ -3731,6 +4111,8 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h +struct au_opt_mod; +int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, + int *do_refresh); ++struct aufs_stfs; ++int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs); + +/* xino.c */ +static const loff_t au_loff_max = LLONG_MAX; @@ -3806,12 +4188,31 @@ diff -urN /usr/share/empty/fs/aufs/branch.h linux/fs/aufs/branch.h +#define WbrWhMustAnyLock(wbr) AuRwMustAnyLock(&wbr->wbr_wh_rwsem) +#define WbrWhMustWriteLock(wbr) AuRwMustWriteLock(&wbr->wbr_wh_rwsem) + ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_FHSM ++static inline void au_br_fhsm_init(struct au_br_fhsm *brfhsm) ++{ ++ mutex_init(&brfhsm->bf_lock); ++ brfhsm->bf_jiffy = 0; ++ brfhsm->bf_readable = 0; ++} ++ ++static inline void au_br_fhsm_fin(struct au_br_fhsm *brfhsm) ++{ ++ mutex_destroy(&brfhsm->bf_lock); ++} ++#else ++AuStubVoid(au_br_fhsm_init, struct au_br_fhsm *brfhsm) ++AuStubVoid(au_br_fhsm_fin, struct au_br_fhsm *brfhsm) ++#endif ++ +#endif /* __KERNEL__ */ +#endif /* __AUFS_BRANCH_H__ */ diff -urN /usr/share/empty/fs/aufs/conf.mk linux/fs/aufs/conf.mk --- /usr/share/empty/fs/aufs/conf.mk 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/conf.mk 2014-06-24 00:14:06.776052275 +0200 -@@ -0,0 +1,36 @@ ++++ linux/fs/aufs/conf.mk 2014-08-14 10:15:45.118609182 +0200 +@@ -0,0 +1,37 @@ + +AuConfStr = CONFIG_AUFS_FS=${CONFIG_AUFS_FS} + @@ -3825,6 +4226,7 @@ diff -urN /usr/share/empty/fs/aufs/conf.mk linux/fs/aufs/conf.mk + SBILIST \ + HNOTIFY HFSNOTIFY \ + EXPORT INO_T_64 \ ++ FHSM \ + RDU \ + SHWH \ + BR_RAMFS \ @@ -3850,8 +4252,8 @@ diff -urN /usr/share/empty/fs/aufs/conf.mk linux/fs/aufs/conf.mk +-include ${srctree}/${src}/conf_priv.mk diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c --- /usr/share/empty/fs/aufs/cpup.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/cpup.c 2014-06-24 00:14:06.779385790 +0200 -@@ -0,0 +1,1289 @@ ++++ linux/fs/aufs/cpup.c 2014-08-14 10:15:45.118609182 +0200 +@@ -0,0 +1,1301 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -4351,7 +4753,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c + int err; + umode_t mode; + unsigned int mnt_flags; -+ unsigned char isdir; ++ unsigned char isdir, isreg, force; + const unsigned char do_dt = !!au_ftest_cpup(cpg->flags, DTIME); + struct au_dtime dt; + struct path h_path; @@ -4382,10 +4784,12 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c + } + h_path.dentry = h_dst; + ++ isreg = 0; + isdir = 0; + mode = h_inode->i_mode; + switch (mode & S_IFMT) { + case S_IFREG: ++ isreg = 1; + err = vfsub_create(h_dir, &h_path, mode | S_IWUSR, + /*want_excl*/true); + if (!err) @@ -4434,6 +4838,16 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c + au_xino_write(sb, cpg->bsrc, h_inode->i_ino, /*ino*/0); + /* ignore this error */ + ++ if (!err) { ++ force = 0; ++ if (isreg) { ++ force = !!cpg->len; ++ if (cpg->len == -1) ++ force = !!i_size_read(h_inode); ++ } ++ au_fhsm_wrote(sb, cpg->bdst, force); ++ } ++ + if (do_dt) + au_dtime_revert(&dt); + return err; @@ -5143,7 +5557,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.c linux/fs/aufs/cpup.c +} diff -urN /usr/share/empty/fs/aufs/cpup.h linux/fs/aufs/cpup.h --- /usr/share/empty/fs/aufs/cpup.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/cpup.h 2014-06-24 00:14:06.779385790 +0200 ++++ linux/fs/aufs/cpup.h 2014-01-30 21:10:02.827480967 +0100 @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -5241,7 +5655,7 @@ diff -urN /usr/share/empty/fs/aufs/cpup.h linux/fs/aufs/cpup.h +#endif /* __AUFS_CPUP_H__ */ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c --- /usr/share/empty/fs/aufs/dbgaufs.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/dbgaufs.c 2014-06-24 00:14:06.779385790 +0200 ++++ linux/fs/aufs/dbgaufs.c 2014-01-30 21:10:02.827480967 +0100 @@ -0,0 +1,432 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -5677,7 +6091,7 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.c linux/fs/aufs/dbgaufs.c +} diff -urN /usr/share/empty/fs/aufs/dbgaufs.h linux/fs/aufs/dbgaufs.h --- /usr/share/empty/fs/aufs/dbgaufs.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/dbgaufs.h 2014-06-24 00:14:06.779385790 +0200 ++++ linux/fs/aufs/dbgaufs.h 2014-01-30 21:10:02.827480967 +0100 @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -5729,7 +6143,7 @@ diff -urN /usr/share/empty/fs/aufs/dbgaufs.h linux/fs/aufs/dbgaufs.h +#endif /* __DBGAUFS_H__ */ diff -urN /usr/share/empty/fs/aufs/dcsub.c linux/fs/aufs/dcsub.c --- /usr/share/empty/fs/aufs/dcsub.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/dcsub.c 2014-06-24 00:14:06.779385790 +0200 ++++ linux/fs/aufs/dcsub.c 2014-01-30 21:10:02.827480967 +0100 @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -5976,8 +6390,8 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.c linux/fs/aufs/dcsub.c +} diff -urN /usr/share/empty/fs/aufs/dcsub.h linux/fs/aufs/dcsub.h --- /usr/share/empty/fs/aufs/dcsub.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/dcsub.h 2014-06-24 00:14:06.779385790 +0200 -@@ -0,0 +1,116 @@ ++++ linux/fs/aufs/dcsub.h 2014-08-14 10:15:45.118609182 +0200 +@@ -0,0 +1,120 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -6044,6 +6458,7 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.h linux/fs/aufs/dcsub.h +{ + int err; + struct inode *inode = d->d_inode; ++ + err = 0; + if (unlikely(d_unhashed(d) || !inode || !inode->i_nlink)) + err = -ENOENT; @@ -6054,6 +6469,7 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.h linux/fs/aufs/dcsub.h +{ + int err; + struct inode *inode = d->d_inode; ++ + err = au_d_hashed_positive(d); + if (err + && inode @@ -6066,6 +6482,7 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.h linux/fs/aufs/dcsub.h +{ + int err; + struct inode *inode; ++ + err = 0; + if (!IS_ROOT(d)) + err = au_d_hashed_positive(d); @@ -6080,6 +6497,7 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.h linux/fs/aufs/dcsub.h +static inline int au_alive_dir(struct dentry *d) +{ + int err; ++ + err = au_d_alive(d); + if (unlikely(err || IS_DEADDIR(d->d_inode))) + err = -ENOENT; @@ -6096,8 +6514,8 @@ diff -urN /usr/share/empty/fs/aufs/dcsub.h linux/fs/aufs/dcsub.h +#endif /* __AUFS_DCSUB_H__ */ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c --- /usr/share/empty/fs/aufs/debug.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/debug.c 2014-06-24 00:14:06.779385790 +0200 -@@ -0,0 +1,518 @@ ++++ linux/fs/aufs/debug.c 2014-08-14 10:15:45.121942630 +0200 +@@ -0,0 +1,519 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -6277,6 +6695,7 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c +{ + struct dentry *wh = NULL; + int hn; ++ struct au_iinfo *iinfo; + + if (!dentry || IS_ERR(dentry)) { + dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry)); @@ -6291,7 +6710,7 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c + d_unhashed(dentry) ? "un" : ""); + hn = -1; + if (bindex >= 0 && dentry->d_inode && au_test_aufs(dentry->d_sb)) { -+ struct au_iinfo *iinfo = au_ii(dentry->d_inode); ++ iinfo = au_ii(dentry->d_inode); + if (iinfo) { + hn = !!au_hn(iinfo->ii_hinode + bindex); + wh = iinfo->ii_hinode[0 + bindex].hi_whdentry; @@ -6618,7 +7037,7 @@ diff -urN /usr/share/empty/fs/aufs/debug.c linux/fs/aufs/debug.c +} diff -urN /usr/share/empty/fs/aufs/debug.h linux/fs/aufs/debug.h --- /usr/share/empty/fs/aufs/debug.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/debug.h 2014-06-24 00:14:06.779385790 +0200 ++++ linux/fs/aufs/debug.h 2014-01-30 21:10:02.827480967 +0100 @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -6869,8 +7288,8 @@ diff -urN /usr/share/empty/fs/aufs/debug.h linux/fs/aufs/debug.h +#endif /* __AUFS_DEBUG_H__ */ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c --- /usr/share/empty/fs/aufs/dentry.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/dentry.c 2014-06-24 00:14:06.779385790 +0200 -@@ -0,0 +1,1084 @@ ++++ linux/fs/aufs/dentry.c 2014-08-14 10:16:04.515942371 +0200 +@@ -0,0 +1,1094 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -6896,6 +7315,7 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c +#include "aufs.h" + +#define AuLkup_ALLOW_NEG 1 ++#define AuLkup_IGNORE_PERM (1 << 1) +#define au_ftest_lkup(flags, name) ((flags) & AuLkup_##name) +#define au_fset_lkup(flags, name) \ + do { (flags) |= AuLkup_##name; } while (0) @@ -6922,12 +7342,14 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c + int wh_found, opq; + unsigned char wh_able; + const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG); ++ const unsigned char ignore_perm = !!au_ftest_lkup(args->flags, ++ IGNORE_PERM); + + wh_found = 0; + br = au_sbr(dentry->d_sb, bindex); + wh_able = !!au_br_whable(br->br_perm); + if (wh_able) -+ wh_found = au_wh_test(h_parent, wh_name, br, /*try_sio*/0); ++ wh_found = au_wh_test(h_parent, wh_name, /*try_sio*/0); + h_dentry = ERR_PTR(wh_found); + if (!wh_found) + goto real_lookup; @@ -6941,7 +7363,10 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c + return NULL; /* success */ + +real_lookup: -+ h_dentry = vfsub_lkup_one(&dentry->d_name, h_parent); ++ if (!ignore_perm) ++ h_dentry = vfsub_lkup_one(&dentry->d_name, h_parent); ++ else ++ h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent); + if (IS_ERR(h_dentry)) + goto out; + @@ -6965,7 +7390,7 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c + goto out; /* success */ + + mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); -+ opq = au_diropq_test(h_dentry, br); ++ opq = au_diropq_test(h_dentry); + mutex_unlock(&h_inode->i_mutex); + if (opq > 0) + au_set_dbdiropq(dentry, bindex); @@ -6999,7 +7424,7 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c +{ + int npositive, err; + aufs_bindex_t bindex, btail, bdiropq; -+ unsigned char isdir; ++ unsigned char isdir, dirperm1; + struct qstr whname; + struct au_do_lookup_args args = { + .flags = 0, @@ -7008,8 +7433,10 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c + const struct qstr *name = &dentry->d_name; + struct dentry *parent; + struct inode *inode; ++ struct super_block *sb; + -+ err = au_test_shwh(dentry->d_sb, name); ++ sb = dentry->d_sb; ++ err = au_test_shwh(sb, name); + if (unlikely(err)) + goto out; + @@ -7021,6 +7448,7 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c + isdir = !!(inode && S_ISDIR(inode->i_mode)); + if (!type) + au_fset_lkup(args.flags, ALLOW_NEG); ++ dirperm1 = !!au_opt_test(au_mntflags(sb), DIRPERM1); + + npositive = 0; + parent = dget_parent(dentry); @@ -7052,6 +7480,8 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c + if (IS_ERR(h_dentry)) + goto out_parent; + au_fclr_lkup(args.flags, ALLOW_NEG); ++ if (dirperm1) ++ au_fset_lkup(args.flags, IGNORE_PERM); + + if (au_dbwh(dentry) >= 0) + break; @@ -7078,7 +7508,7 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c + au_update_dbstart(dentry); + } + err = npositive; -+ if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE) ++ if (unlikely(!au_opt_test(au_mntflags(sb), UDBA_NONE) + && au_dbstart(dentry) < 0)) { + err = -EIO; + AuIOErr("both of real entry and whiteout found, %pd, err %d\n", @@ -7092,8 +7522,7 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c + return err; +} + -+struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent, -+ struct au_branch *br) ++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent) +{ + struct dentry *dentry; + int wkq_err; @@ -7130,7 +7559,7 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c + if (wh) + h_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); + else -+ h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent, br); ++ h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent); + err = PTR_ERR(h_dentry); + if (IS_ERR(h_dentry)) + goto out; @@ -7957,8 +8386,8 @@ diff -urN /usr/share/empty/fs/aufs/dentry.c linux/fs/aufs/dentry.c +}; diff -urN /usr/share/empty/fs/aufs/dentry.h linux/fs/aufs/dentry.h --- /usr/share/empty/fs/aufs/dentry.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/dentry.h 2014-06-24 00:14:06.779385790 +0200 -@@ -0,0 +1,234 @@ ++++ linux/fs/aufs/dentry.h 2014-08-14 10:15:45.121942630 +0200 +@@ -0,0 +1,233 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -8007,8 +8436,7 @@ diff -urN /usr/share/empty/fs/aufs/dentry.h linux/fs/aufs/dentry.h +/* dentry.c */ +extern const struct dentry_operations aufs_dop; +struct au_branch; -+struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent, -+ struct au_branch *br); ++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent); +int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, + struct dentry *h_parent, struct au_branch *br); + @@ -8195,7 +8623,7 @@ diff -urN /usr/share/empty/fs/aufs/dentry.h linux/fs/aufs/dentry.h +#endif /* __AUFS_DENTRY_H__ */ diff -urN /usr/share/empty/fs/aufs/dinfo.c linux/fs/aufs/dinfo.c --- /usr/share/empty/fs/aufs/dinfo.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/dinfo.c 2014-06-24 00:14:06.779385790 +0200 ++++ linux/fs/aufs/dinfo.c 2014-08-14 10:15:45.121942630 +0200 @@ -0,0 +1,544 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -8743,8 +9171,8 @@ diff -urN /usr/share/empty/fs/aufs/dinfo.c linux/fs/aufs/dinfo.c +} diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c --- /usr/share/empty/fs/aufs/dir.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/dir.c 2014-06-24 00:14:06.779385790 +0200 -@@ -0,0 +1,639 @@ ++++ linux/fs/aufs/dir.c 2014-08-14 10:15:45.121942630 +0200 +@@ -0,0 +1,645 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -8964,6 +9392,8 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c + finfo = au_fi(file); + fidir = finfo->fi_hdir; + if (fidir) { ++ au_sphl_del(&finfo->fi_hlist, ++ &au_sbi(file->f_dentry->d_sb)->si_files); + vdir_cache = fidir->fd_vdir_cache; /* lock-free */ + if (vdir_cache) + au_vdir_free(vdir_cache); @@ -9301,6 +9731,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c + .actor = au_diractor(test_empty_cb) + } + }; ++ int (*test_empty)(struct dentry *dentry, struct test_empty_arg *arg); + + SiMustAnyLock(dentry->d_sb); + @@ -9316,8 +9747,11 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c + bstart = au_dbstart(dentry); + if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) + au_fset_testempty(arg.flags, SHWH); ++ test_empty = do_test_empty; ++ if (au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1)) ++ test_empty = sio_test_empty; + arg.bindex = bstart; -+ err = do_test_empty(dentry, &arg); ++ err = test_empty(dentry, &arg); + if (unlikely(err)) + goto out_whlist; + @@ -9329,7 +9763,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c + h_dentry = au_h_dptr(dentry, bindex); + if (h_dentry && h_dentry->d_inode) { + arg.bindex = bindex; -+ err = do_test_empty(dentry, &arg); ++ err = test_empty(dentry, &arg); + } + } + @@ -9386,7 +9820,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.c linux/fs/aufs/dir.c +}; diff -urN /usr/share/empty/fs/aufs/dir.h linux/fs/aufs/dir.h --- /usr/share/empty/fs/aufs/dir.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/dir.h 2014-06-24 00:14:06.779385790 +0200 ++++ linux/fs/aufs/dir.h 2014-01-30 21:10:02.830814411 +0100 @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -9526,7 +9960,7 @@ diff -urN /usr/share/empty/fs/aufs/dir.h linux/fs/aufs/dir.h +#endif /* __AUFS_DIR_H__ */ diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c --- /usr/share/empty/fs/aufs/dynop.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/dynop.c 2014-06-24 00:14:06.782719306 +0200 ++++ linux/fs/aufs/dynop.c 2014-01-30 21:10:02.830814411 +0100 @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2010-2014 Junjiro R. Okajima @@ -9909,7 +10343,7 @@ diff -urN /usr/share/empty/fs/aufs/dynop.c linux/fs/aufs/dynop.c +} diff -urN /usr/share/empty/fs/aufs/dynop.h linux/fs/aufs/dynop.h --- /usr/share/empty/fs/aufs/dynop.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/dynop.h 2014-06-24 00:14:06.782719306 +0200 ++++ linux/fs/aufs/dynop.h 2014-01-30 21:10:02.830814411 +0100 @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2010-2014 Junjiro R. Okajima @@ -9988,7 +10422,7 @@ diff -urN /usr/share/empty/fs/aufs/dynop.h linux/fs/aufs/dynop.h +#endif /* __AUFS_DYNOP_H__ */ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c --- /usr/share/empty/fs/aufs/export.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/export.c 2014-06-24 00:14:06.782719306 +0200 ++++ linux/fs/aufs/export.c 2014-01-30 21:10:02.830814411 +0100 @@ -0,0 +1,831 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -10821,10 +11255,424 @@ diff -urN /usr/share/empty/fs/aufs/export.c linux/fs/aufs/export.c + BUILD_BUG_ON(sizeof(u) != sizeof(int)); + atomic_set(&sbinfo->si_xigen_next, u); +} +diff -urN /usr/share/empty/fs/aufs/fhsm.c linux/fs/aufs/fhsm.c +--- /usr/share/empty/fs/aufs/fhsm.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux/fs/aufs/fhsm.c 2014-08-14 10:15:45.121942630 +0200 +@@ -0,0 +1,410 @@ ++/* ++ * Copyright (C) 2011-2014 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * File-based Hierarchy Storage Management ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++static int au_fhsm_test_jiffy(struct au_sbinfo *sbinfo, struct au_branch *br) ++{ ++ struct au_br_fhsm *bf; ++ ++ bf = br->br_fhsm; ++ MtxMustLock(&bf->bf_lock); ++ ++ return !bf->bf_readable ++ || time_after(jiffies, ++ bf->bf_jiffy + sbinfo->si_fhsm.fhsm_expire); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_fhsm_notify(struct super_block *sb, int val) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ if (au_fhsm_pid(fhsm) ++ && atomic_read(&fhsm->fhsm_readable) != -1) { ++ atomic_set(&fhsm->fhsm_readable, val); ++ if (val) ++ wake_up(&fhsm->fhsm_wqh); ++ } ++} ++ ++static int au_fhsm_stfs(struct super_block *sb, aufs_bindex_t bindex, ++ struct aufs_stfs *rstfs, int do_lock, int do_notify) ++{ ++ int err; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(au_br_rdonly(br)); ++ bf = br->br_fhsm; ++ AuDebugOn(!bf); ++ ++ if (do_lock) ++ mutex_lock(&bf->bf_lock); ++ else ++ MtxMustLock(&bf->bf_lock); ++ ++ /* sb->s_root for NFS is unreliable */ ++ err = au_br_stfs(br, &bf->bf_stfs); ++ if (unlikely(err)) { ++ AuErr1("FHSM failed (%d), b%d, ignored.\n", bindex, err); ++ goto out; ++ } ++ ++ bf->bf_jiffy = jiffies; ++ bf->bf_readable = 1; ++ if (do_notify) ++ au_fhsm_notify(sb, /*val*/1); ++ if (rstfs) ++ *rstfs = bf->bf_stfs; ++ ++out: ++ if (do_lock) ++ mutex_unlock(&bf->bf_lock); ++ au_fhsm_notify(sb, /*val*/1); ++ ++ return err; ++} ++ ++void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force) ++{ ++ int err; ++ unsigned char do_notify; ++ aufs_bindex_t bend, blower; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ AuDbg("b%d, force %d\n", bindex, force); ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ if (!au_ftest_si(sbinfo, FHSM)) ++ return; ++ ++ do_notify = 0; ++ bend = au_sbend(sb); ++ for (blower = bindex + 1; blower <= bend; blower++) { ++ br = au_sbr(sb, blower); ++ if (au_br_fhsm(br->br_perm)) { ++ do_notify = 1; ++ break; ++ } ++ } ++ if (!do_notify) ++ return; ++ ++ br = au_sbr(sb, bindex); ++ bf = br->br_fhsm; ++ AuDebugOn(!bf); ++ mutex_lock(&bf->bf_lock); ++ if (force ++ || au_fhsm_pid(fhsm) ++ || au_fhsm_test_jiffy(sbinfo, br)) ++ err = au_fhsm_stfs(sb, bindex, /*rstfs*/NULL, /*do_lock*/0, ++ /*do_notify*/1); ++ mutex_unlock(&bf->bf_lock); ++} ++ ++void au_fhsm_wrote_all(struct super_block *sb, int force) ++{ ++ aufs_bindex_t bindex, bend; ++ struct au_branch *br; ++ ++ /* exclude the bottom */ ++ bend = au_sbend(sb); ++ for (bindex = 0; bindex < bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) ++ au_fhsm_wrote(sb, bindex, force); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static unsigned int au_fhsm_poll(struct file *file, ++ struct poll_table_struct *wait) ++{ ++ unsigned int mask; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ mask = 0; ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++ poll_wait(file, &fhsm->fhsm_wqh, wait); ++ if (atomic_read(&fhsm->fhsm_readable)) ++ mask = POLLIN /* | POLLRDNORM */; ++ ++ AuTraceErr((int)mask); ++ return mask; ++} ++ ++static int au_fhsm_do_read_one(struct aufs_stbr __user *stbr, ++ struct aufs_stfs *stfs, __s16 brid) ++{ ++ int err; ++ ++ err = copy_to_user(&stbr->stfs, stfs, sizeof(*stfs)); ++ if (!err) ++ err = __put_user(brid, &stbr->brid); ++ if (unlikely(err)) ++ err = -EFAULT; ++ ++ return err; ++} ++ ++static ssize_t au_fhsm_do_read(struct super_block *sb, ++ struct aufs_stbr __user *stbr, size_t count) ++{ ++ ssize_t err; ++ int nstbr; ++ aufs_bindex_t bindex, bend; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ /* except the bottom branch */ ++ err = 0; ++ nstbr = 0; ++ bend = au_sbend(sb); ++ for (bindex = 0; !err && bindex < bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_fhsm(br->br_perm)) ++ continue; ++ ++ bf = br->br_fhsm; ++ mutex_lock(&bf->bf_lock); ++ if (bf->bf_readable) { ++ err = -EFAULT; ++ if (count >= sizeof(*stbr)) ++ err = au_fhsm_do_read_one(stbr++, &bf->bf_stfs, ++ br->br_id); ++ if (!err) { ++ bf->bf_readable = 0; ++ count -= sizeof(*stbr); ++ nstbr++; ++ } ++ } ++ mutex_unlock(&bf->bf_lock); ++ } ++ if (!err) ++ err = sizeof(*stbr) * nstbr; ++ ++ return err; ++} ++ ++static ssize_t au_fhsm_read(struct file *file, char __user *buf, size_t count, ++ loff_t *pos) ++{ ++ ssize_t err; ++ int readable; ++ aufs_bindex_t nfhsm, bindex, bend; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ struct au_branch *br; ++ struct super_block *sb; ++ ++ err = 0; ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++need_data: ++ spin_lock_irq(&fhsm->fhsm_wqh.lock); ++ if (!atomic_read(&fhsm->fhsm_readable)) { ++ if (vfsub_file_flags(file) & O_NONBLOCK) ++ err = -EAGAIN; ++ else ++ err = wait_event_interruptible_locked_irq ++ (fhsm->fhsm_wqh, ++ atomic_read(&fhsm->fhsm_readable)); ++ } ++ spin_unlock_irq(&fhsm->fhsm_wqh.lock); ++ if (unlikely(err)) ++ goto out; ++ ++ /* sb may already be dead */ ++ au_rw_read_lock(&sbinfo->si_rwsem); ++ readable = atomic_read(&fhsm->fhsm_readable); ++ if (readable > 0) { ++ sb = sbinfo->si_sb; ++ AuDebugOn(!sb); ++ /* exclude the bottom branch */ ++ nfhsm = 0; ++ bend = au_sbend(sb); ++ for (bindex = 0; bindex < bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) ++ nfhsm++; ++ } ++ err = -EMSGSIZE; ++ if (nfhsm * sizeof(struct aufs_stbr) <= count) { ++ atomic_set(&fhsm->fhsm_readable, 0); ++ err = au_fhsm_do_read(sbinfo->si_sb, (void __user *)buf, ++ count); ++ } ++ } ++ au_rw_read_unlock(&sbinfo->si_rwsem); ++ if (!readable) ++ goto need_data; ++ ++out: ++ return err; ++} ++ ++static int au_fhsm_release(struct inode *inode, struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ /* sb may already be dead */ ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock(&fhsm->fhsm_spin); ++ fhsm->fhsm_pid = 0; ++ spin_unlock(&fhsm->fhsm_spin); ++ kobject_put(&sbinfo->si_kobj); ++ ++ return 0; ++} ++ ++static const struct file_operations au_fhsm_fops = { ++ .owner = THIS_MODULE, ++ .llseek = noop_llseek, ++ .read = au_fhsm_read, ++ .poll = au_fhsm_poll, ++ .release = au_fhsm_release ++}; ++ ++int au_fhsm_fd(struct super_block *sb, int oflags) ++{ ++ int err, fd; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(oflags & ~(O_CLOEXEC | O_NONBLOCK))) ++ goto out; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock(&fhsm->fhsm_spin); ++ if (!fhsm->fhsm_pid) ++ fhsm->fhsm_pid = current->pid; ++ else ++ err = -EBUSY; ++ spin_unlock(&fhsm->fhsm_spin); ++ if (unlikely(err)) ++ goto out; ++ ++ oflags |= O_RDONLY; ++ /* oflags |= FMODE_NONOTIFY; */ ++ fd = anon_inode_getfd("[aufs_fhsm]", &au_fhsm_fops, sbinfo, oflags); ++ err = fd; ++ if (unlikely(fd < 0)) ++ goto out_pid; ++ ++ /* succeed reglardless 'fhsm' status */ ++ kobject_get(&sbinfo->si_kobj); ++ si_noflush_read_lock(sb); ++ if (au_ftest_si(sbinfo, FHSM)) ++ au_fhsm_wrote_all(sb, /*force*/0); ++ si_read_unlock(sb); ++ goto out; /* success */ ++ ++out_pid: ++ spin_lock(&fhsm->fhsm_spin); ++ fhsm->fhsm_pid = 0; ++ spin_unlock(&fhsm->fhsm_spin); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_fhsm_br_alloc(struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ br->br_fhsm = kmalloc(sizeof(*br->br_fhsm), GFP_NOFS); ++ if (br->br_fhsm) ++ au_br_fhsm_init(br->br_fhsm); ++ else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_fhsm_fin(struct super_block *sb) ++{ ++ au_fhsm_notify(sb, /*val*/-1); ++} ++ ++void au_fhsm_init(struct au_sbinfo *sbinfo) ++{ ++ struct au_fhsm *fhsm; ++ ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock_init(&fhsm->fhsm_spin); ++ init_waitqueue_head(&fhsm->fhsm_wqh); ++ atomic_set(&fhsm->fhsm_readable, 0); ++ fhsm->fhsm_expire ++ = msecs_to_jiffies(AUFS_FHSM_CACHE_DEF_SEC * MSEC_PER_SEC); ++} ++ ++void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec) ++{ ++ sbinfo->si_fhsm.fhsm_expire ++ = msecs_to_jiffies(sec * MSEC_PER_SEC); ++} ++ ++void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo) ++{ ++ unsigned int u; ++ ++ if (!au_ftest_si(sbinfo, FHSM)) ++ return; ++ ++ u = jiffies_to_msecs(sbinfo->si_fhsm.fhsm_expire) / MSEC_PER_SEC; ++ if (u != AUFS_FHSM_CACHE_DEF_SEC) ++ seq_printf(seq, ",fhsm_sec=%u", u); ++} diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c --- /usr/share/empty/fs/aufs/file.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/file.c 2014-06-24 00:14:06.782719306 +0200 -@@ -0,0 +1,711 @@ ++++ linux/fs/aufs/file.c 2014-08-14 10:16:04.515942371 +0200 +@@ -0,0 +1,835 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -10936,24 +11784,149 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c + return h_file; +} + ++static int au_cmoo(struct dentry *dentry) ++{ ++ int err, cmoo; ++ unsigned int udba; ++ struct path h_path; ++ struct au_pin pin; ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ struct inode *inode, *delegated; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ pid_t pid; ++ struct au_branch *br; ++ struct dentry *parent; ++ struct au_hinode *hdir; ++ ++ DiMustWriteLock(dentry); ++ inode = dentry->d_inode; ++ IiMustWriteLock(inode); ++ ++ err = 0; ++ if (IS_ROOT(dentry)) ++ goto out; ++ cpg.bsrc = au_dbstart(dentry); ++ if (!cpg.bsrc) ++ goto out; ++ ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ pid = au_fhsm_pid(fhsm); ++ if (pid ++ && (current->pid == pid ++ || current->real_parent->pid == pid)) ++ goto out; ++ ++ br = au_sbr(sb, cpg.bsrc); ++ cmoo = au_br_cmoo(br->br_perm); ++ if (!cmoo) ++ goto out; ++ if (!S_ISREG(inode->i_mode)) ++ cmoo &= AuBrAttr_COO_ALL; ++ if (!cmoo) ++ goto out; ++ ++ parent = dget_parent(dentry); ++ di_write_lock_parent(parent); ++ err = au_wbr_do_copyup_bu(dentry, cpg.bsrc - 1); ++ cpg.bdst = err; ++ if (unlikely(err < 0)) { ++ err = 0; /* there is no upper writable branch */ ++ goto out_dgrade; ++ } ++ AuDbg("bsrc %d, bdst %d\n", cpg.bsrc, cpg.bdst); ++ ++ /* do not respect the coo attrib for the target branch */ ++ err = au_cpup_dirs(dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_dgrade; ++ ++ di_downgrade_lock(parent, AuLock_IR); ++ udba = au_opt_udba(sb); ++ err = au_pin(&pin, dentry, cpg.bdst, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ if (unlikely(err)) ++ goto out_parent; ++ if (!(cmoo & AuBrWAttr_MOO)) ++ goto out_parent; /* success */ ++ ++ err = au_pin(&pin, dentry, cpg.bsrc, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ h_path.mnt = au_br_mnt(br); ++ h_path.dentry = au_h_dptr(dentry, cpg.bsrc); ++ hdir = au_hi(parent->d_inode, cpg.bsrc); ++ delegated = NULL; ++ err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, /*force*/1); ++ au_unpin(&pin); ++ /* todo: keep h_dentry or not? */ ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) { ++ pr_err("unlink %pd after coo failed (%d), ignored\n", ++ dentry, err); ++ err = 0; ++ } ++ goto out_parent; /* success */ ++ ++out_dgrade: ++ di_downgrade_lock(parent, AuLock_IR); ++out_parent: ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ +int au_do_open(struct file *file, int (*open)(struct file *file, int flags), + struct au_fidir *fidir) +{ + int err; + struct dentry *dentry; ++ struct au_finfo *finfo; + + err = au_finfo_init(file, fidir); + if (unlikely(err)) + goto out; + + dentry = file->f_dentry; -+ di_read_lock_child(dentry, AuLock_IR); -+ err = open(file, vfsub_file_flags(file)); ++ di_write_lock_child(dentry); ++ err = au_cmoo(dentry); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (!err) ++ err = open(file, vfsub_file_flags(file)); + di_read_unlock(dentry, AuLock_IR); + ++ finfo = au_fi(file); ++ if (!err) { ++ finfo->fi_file = file; ++ au_sphl_add(&finfo->fi_hlist, ++ &au_sbi(file->f_dentry->d_sb)->si_files); ++ } + fi_write_unlock(file); + if (unlikely(err)) { -+ au_fi(file)->fi_hdir = NULL; ++ finfo->fi_hdir = NULL; + au_finfo_fin(file); + } + @@ -11459,8 +12432,7 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c + +/* it will never be called, but necessary to support O_DIRECT */ +static ssize_t aufs_direct_IO(int rw, struct kiocb *iocb, -+ const struct iovec *iov, loff_t offset, -+ unsigned long nr_segs) ++ struct iov_iter *iter, loff_t offset) +{ BUG(); return 0; } + +/* @@ -11538,7 +12510,7 @@ diff -urN /usr/share/empty/fs/aufs/file.c linux/fs/aufs/file.c +}; diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h --- /usr/share/empty/fs/aufs/file.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/file.h 2014-06-24 00:14:06.782719306 +0200 ++++ linux/fs/aufs/file.h 2014-08-14 10:15:45.121942630 +0200 @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -11831,7 +12803,7 @@ diff -urN /usr/share/empty/fs/aufs/file.h linux/fs/aufs/file.h +#endif /* __AUFS_FILE_H__ */ diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c --- /usr/share/empty/fs/aufs/finfo.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/finfo.c 2014-06-24 00:14:06.782719306 +0200 ++++ linux/fs/aufs/finfo.c 2014-01-30 21:10:02.850815069 +0100 @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -11991,8 +12963,8 @@ diff -urN /usr/share/empty/fs/aufs/finfo.c linux/fs/aufs/finfo.c +} diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c --- /usr/share/empty/fs/aufs/f_op.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/f_op.c 2014-06-24 00:14:06.782719306 +0200 -@@ -0,0 +1,782 @@ ++++ linux/fs/aufs/f_op.c 2014-08-14 10:16:04.515942371 +0200 +@@ -0,0 +1,813 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -12051,8 +13023,6 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + au_set_fbstart(file, bindex); + au_set_h_fptr(file, bindex, h_file); + au_update_figen(file); -+ finfo->fi_file = file; -+ au_sphl_add(&finfo->fi_hlist, &au_sbi(dentry->d_sb)->si_files); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + } @@ -12178,10 +13148,12 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + size_t count, loff_t *ppos) +{ + ssize_t err; ++ blkcnt_t blks; ++ aufs_bindex_t bstart; + struct au_pin pin; + struct dentry *dentry; ++ struct inode *inode, *h_inode; + struct super_block *sb; -+ struct inode *inode; + struct file *h_file; + char __user *buf = (char __user *)ubuf; + @@ -12202,8 +13174,11 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + goto out; + } + ++ bstart = au_fbstart(file); + h_file = au_hf_top(file); + get_file(h_file); ++ h_inode = h_file->f_dentry->d_inode; ++ blks = h_inode->i_blocks; + au_unpin(&pin); + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); @@ -12212,6 +13187,9 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + ii_write_lock_child(inode); + au_cpup_attr_timesizes(inode); + inode->i_mode = file_inode(h_file)->i_mode; ++ AuDbg("blks %llu, %llu\n", (u64)blks, (u64)h_inode->i_blocks); ++ if (err > 0) ++ au_fhsm_wrote(sb, bstart, /*force*/h_inode->i_blocks > blks); + ii_write_unlock(inode); + fput(h_file); + @@ -12221,41 +13199,50 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + return err; +} + -+static ssize_t au_do_aio(struct file *h_file, int rw, struct kiocb *kio, -+ const struct iovec *iov, unsigned long nv, loff_t pos) ++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 (*func)(struct kiocb *, const struct iovec *, unsigned long, -+ loff_t); ++ ssize_t (*iter)(struct kiocb *, struct iov_iter *); ++ ssize_t (*aio)(struct kiocb *, const struct iovec *, unsigned long, ++ loff_t); + + err = security_file_permission(h_file, rw); + if (unlikely(err)) + goto out; + + err = -ENOSYS; -+ func = NULL; -+ if (rw == MAY_READ) -+ func = h_file->f_op->aio_read; -+ else if (rw == MAY_WRITE) -+ func = h_file->f_op->aio_write; -+ if (func) { -+ file = kio->ki_filp; -+ kio->ki_filp = h_file; ++ iter = NULL; ++ aio = NULL; ++ if (rw == MAY_READ) { ++ iter = h_file->f_op->read_iter; ++ aio = h_file->f_op->aio_read; ++ } else if (rw == MAY_WRITE) { ++ iter = h_file->f_op->write_iter; ++ aio = h_file->f_op->aio_write; ++ } ++ ++ file = kio->ki_filp; ++ kio->ki_filp = h_file; ++ if (iter) { + lockdep_off(); -+ err = func(kio, iov, nv, pos); ++ err = iter(kio, iov_iter); ++ lockdep_on(); ++ } else if (aio) { ++ lockdep_off(); ++ err = aio(kio, iov_iter->iov, iov_iter->nr_segs, kio->ki_pos); + lockdep_on(); -+ kio->ki_filp = file; + } else + /* currently there is no such fs */ + WARN_ON_ONCE(1); ++ kio->ki_filp = file; + +out: + return err; +} + -+static ssize_t aufs_aio_read(struct kiocb *kio, const struct iovec *iov, -+ unsigned long nv, loff_t pos) ++static ssize_t aufs_read_iter(struct kiocb *kio, struct iov_iter *iov_iter) +{ + ssize_t err; + struct file *file, *h_file; @@ -12275,7 +13262,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + di_read_unlock(dentry, AuLock_IR); + fi_read_unlock(file); + -+ err = au_do_aio(h_file, MAY_READ, kio, iov, nv, pos); ++ err = au_do_iter(h_file, MAY_READ, kio, iov_iter); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + /* update without lock, I don't think it a problem */ @@ -12287,13 +13274,14 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + return err; +} + -+static ssize_t aufs_aio_write(struct kiocb *kio, const struct iovec *iov, -+ unsigned long nv, loff_t pos) ++static ssize_t aufs_write_iter(struct kiocb *kio, struct iov_iter *iov_iter) +{ + ssize_t err; ++ blkcnt_t blks; ++ aufs_bindex_t bstart; + struct au_pin pin; + struct dentry *dentry; -+ struct inode *inode; ++ struct inode *inode, *h_inode; + struct file *file, *h_file; + struct super_block *sb; + @@ -12315,16 +13303,22 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + goto out; + } + ++ bstart = au_fbstart(file); + h_file = au_hf_top(file); + get_file(h_file); ++ h_inode = h_file->f_dentry->d_inode; ++ blks = h_inode->i_blocks; + au_unpin(&pin); + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); + -+ err = au_do_aio(h_file, MAY_WRITE, kio, iov, nv, pos); ++ err = au_do_iter(h_file, MAY_WRITE, kio, iov_iter); + ii_write_lock_child(inode); + au_cpup_attr_timesizes(inode); + inode->i_mode = file_inode(h_file)->i_mode; ++ AuDbg("blks %llu, %llu\n", (u64)blks, (u64)h_inode->i_blocks); ++ if (err > 0) ++ au_fhsm_wrote(sb, bstart, /*force*/h_inode->i_blocks > blks); + ii_write_unlock(inode); + fput(h_file); + @@ -12380,11 +13374,13 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + size_t len, unsigned int flags) +{ + ssize_t err; ++ blkcnt_t blks; ++ aufs_bindex_t bstart; + struct au_pin pin; + struct dentry *dentry; -+ struct inode *inode; -+ struct file *h_file; ++ struct inode *inode, *h_inode; + struct super_block *sb; ++ struct file *h_file; + + dentry = file->f_dentry; + sb = dentry->d_sb; @@ -12403,8 +13399,11 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + goto out; + } + ++ bstart = au_fbstart(file); + h_file = au_hf_top(file); + get_file(h_file); ++ h_inode = h_file->f_dentry->d_inode; ++ blks = h_inode->i_blocks; + au_unpin(&pin); + di_read_unlock(dentry, AuLock_IR); + fi_write_unlock(file); @@ -12413,6 +13412,9 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + ii_write_lock_child(inode); + au_cpup_attr_timesizes(inode); + inode->i_mode = file_inode(h_file)->i_mode; ++ AuDbg("blks %llu, %llu\n", (u64)blks, (u64)h_inode->i_blocks); ++ if (err > 0) ++ au_fhsm_wrote(sb, bstart, /*force*/h_inode->i_blocks > blks); + ii_write_unlock(inode); + fput(h_file); + @@ -12750,8 +13752,9 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c + + .read = aufs_read, + .write = aufs_write, -+ .aio_read = aufs_aio_read, -+ .aio_write = aufs_aio_write, ++ .read_iter = aufs_read_iter, ++ .write_iter = aufs_write_iter, ++ +#ifdef CONFIG_AUFS_POLL + .poll = aufs_poll, +#endif @@ -12777,7 +13780,7 @@ diff -urN /usr/share/empty/fs/aufs/f_op.c linux/fs/aufs/f_op.c +}; diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h --- /usr/share/empty/fs/aufs/fstype.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/fstype.h 2014-06-24 00:14:06.782719306 +0200 ++++ linux/fs/aufs/fstype.h 2014-01-30 21:10:02.850815069 +0100 @@ -0,0 +1,469 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -13250,7 +14253,7 @@ diff -urN /usr/share/empty/fs/aufs/fstype.h linux/fs/aufs/fstype.h +#endif /* __AUFS_FSTYPE_H__ */ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c --- /usr/share/empty/fs/aufs/hfsnotify.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/hfsnotify.c 2014-06-24 00:14:06.782719306 +0200 ++++ linux/fs/aufs/hfsnotify.c 2014-08-14 10:16:04.515942371 +0200 @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -13287,7 +14290,7 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c + hn_mark); + AuDbg("here\n"); + au_cache_free_hnotify(hn); -+ smp_mb__before_atomic_dec(); ++ smp_mb__before_atomic(); + if (atomic64_dec_and_test(&au_hfsn_ifree)) + wake_up(&au_hfsn_wq); +} @@ -13535,7 +14538,7 @@ diff -urN /usr/share/empty/fs/aufs/hfsnotify.c linux/fs/aufs/hfsnotify.c +}; diff -urN /usr/share/empty/fs/aufs/hfsplus.c linux/fs/aufs/hfsplus.c --- /usr/share/empty/fs/aufs/hfsplus.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/hfsplus.c 2014-06-24 00:14:06.782719306 +0200 ++++ linux/fs/aufs/hfsplus.c 2014-01-30 21:10:02.850815069 +0100 @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010-2014 Junjiro R. Okajima @@ -13595,8 +14598,8 @@ diff -urN /usr/share/empty/fs/aufs/hfsplus.c linux/fs/aufs/hfsplus.c +} diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c --- /usr/share/empty/fs/aufs/hnotify.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/hnotify.c 2014-06-24 00:14:06.782719306 +0200 -@@ -0,0 +1,713 @@ ++++ linux/fs/aufs/hnotify.c 2014-08-14 10:16:04.515942371 +0200 +@@ -0,0 +1,714 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -13916,6 +14919,7 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c +static int hn_job(struct hn_job_args *a) +{ + const unsigned int isdir = au_ftest_hnjob(a->flags, ISDIR); ++ int e; + + /* reset xino */ + if (au_ftest_hnjob(a->flags, XINO0) && a->inode) @@ -13933,11 +14937,11 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c + + /* make the generation obsolete */ + if (au_ftest_hnjob(a->flags, GEN)) { -+ int err = -1; ++ e = -1; + if (a->inode) -+ err = hn_gen_by_inode(a->h_name, a->h_nlen, a->inode, ++ e = hn_gen_by_inode(a->h_name, a->h_nlen, a->inode, + isdir); -+ if (err && a->dentry) ++ if (e && a->dentry) + hn_gen_by_name(a->dentry, isdir); + /* ignore this error */ + } @@ -14312,7 +15316,7 @@ diff -urN /usr/share/empty/fs/aufs/hnotify.c linux/fs/aufs/hnotify.c +} diff -urN /usr/share/empty/fs/aufs/iinfo.c linux/fs/aufs/iinfo.c --- /usr/share/empty/fs/aufs/iinfo.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/iinfo.c 2014-06-24 00:14:06.786052822 +0200 ++++ linux/fs/aufs/iinfo.c 2014-08-14 10:15:45.128609525 +0200 @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -14593,8 +15597,8 @@ diff -urN /usr/share/empty/fs/aufs/iinfo.c linux/fs/aufs/iinfo.c +} diff -urN /usr/share/empty/fs/aufs/inode.c linux/fs/aufs/inode.c --- /usr/share/empty/fs/aufs/inode.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/inode.c 2014-06-24 00:14:06.786052822 +0200 -@@ -0,0 +1,491 @@ ++++ linux/fs/aufs/inode.c 2014-08-14 10:15:45.128609525 +0200 +@@ -0,0 +1,492 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -15051,6 +16055,7 @@ diff -urN /usr/share/empty/fs/aufs/inode.c linux/fs/aufs/inode.c + struct inode *inode) +{ + int err; ++ struct inode *hi; + + err = au_br_rdonly(au_sbr(sb, bindex)); + @@ -15063,7 +16068,7 @@ diff -urN /usr/share/empty/fs/aufs/inode.c linux/fs/aufs/inode.c + * permission check is unnecessary since vfsub routine + * will be called later + */ -+ struct inode *hi = au_h_iptr(inode, bindex); ++ hi = au_h_iptr(inode, bindex); + if (hi) + err = IS_IMMUTABLE(hi) ? -EROFS : 0; + } @@ -15088,7 +16093,7 @@ diff -urN /usr/share/empty/fs/aufs/inode.c linux/fs/aufs/inode.c +} diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h --- /usr/share/empty/fs/aufs/inode.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/inode.h 2014-06-24 00:14:06.786052822 +0200 ++++ linux/fs/aufs/inode.h 2014-08-14 10:15:45.128609525 +0200 @@ -0,0 +1,601 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -15693,8 +16698,8 @@ diff -urN /usr/share/empty/fs/aufs/inode.h linux/fs/aufs/inode.h +#endif /* __AUFS_INODE_H__ */ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c --- /usr/share/empty/fs/aufs/ioctl.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/ioctl.c 2014-06-24 00:14:06.786052822 +0200 -@@ -0,0 +1,201 @@ ++++ linux/fs/aufs/ioctl.c 2014-08-14 10:15:45.128609525 +0200 +@@ -0,0 +1,214 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -15717,6 +16722,7 @@ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c + * plink-management and readdir in userspace. + * assist the pathconf(3) wrapper library. + * move-down ++ * File-based Hierarchical Storage Management. + */ + +#include @@ -15833,6 +16839,14 @@ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c + err = au_ibusy_ioctl(file, arg); + break; + ++ case AUFS_CTL_BRINFO: ++ err = au_brinfo_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_FHSM_FD: ++ err = au_fhsm_fd(file->f_dentry->d_sb, arg); ++ break; ++ + default: + /* do not call the lower */ + AuDbg("0x%x\n", cmd); @@ -15882,6 +16896,10 @@ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c + 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); + } @@ -15898,8 +16916,8 @@ diff -urN /usr/share/empty/fs/aufs/ioctl.c linux/fs/aufs/ioctl.c +#endif diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c --- /usr/share/empty/fs/aufs/i_op_add.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/i_op_add.c 2014-06-24 00:14:06.782719306 +0200 -@@ -0,0 +1,881 @@ ++++ linux/fs/aufs/i_op_add.c 2014-08-14 10:15:45.121942630 +0200 +@@ -0,0 +1,885 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -15935,17 +16953,19 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c + 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 = wh_dentry->d_parent->d_inode; /* 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(dir->i_sb, bindex); ++ h_path.mnt = au_sbr_mnt(sb, bindex); + err = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, + dentry); + if (unlikely(err)) @@ -15960,6 +16980,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c + if (au_ibstart(dir) == au_dbstart(dentry)) + au_cpup_attr_timesizes(dir); + dir->i_version++; ++ au_fhsm_wrote(sb, bindex, /*force*/0); + return 0; /* success */ + } + @@ -16132,7 +17153,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c +static int add_simple(struct inode *dir, struct dentry *dentry, + struct simple_arg *arg) +{ -+ int err; ++ int err, rerr; + aufs_bindex_t bstart; + unsigned char created; + struct dentry *wh_dentry, *parent; @@ -16194,7 +17215,6 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c + + /* revert */ + if (unlikely(created && err && a->h_path.dentry->d_inode)) { -+ int rerr; + /* no delegation since it is just created */ + rerr = vfsub_unlink(h_dir, &a->h_path, /*delegated*/NULL, + /*force*/0); @@ -16643,6 +17663,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c + 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: @@ -16783,8 +17805,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op_add.c linux/fs/aufs/i_op_add.c +} diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c --- /usr/share/empty/fs/aufs/i_op.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/i_op.c 2014-06-24 00:14:06.782719306 +0200 -@@ -0,0 +1,1138 @@ ++++ linux/fs/aufs/i_op.c 2014-08-14 10:15:45.121942630 +0200 +@@ -0,0 +1,1142 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -16889,7 +17911,9 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + goto out; +#endif + -+ if (!isdir || write_mask) { ++ if (!isdir ++ || write_mask ++ || au_opt_test(au_mntflags(sb), DIRPERM1)) { + err = au_busy_or_stale(); + h_inode = au_h_iptr(inode, au_ibstart(inode)); + if (unlikely(!h_inode @@ -17333,6 +18357,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + if (!err) + goto out; /* success */ + ++ au_unpin(p); ++ +out_err: + pr_err("err %d\n", err); + err = au_busy_or_stale(); @@ -17678,7 +18704,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + struct dentry *dentry, struct kstat *st) +{ + int err; -+ unsigned int mnt_flags; ++ unsigned int mnt_flags, sigen; + aufs_bindex_t bindex; + unsigned char udba_none, positive; + struct super_block *sb, *h_sb; @@ -17695,7 +18721,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c + + /* support fstat(2) */ + if (!d_unlinked(dentry) && !udba_none) { -+ unsigned int sigen = au_sigen(sb); ++ sigen = au_sigen(sb); + err = au_digen_test(dentry, sigen); + if (!err) { + di_read_lock_child(dentry, AuLock_IR); @@ -17925,8 +18951,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op.c linux/fs/aufs/i_op.c +}; diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c --- /usr/share/empty/fs/aufs/i_op_del.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/i_op_del.c 2014-06-24 00:14:06.782719306 +0200 -@@ -0,0 +1,506 @@ ++++ linux/fs/aufs/i_op_del.c 2014-08-14 10:15:45.121942630 +0200 +@@ -0,0 +1,507 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -18055,11 +19081,12 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c + * let's try heavy test. + */ + err = -EACCES; -+ if (unlikely(au_test_h_perm(h_parent->d_inode, MAY_EXEC | MAY_WRITE))) ++ if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1) ++ && au_test_h_perm(h_parent->d_inode, ++ MAY_EXEC | MAY_WRITE))) + goto out; + -+ h_latest = au_sio_lkup_one(&dentry->d_name, h_parent, -+ au_sbr(dentry->d_sb, bindex)); ++ h_latest = au_sio_lkup_one(&dentry->d_name, h_parent); + err = -EIO; + if (IS_ERR(h_latest)) + goto out; @@ -18435,8 +19462,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op_del.c linux/fs/aufs/i_op_del.c +} diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c --- /usr/share/empty/fs/aufs/i_op_ren.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/i_op_ren.c 2014-06-24 00:14:06.786052822 +0200 -@@ -0,0 +1,1032 @@ ++++ linux/fs/aufs/i_op_ren.c 2014-08-14 10:15:45.128609525 +0200 +@@ -0,0 +1,1034 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -18721,7 +19748,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c + au_hn_imtx_unlock(a->src_hinode); + if (IS_ERR(diropq)) + err = PTR_ERR(diropq); -+ dput(diropq); ++ else ++ dput(diropq); + + return err; +} @@ -18821,6 +19849,7 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c + if (a->thargs) + au_ren_del_whtmp(a); /* ignore this error */ + ++ au_fhsm_wrote(a->src_dentry->d_sb, a->btgt, /*force*/0); + err = 0; + goto out_success; + @@ -19471,8 +20500,8 @@ diff -urN /usr/share/empty/fs/aufs/i_op_ren.c linux/fs/aufs/i_op_ren.c +} diff -urN /usr/share/empty/fs/aufs/Kconfig linux/fs/aufs/Kconfig --- /usr/share/empty/fs/aufs/Kconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/Kconfig 2014-06-24 00:14:06.776052275 +0200 -@@ -0,0 +1,168 @@ ++++ linux/fs/aufs/Kconfig 2014-08-14 10:15:45.118609182 +0200 +@@ -0,0 +1,177 @@ +config AUFS_FS + tristate "Aufs (Advanced multi layered unification filesystem) support" + help @@ -19562,6 +20591,15 @@ diff -urN /usr/share/empty/fs/aufs/Kconfig linux/fs/aufs/Kconfig + /* typedef unsigned long/int __kernel_ino_t */ + /* alpha and s390x are int */ + ++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 @@ -19643,7 +20681,7 @@ diff -urN /usr/share/empty/fs/aufs/Kconfig linux/fs/aufs/Kconfig +endif diff -urN /usr/share/empty/fs/aufs/loop.c linux/fs/aufs/loop.c --- /usr/share/empty/fs/aufs/loop.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/loop.c 2014-06-24 00:14:06.786052822 +0200 ++++ linux/fs/aufs/loop.c 2014-01-30 21:10:02.850815069 +0100 @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -19792,7 +20830,7 @@ diff -urN /usr/share/empty/fs/aufs/loop.c linux/fs/aufs/loop.c +} diff -urN /usr/share/empty/fs/aufs/loop.h linux/fs/aufs/loop.h --- /usr/share/empty/fs/aufs/loop.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/loop.h 2014-06-24 00:14:06.786052822 +0200 ++++ linux/fs/aufs/loop.h 2014-01-30 21:10:02.850815069 +0100 @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -19848,7 +20886,7 @@ diff -urN /usr/share/empty/fs/aufs/loop.h linux/fs/aufs/loop.h +#endif /* __AUFS_LOOP_H__ */ diff -urN /usr/share/empty/fs/aufs/magic.mk linux/fs/aufs/magic.mk --- /usr/share/empty/fs/aufs/magic.mk 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/magic.mk 2014-06-24 00:14:06.786052822 +0200 ++++ linux/fs/aufs/magic.mk 2014-01-30 21:10:02.850815069 +0100 @@ -0,0 +1,54 @@ + +# defined in ${srctree}/fs/fuse/inode.c @@ -19906,8 +20944,8 @@ diff -urN /usr/share/empty/fs/aufs/magic.mk linux/fs/aufs/magic.mk +endif diff -urN /usr/share/empty/fs/aufs/Makefile linux/fs/aufs/Makefile --- /usr/share/empty/fs/aufs/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/Makefile 2014-06-24 00:14:06.776052275 +0200 -@@ -0,0 +1,41 @@ ++++ linux/fs/aufs/Makefile 2014-08-14 10:15:45.118609182 +0200 +@@ -0,0 +1,42 @@ + +include ${src}/magic.mk +ifeq (${CONFIG_AUFS_FS},m) @@ -19944,6 +20982,7 @@ diff -urN /usr/share/empty/fs/aufs/Makefile linux/fs/aufs/Makefile +aufs-$(CONFIG_AUFS_HNOTIFY) += hnotify.o +aufs-$(CONFIG_AUFS_HFSNOTIFY) += hfsnotify.o +aufs-$(CONFIG_AUFS_EXPORT) += export.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 @@ -19951,8 +20990,8 @@ diff -urN /usr/share/empty/fs/aufs/Makefile linux/fs/aufs/Makefile +aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c --- /usr/share/empty/fs/aufs/module.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/module.c 2014-06-24 00:14:06.786052822 +0200 -@@ -0,0 +1,202 @@ ++++ linux/fs/aufs/module.c 2014-08-14 10:15:45.128609525 +0200 +@@ -0,0 +1,210 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -20064,6 +21103,11 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c +MODULE_PARM_DESC(brs, "use /fs/aufs/si_*/brN"); +module_param_named(brs, sysaufs_brs, int, S_IRUGO); + ++/* this module parameter has no meaning when USER_NS is disabled */ ++static bool au_userns; ++MODULE_PARM_DESC(allow_userns, "allow unprivileged to mount under userns"); ++module_param_named(allow_userns, au_userns, bool, S_IRUGO); ++ +/* ---------------------------------------------------------------------- */ + +static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */ @@ -20114,9 +21158,12 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c + err = au_cache_init(); + if (unlikely(err)) + goto out_sysrq; ++ ++ aufs_fs_type.fs_flags |= au_userns ? FS_USERNS_MOUNT : 0; + err = register_filesystem(&aufs_fs_type); + if (unlikely(err)) + goto out_cache; ++ + /* since we define pr_fmt, call printk directly */ + printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n"); + goto out; /* success */ @@ -20157,7 +21204,7 @@ diff -urN /usr/share/empty/fs/aufs/module.c linux/fs/aufs/module.c +module_exit(aufs_exit); diff -urN /usr/share/empty/fs/aufs/module.h linux/fs/aufs/module.h --- /usr/share/empty/fs/aufs/module.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/module.h 2014-06-24 00:14:06.786052822 +0200 ++++ linux/fs/aufs/module.h 2014-01-30 21:10:02.850815069 +0100 @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -20265,8 +21312,8 @@ diff -urN /usr/share/empty/fs/aufs/module.h linux/fs/aufs/module.h +#endif /* __AUFS_MODULE_H__ */ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c --- /usr/share/empty/fs/aufs/mvdown.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/mvdown.c 2014-06-24 00:14:06.786052822 +0200 -@@ -0,0 +1,627 @@ ++++ linux/fs/aufs/mvdown.c 2014-08-14 10:15:45.128609525 +0200 +@@ -0,0 +1,657 @@ +/* + * Copyright (C) 2011-2014 Junjiro R. Okajima + * @@ -20308,10 +21355,10 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c +}; + +#define mvd_errno mvdown.au_errno -+#define mvd_bsrc mvdown.a[AUFS_MVDOWN_UPPER].bindex -+#define mvd_src_brid mvdown.a[AUFS_MVDOWN_UPPER].brid -+#define mvd_bdst mvdown.a[AUFS_MVDOWN_LOWER].bindex -+#define mvd_dst_brid mvdown.a[AUFS_MVDOWN_LOWER].brid ++#define mvd_bsrc mvdown.stbr[AUFS_MVDOWN_UPPER].bindex ++#define mvd_src_brid mvdown.stbr[AUFS_MVDOWN_UPPER].brid ++#define mvd_bdst mvdown.stbr[AUFS_MVDOWN_LOWER].bindex ++#define mvd_dst_brid mvdown.stbr[AUFS_MVDOWN_LOWER].brid + +#define mvd_h_src_sb info[AUFS_MVDOWN_UPPER].h_sb +#define mvd_h_src_parent info[AUFS_MVDOWN_UPPER].h_parent @@ -20330,6 +21377,42 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c + pr_err(__VA_ARGS__); \ + } while (0) + ++static int find_lower_writable(struct au_mvd_args *a) ++{ ++ struct super_block *sb; ++ aufs_bindex_t bindex, bend; ++ struct au_branch *br; ++ ++ sb = a->sb; ++ bindex = a->mvd_bsrc; ++ bend = au_sbend(sb); ++ if (a->mvdown.flags & AUFS_MVDOWN_FHSM_LOWER) ++ for (bindex++; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm) ++ && (!(au_br_sb(br)->s_flags & MS_RDONLY))) ++ return bindex; ++ } ++ else if (!(a->mvdown.flags & AUFS_MVDOWN_ROLOWER)) ++ for (bindex++; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_rdonly(br)) ++ return bindex; ++ } ++ else ++ for (bindex++; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!(au_br_sb(br)->s_flags & MS_RDONLY)) { ++ if (au_br_rdonly(br)) ++ a->mvdown.flags ++ |= AUFS_MVDOWN_ROLOWER_R; ++ return bindex; ++ } ++ } ++ ++ return -1; ++} ++ +/* make the parent dir on bdst */ +static int au_do_mkdir(const unsigned char dmsg, struct au_mvd_args *a) +{ @@ -20497,6 +21580,26 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c + return err; +} + ++/* Since mvdown succeeded, we ignore an error of this function */ ++static void au_do_stfs(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_branch *br; ++ ++ a->mvdown.flags |= AUFS_MVDOWN_STFS_FAILED; ++ br = au_sbr(a->sb, a->mvd_bsrc); ++ err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_UPPER].stfs); ++ if (!err) { ++ br = au_sbr(a->sb, a->mvd_bdst); ++ a->mvdown.stbr[AUFS_MVDOWN_LOWER].brid = br->br_id; ++ err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_LOWER].stfs); ++ } ++ if (!err) ++ a->mvdown.flags &= ~AUFS_MVDOWN_STFS_FAILED; ++ else ++ AU_MVD_PR(dmsg, "statfs failed (%d), ignored\n", err); ++} ++ +/* + * copy-down the file and unlink the bsrc file. + * - unlink the bdst whout if exist @@ -20526,6 +21629,12 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c + if (unlikely(err)) + goto out_unlock; + ++ if (find_lower_writable(a) < 0) ++ a->mvdown.flags |= AUFS_MVDOWN_BOTTOM; ++ ++ if (a->mvdown.flags & AUFS_MVDOWN_STFS) ++ au_do_stfs(dmsg, a); ++ + /* maintain internal array */ + if (!(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) { + au_set_h_dptr(a->dentry, a->mvd_bsrc, NULL); @@ -20547,36 +21656,6 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c + +/* ---------------------------------------------------------------------- */ + -+static int find_lower_writable(struct au_mvd_args *a) -+{ -+ struct super_block *sb; -+ aufs_bindex_t bindex, bend; -+ struct au_branch *br; -+ -+ sb = a->sb; -+ bindex = a->mvd_bsrc; -+ bend = au_sbend(sb); -+ if (!(a->mvdown.flags & AUFS_MVDOWN_ROLOWER)) { -+ for (bindex++; bindex <= bend; bindex++) { -+ br = au_sbr(sb, bindex); -+ if (!au_br_rdonly(br)) -+ return bindex; -+ } -+ } else { -+ for (bindex++; bindex <= bend; bindex++) { -+ br = au_sbr(sb, bindex); -+ if (!(au_br_sb(br)->s_flags & MS_RDONLY)) { -+ if (au_br_rdonly(br)) -+ a->mvdown.flags -+ |= AUFS_MVDOWN_ROLOWER_R; -+ return bindex; -+ } -+ } -+ } -+ -+ return -1; -+} -+ +/* make sure the file is idle */ +static int au_mvd_args_busy(const unsigned char dmsg, struct au_mvd_args *a) +{ @@ -20822,8 +21901,6 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c + if (unlikely(!capable(CAP_SYS_ADMIN))) + goto out; + -+ WARN_ONCE(1, "move-down is still testing...\n"); -+ + err = -ENOMEM; + args = kmalloc(sizeof(*args), GFP_NOFS); + if (unlikely(!args)) @@ -20896,8 +21973,8 @@ diff -urN /usr/share/empty/fs/aufs/mvdown.c linux/fs/aufs/mvdown.c +} diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c --- /usr/share/empty/fs/aufs/opts.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/opts.c 2014-06-24 00:14:06.786052822 +0200 -@@ -0,0 +1,1701 @@ ++++ linux/fs/aufs/opts.c 2014-08-14 10:15:45.128609525 +0200 +@@ -0,0 +1,1790 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -20945,9 +22022,11 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + Opt_diropq_a, Opt_diropq_w, + Opt_warn_perm, Opt_nowarn_perm, + Opt_wbr_copyup, Opt_wbr_create, ++ Opt_fhsm_sec, + Opt_refrof, Opt_norefrof, + Opt_verbose, Opt_noverbose, + Opt_sum, Opt_nosum, Opt_wsum, ++ Opt_dirperm1, Opt_nodirperm1, + Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err +}; + @@ -21001,6 +22080,12 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + {Opt_dio, "dio"}, + {Opt_nodio, "nodio"}, + ++#ifdef CONFIG_AUFS_FHSM ++ {Opt_fhsm_sec, "fhsm_sec=%d"}, ++#else ++ {Opt_ignore_silent, "fhsm_sec=%d"}, ++#endif ++ + {Opt_diropq_a, "diropq=always"}, + {Opt_diropq_a, "diropq=a"}, + {Opt_diropq_w, "diropq=whiteouted"}, @@ -21010,9 +22095,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + {Opt_nowarn_perm, "nowarn_perm"}, + + /* keep them temporary */ -+ {Opt_ignore_silent, "coo=%s"}, + {Opt_ignore_silent, "nodlgt"}, -+ {Opt_ignore_silent, "nodirperm1"}, + {Opt_ignore_silent, "clean_plink"}, + +#ifdef CONFIG_AUFS_SHWH @@ -21020,6 +22103,9 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c +#endif + {Opt_noshwh, "noshwh"}, + ++ {Opt_dirperm1, "dirperm1"}, ++ {Opt_nodirperm1, "nodirperm1"}, ++ + {Opt_rendir, "rendir=%d"}, + + {Opt_refrof, "refrof"}, @@ -21065,17 +22151,37 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + +/* ---------------------------------------------------------------------- */ + -+static const char *au_parser_pattern(int val, struct match_token *token) ++static const char *au_parser_pattern(int val, match_table_t tbl) +{ -+ while (token->pattern) { -+ if (token->token == val) -+ return token->pattern; -+ token++; ++ struct match_token *p; ++ ++ p = tbl; ++ while (p->pattern) { ++ if (p->token == val) ++ return p->pattern; ++ p++; + } + BUG(); + return "??"; +} + ++static const char *au_optstr(int *val, match_table_t tbl) ++{ ++ struct match_token *p; ++ int v; ++ ++ v = *val; ++ p = tbl; ++ while (p->token) { ++ if ((v & p->token) == p->token) { ++ *val &= ~p->token; ++ return p->pattern; ++ } ++ p++; ++ } ++ return NULL; ++} ++ +/* ---------------------------------------------------------------------- */ + +static match_table_t brperm = { @@ -21086,16 +22192,22 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c +}; + +static match_table_t brattr = { ++ /* general */ ++ {AuBrAttr_COO_REG, AUFS_BRATTR_COO_REG}, ++ {AuBrAttr_COO_ALL, AUFS_BRATTR_COO_ALL}, + {AuBrAttr_UNPIN, AUFS_BRATTR_UNPIN}, ++ {AuBrAttr_FHSM, AUFS_BRATTR_FHSM}, ++ ++ /* ro/rr branch */ + {AuBrRAttr_WH, AUFS_BRRATTR_WH}, ++ ++ /* rw branch */ ++ {AuBrWAttr_MOO, AUFS_BRWATTR_MOO}, + {AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH}, ++ + {0, NULL} +}; + -+#define AuBrStr_LONGEST AUFS_BRPERM_RW \ -+ "+" AUFS_BRATTR_UNPIN \ -+ "+" AUFS_BRWATTR_NLWH -+ +static int br_attr_val(char *str, match_table_t table, substring_t args[]) +{ + int attr, v; @@ -21107,9 +22219,11 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + if (p) + *p = 0; + v = match_token(str, table, args); -+ if (v) ++ if (v) { ++ if (v & AuBrAttr_CMOO_Mask) ++ attr &= ~AuBrAttr_CMOO_Mask; + attr |= v; -+ else { ++ } else { + if (p) + *p = '+'; + pr_warn("ignored branch attribute %s\n", str); @@ -21122,11 +22236,43 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + return attr; +} + ++static int au_do_optstr_br_attr(au_br_perm_str_t *str, int perm) ++{ ++ int sz; ++ const char *p; ++ char *q; ++ ++ sz = 0; ++ q = str->a; ++ *q = 0; ++ p = au_optstr(&perm, brattr); ++ if (p) { ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ } else ++ goto out; ++ ++ do { ++ p = au_optstr(&perm, brattr); ++ if (p) { ++ *q++ = '+'; ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ } ++ } while (p); ++ ++out: ++ return sz; ++} ++ +static int noinline_for_stack br_perm_val(char *perm) +{ -+ int val; -+ char *p, *q; ++ int val, bad, sz; ++ char *p; + substring_t args[MAX_OPT_ARGS]; ++ au_br_perm_str_t attr; + + p = strchr(perm, '+'); + if (p) @@ -21142,83 +22288,51 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + if (!p) + goto out; + -+ p++; -+ while (1) { -+ q = strchr(p, '+'); -+ if (q) -+ *q = 0; -+ val |= br_attr_val(p, brattr, args); -+ if (q) { -+ *q = '+'; -+ p = q + 1; -+ } else -+ break; -+ } ++ val |= br_attr_val(p + 1, brattr, args); ++ ++ bad = 0; + switch (val & AuBrPerm_Mask) { + case AuBrPerm_RO: + case AuBrPerm_RR: -+ if (unlikely(val & AuBrWAttr_NoLinkWH)) { -+ pr_warn("ignored branch attribute %s\n", -+ AUFS_BRWATTR_NLWH); -+ val &= ~AuBrWAttr_NoLinkWH; -+ } ++ bad = val & AuBrWAttr_Mask; ++ val &= ~AuBrWAttr_Mask; + break; + case AuBrPerm_RW: -+ if (unlikely(val & AuBrRAttr_WH)) { -+ pr_warn("ignored branch attribute %s\n", -+ AUFS_BRRATTR_WH); -+ val &= ~AuBrRAttr_WH; -+ } ++ bad = val & AuBrRAttr_Mask; ++ val &= ~AuBrRAttr_Mask; + break; + } ++ if (unlikely(bad)) { ++ sz = au_do_optstr_br_attr(&attr, bad); ++ AuDebugOn(!sz); ++ pr_warn("ignored branch attribute %s\n", attr.a); ++ } + +out: + return val; +} + -+/* Caller should free the return value */ -+char *au_optstr_br_perm(int brperm) ++void au_optstr_br_perm(au_br_perm_str_t *str, int perm) +{ -+ char *p, a[sizeof(AuBrStr_LONGEST)]; ++ au_br_perm_str_t attr; ++ const char *p; ++ char *q; + int sz; + -+#define SetPerm(str) do { \ -+ sz = sizeof(str); \ -+ memcpy(a, str, sz); \ -+ p = a + sz - 1; \ -+ } while (0) -+ -+#define AppendAttr(flag, str) do { \ -+ if (brperm & flag) { \ -+ sz = sizeof(str); \ -+ *p++ = '+'; \ -+ memcpy(p, str, sz); \ -+ p += sz - 1; \ -+ } \ -+ } while (0) ++ q = str->a; ++ p = au_optstr(&perm, brperm); ++ AuDebugOn(!p || !*p); ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; + -+ switch (brperm & AuBrPerm_Mask) { -+ case AuBrPerm_RO: -+ SetPerm(AUFS_BRPERM_RO); -+ break; -+ case AuBrPerm_RR: -+ SetPerm(AUFS_BRPERM_RR); -+ break; -+ case AuBrPerm_RW: -+ SetPerm(AUFS_BRPERM_RW); -+ break; -+ default: -+ AuDebugOn(1); ++ sz = au_do_optstr_br_attr(&attr, perm); ++ if (sz) { ++ *q++ = '+'; ++ memcpy(q, attr.a, sz + 1); + } + -+ AppendAttr(AuBrAttr_UNPIN, AUFS_BRATTR_UNPIN); -+ AppendAttr(AuBrRAttr_WH, AUFS_BRRATTR_WH); -+ AppendAttr(AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH); -+ -+ AuDebugOn(strlen(a) >= sizeof(a)); -+ return kstrdup(a, GFP_NOFS); -+#undef SetPerm -+#undef AppendAttr ++ AuDebugOn(strlen(str->a) >= sizeof(str->a)); +} + +/* ---------------------------------------------------------------------- */ @@ -21244,7 +22358,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + +const char *au_optstr_udba(int udba) +{ -+ return au_parser_pattern(udba, (void *)udbalevel); ++ return au_parser_pattern(udba, udbalevel); +} + +/* ---------------------------------------------------------------------- */ @@ -21366,7 +22480,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + +const char *au_optstr_wbr_create(int wbr_create) +{ -+ return au_parser_pattern(wbr_create, (void *)au_wbr_create_policy); ++ return au_parser_pattern(wbr_create, au_wbr_create_policy); +} + +static match_table_t au_wbr_copyup_policy = { @@ -21388,7 +22502,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + +const char *au_optstr_wbr_copyup(int wbr_copyup) +{ -+ return au_parser_pattern(wbr_copyup, (void *)au_wbr_copyup_policy); ++ return au_parser_pattern(wbr_copyup, au_wbr_copyup_policy); +} + +/* ---------------------------------------------------------------------- */ @@ -21491,6 +22605,12 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + case Opt_noshwh: + AuLabel(noshwh); + break; ++ case Opt_dirperm1: ++ AuLabel(dirperm1); ++ break; ++ case Opt_nodirperm1: ++ AuLabel(nodirperm1); ++ break; + case Opt_plink: + AuLabel(plink); + break; @@ -21568,6 +22688,9 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + AuDbg("copyup %d, %s\n", opt->wbr_copyup, + au_optstr_wbr_copyup(opt->wbr_copyup)); + break; ++ case Opt_fhsm_sec: ++ AuDbg("fhsm_sec %u\n", opt->fhsm_second); ++ break; + default: + BUG(); + } @@ -21994,6 +23117,8 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + case Opt_notrunc_xib: + case Opt_shwh: + case Opt_noshwh: ++ case Opt_dirperm1: ++ case Opt_nodirperm1: + case Opt_plink: + case Opt_noplink: + case Opt_list_plink: @@ -22044,6 +23169,20 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + pr_err("wrong value, %s\n", opt_str); + break; + ++ case Opt_fhsm_sec: ++ if (unlikely(match_int(&a->args[0], &n) ++ || n < 0)) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ if (sysaufs_brs) { ++ opt->fhsm_second = n; ++ opt->type = token; ++ } else ++ pr_warn("ignored %s\n", opt_str); ++ err = 0; ++ break; ++ + case Opt_ignore: + pr_warn("ignored %s\n", opt_str); + /*FALLTHROUGH*/ @@ -22160,6 +23299,10 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + au_fset_opts(opts->flags, REFRESH_DYAOP); + break; + ++ case Opt_fhsm_sec: ++ au_fhsm_set(sbinfo, opt->fhsm_second); ++ break; ++ + case Opt_diropq_a: + au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ); + break; @@ -22235,6 +23378,13 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + au_opt_clr(sbinfo->si_mntflags, SHWH); + break; + ++ case Opt_dirperm1: ++ au_opt_set(sbinfo->si_mntflags, DIRPERM1); ++ break; ++ case Opt_nodirperm1: ++ au_opt_clr(sbinfo->si_mntflags, DIRPERM1); ++ break; ++ + case Opt_trunc_xino: + au_opt_set(sbinfo->si_mntflags, TRUNC_XINO); + break; @@ -22366,7 +23516,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c +int au_opts_verify(struct super_block *sb, unsigned long sb_flags, + unsigned int pending) +{ -+ int err; ++ int err, fhsm; + aufs_bindex_t bindex, bend; + unsigned char do_plink, skip, do_free; + struct au_branch *br; @@ -22392,7 +23542,12 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + && !au_opt_test(sbinfo->si_mntflags, XINO)) + pr_warn("udba=*notify requires xino\n"); + ++ if (au_opt_test(sbinfo->si_mntflags, DIRPERM1)) ++ pr_warn("dirperm1 breaks the protection" ++ " by the permission bits on the lower branch\n"); ++ + err = 0; ++ fhsm = 0; + root = sb->s_root; + dir = root->d_inode; + do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK); @@ -22435,6 +23590,11 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + if (wbr) + wbr_wh_read_unlock(wbr); + ++ if (au_br_fhsm(br->br_perm)) { ++ fhsm++; ++ AuDebugOn(!br->br_fhsm); ++ } ++ + if (skip) + continue; + @@ -22453,6 +23613,11 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + } + } + ++ if (fhsm >= 2) ++ au_fset_si(sbinfo, FHSM); ++ else ++ au_fclr_si(sbinfo, FHSM); ++ + return err; +} + @@ -22465,6 +23630,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + struct au_opt_xino *opt_xino, xino; + struct au_sbinfo *sbinfo; + struct au_branch *br; ++ struct inode *dir; + + SiMustWriteLock(sb); + @@ -22538,7 +23704,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c + /* go on even if err */ + } + if (au_opt_test(tmp, UDBA_HNOTIFY)) { -+ struct inode *dir = sb->s_root->d_inode; ++ dir = sb->s_root->d_inode; + au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO); + } + @@ -22601,8 +23767,8 @@ diff -urN /usr/share/empty/fs/aufs/opts.c linux/fs/aufs/opts.c +} diff -urN /usr/share/empty/fs/aufs/opts.h linux/fs/aufs/opts.h --- /usr/share/empty/fs/aufs/opts.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/opts.h 2014-06-24 00:14:06.786052822 +0200 -@@ -0,0 +1,210 @@ ++++ linux/fs/aufs/opts.h 2014-08-14 10:15:45.128609525 +0200 +@@ -0,0 +1,213 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -22630,6 +23796,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.h linux/fs/aufs/opts.h +#ifdef __KERNEL__ + +#include ++#include "branch.h" + +struct file; +struct super_block; @@ -22645,7 +23812,8 @@ diff -urN /usr/share/empty/fs/aufs/opts.h linux/fs/aufs/opts.h +#define AuOpt_UDBA_HNOTIFY (1 << 4) +#define AuOpt_SHWH (1 << 5) /* show whiteout */ +#define AuOpt_PLINK (1 << 6) /* pseudo-link */ -+#define AuOpt_DIRPERM1 (1 << 7) /* unimplemented */ ++#define AuOpt_DIRPERM1 (1 << 7) /* ignore the lower dir's perm ++ bits */ +#define AuOpt_REFROF (1 << 8) /* unimplemented */ +#define AuOpt_ALWAYS_DIROPQ (1 << 9) /* policy to creating diropq */ +#define AuOpt_SUM (1 << 10) /* summation for statfs(2) */ @@ -22770,6 +23938,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.h linux/fs/aufs/opts.h + int udba; + struct au_opt_wbr_create wbr_create; + int wbr_copyup; ++ unsigned int fhsm_second; + }; +}; + @@ -22795,7 +23964,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.h linux/fs/aufs/opts.h + +/* ---------------------------------------------------------------------- */ + -+char *au_optstr_br_perm(int brperm); ++void au_optstr_br_perm(au_br_perm_str_t *str, int perm); +const char *au_optstr_udba(int udba); +const char *au_optstr_wbr_copyup(int wbr_copyup); +const char *au_optstr_wbr_create(int wbr_create); @@ -22815,7 +23984,7 @@ diff -urN /usr/share/empty/fs/aufs/opts.h linux/fs/aufs/opts.h +#endif /* __AUFS_OPTS_H__ */ diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c --- /usr/share/empty/fs/aufs/plink.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/plink.c 2014-06-24 00:14:06.786052822 +0200 ++++ linux/fs/aufs/plink.c 2014-01-30 21:10:02.857481956 +0100 @@ -0,0 +1,532 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -23351,7 +24520,7 @@ diff -urN /usr/share/empty/fs/aufs/plink.c linux/fs/aufs/plink.c +} diff -urN /usr/share/empty/fs/aufs/poll.c linux/fs/aufs/poll.c --- /usr/share/empty/fs/aufs/poll.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/poll.c 2014-06-24 00:14:06.786052822 +0200 ++++ linux/fs/aufs/poll.c 2014-01-30 21:10:02.857481956 +0100 @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -23410,7 +24579,7 @@ diff -urN /usr/share/empty/fs/aufs/poll.c linux/fs/aufs/poll.c +} diff -urN /usr/share/empty/fs/aufs/procfs.c linux/fs/aufs/procfs.c --- /usr/share/empty/fs/aufs/procfs.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/procfs.c 2014-06-24 00:14:06.786052822 +0200 ++++ linux/fs/aufs/procfs.c 2014-01-30 21:10:02.857481956 +0100 @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2010-2014 Junjiro R. Okajima @@ -23583,7 +24752,7 @@ diff -urN /usr/share/empty/fs/aufs/procfs.c linux/fs/aufs/procfs.c +} diff -urN /usr/share/empty/fs/aufs/rdu.c linux/fs/aufs/rdu.c --- /usr/share/empty/fs/aufs/rdu.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/rdu.c 2014-06-24 00:14:06.786052822 +0200 ++++ linux/fs/aufs/rdu.c 2014-01-30 21:10:02.857481956 +0100 @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -23975,8 +25144,8 @@ diff -urN /usr/share/empty/fs/aufs/rdu.c linux/fs/aufs/rdu.c +#endif diff -urN /usr/share/empty/fs/aufs/rwsem.h linux/fs/aufs/rwsem.h --- /usr/share/empty/fs/aufs/rwsem.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/rwsem.h 2014-06-24 00:14:06.789386337 +0200 -@@ -0,0 +1,187 @@ ++++ linux/fs/aufs/rwsem.h 2014-08-14 10:15:45.128609525 +0200 +@@ -0,0 +1,191 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -24115,7 +25284,9 @@ diff -urN /usr/share/empty/fs/aufs/rwsem.h linux/fs/aufs/rwsem.h +/* why is not _nested version defined */ +static inline int au_rw_read_trylock(struct au_rwsem *rw) +{ -+ int ret = down_read_trylock(&rw->rwsem); ++ int ret; ++ ++ ret = down_read_trylock(&rw->rwsem); + if (ret) + AuDbgRcntInc(rw); + return ret; @@ -24123,7 +25294,9 @@ diff -urN /usr/share/empty/fs/aufs/rwsem.h linux/fs/aufs/rwsem.h + +static inline int au_rw_write_trylock(struct au_rwsem *rw) +{ -+ int ret = down_write_trylock(&rw->rwsem); ++ int ret; ++ ++ ret = down_write_trylock(&rw->rwsem); + if (ret) + AuDbgWcntInc(rw); + return ret; @@ -24166,8 +25339,8 @@ diff -urN /usr/share/empty/fs/aufs/rwsem.h linux/fs/aufs/rwsem.h +#endif /* __AUFS_RWSEM_H__ */ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c --- /usr/share/empty/fs/aufs/sbinfo.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/sbinfo.c 2014-06-24 00:14:06.789386337 +0200 -@@ -0,0 +1,351 @@ ++++ linux/fs/aufs/sbinfo.c 2014-08-14 10:15:45.128609525 +0200 +@@ -0,0 +1,353 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -24267,6 +25440,8 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c + sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup; + sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create; + ++ au_fhsm_init(sbinfo); ++ + sbinfo->si_mntflags = au_opts_plink(AuOpt_Def); + + sbinfo->si_xino_jiffy = jiffies; @@ -24521,7 +25696,7 @@ diff -urN /usr/share/empty/fs/aufs/sbinfo.c linux/fs/aufs/sbinfo.c +} diff -urN /usr/share/empty/fs/aufs/spl.h linux/fs/aufs/spl.h --- /usr/share/empty/fs/aufs/spl.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/spl.h 2014-06-24 00:14:06.789386337 +0200 ++++ linux/fs/aufs/spl.h 2014-01-30 21:10:02.857481956 +0100 @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -24636,8 +25811,8 @@ diff -urN /usr/share/empty/fs/aufs/spl.h linux/fs/aufs/spl.h +#endif /* __AUFS_SPL_H__ */ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c --- /usr/share/empty/fs/aufs/super.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/super.c 2014-06-24 00:14:06.789386337 +0200 -@@ -0,0 +1,1001 @@ ++++ linux/fs/aufs/super.c 2014-08-14 10:15:45.131942973 +0200 +@@ -0,0 +1,1004 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -24736,7 +25911,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + struct path path; + struct au_hdentry *hdp; + struct au_branch *br; -+ char *perm; ++ au_br_perm_str_t perm; + + err = 0; + bend = au_sbend(sb); @@ -24747,14 +25922,10 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + path.dentry = hdp[bindex].hd_dentry; + err = au_seq_path(seq, &path); + if (err > 0) { -+ perm = au_optstr_br_perm(br->br_perm); -+ if (perm) { -+ err = seq_printf(seq, "=%s", perm); -+ kfree(perm); -+ if (err == -1) -+ err = -E2BIG; -+ } else -+ err = -ENOMEM; ++ au_optstr_br_perm(&perm, br->br_perm); ++ err = seq_printf(seq, "=%s", perm.a); ++ if (err == -1) ++ err = -E2BIG; + } + if (!err && bindex != bend) + err = seq_putc(seq, ':'); @@ -24900,7 +26071,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + AuBool(SHWH, shwh); + AuBool(PLINK, plink); + AuBool(DIO, dio); -+ /* AuBool(DIRPERM1, dirperm1); */ ++ AuBool(DIRPERM1, dirperm1); + /* AuBool(REFROF, refrof); */ + + v = sbinfo->si_wbr_create; @@ -24923,6 +26094,8 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + AuUInt(RDBLK, rdblk, sbinfo->si_rdblk); + AuUInt(RDHASH, rdhash, sbinfo->si_rdhash); + ++ au_fhsm_show(m, sbinfo); ++ + AuBool(SUM, sum); + /* AuBool(SUM_W, wsum); */ + AuBool(WARN_PERM, warn_perm); @@ -25124,7 +26297,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c +void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, void *arg) +{ + void *array; -+ unsigned long long n; ++ unsigned long long n, sz; + + array = NULL; + n = 0; @@ -25137,9 +26310,10 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + goto out; + } + -+ array = kmalloc(sizeof(array) * *hint, GFP_NOFS); ++ sz = sizeof(array) * *hint; ++ array = kzalloc(sz, GFP_NOFS); + if (unlikely(!array)) -+ array = vmalloc(sizeof(array) * *hint); ++ array = vzalloc(sz); + if (unlikely(!array)) { + array = ERR_PTR(-ENOMEM); + goto out; @@ -25306,6 +26480,8 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + sigen = au_sigen(sb); + for (ull = 0; ull < max; ull++) { + inode = array[ull]; ++ if (unlikely(!inode)) ++ break; + if (au_iigen(inode, NULL) != sigen) { + ii_write_lock_child(inode); + e = au_refresh_hinode_self(inode); @@ -25439,6 +26615,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + au_dy_arefresh(do_dx); + } + ++ au_fhsm_wrote_all(sb, /*force*/1); /* ?? */ + aufs_write_unlock(root); + +out_mtx: @@ -25614,6 +26791,7 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c + if (sbinfo) { + au_sbilist_del(sb); + aufs_write_lock(sb->s_root); ++ au_fhsm_fin(sb); + if (sbinfo->si_wbr_create_ops->fin) + sbinfo->si_wbr_create_ops->fin(sb); + if (au_opt_test(sbinfo->si_mntflags, UDBA_HNOTIFY)) { @@ -25641,8 +26819,8 @@ diff -urN /usr/share/empty/fs/aufs/super.c linux/fs/aufs/super.c +}; diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h --- /usr/share/empty/fs/aufs/super.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/super.h 2014-06-24 00:14:06.789386337 +0200 -@@ -0,0 +1,571 @@ ++++ linux/fs/aufs/super.h 2014-08-14 10:15:45.131942973 +0200 +@@ -0,0 +1,642 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -25720,6 +26898,20 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + return ino % AuPlink_NHASH; +} + ++/* File-based Hierarchical Storage Management */ ++struct au_fhsm { ++#ifdef CONFIG_AUFS_FHSM ++ /* allow only one process who can receive the notification */ ++ spinlock_t fhsm_spin; ++ pid_t fhsm_pid; ++ wait_queue_head_t fhsm_wqh; ++ atomic_t fhsm_readable; ++ ++ /* only this is protected by si_rwsem */ ++ unsigned long fhsm_expire; ++#endif ++}; ++ +struct au_branch; +struct au_sbinfo { + /* nowait tasks in the system-wide workqueue */ @@ -25769,6 +26961,9 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + /* most free space */ + struct au_wbr_mfs si_wbr_mfs; + ++ /* File-based Hierarchical Storage Management */ ++ struct au_fhsm si_fhsm; ++ + /* mount flags */ + /* include/asm-ia64/siginfo.h defines a macro named si_flags */ + unsigned int si_mntflags; @@ -25852,6 +27047,14 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + * if it is false, refreshing dirs at access time is unnecesary + */ +#define AuSi_FAILED_REFRESH_DIR 1 ++ ++#define AuSi_FHSM (1 << 1) /* fhsm is active now */ ++ ++#ifndef CONFIG_AUFS_FHSM ++#undef AuSi_FHSM ++#define AuSi_FHSM 0 ++#endif ++ +static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi, + unsigned int flag) +{ @@ -25929,10 +27132,46 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h +extern struct au_wbr_create_operations au_wbr_create_ops[]; +int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst); +int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex); ++int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t bstart); + +/* mvdown.c */ +int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *arg); + ++#ifdef CONFIG_AUFS_FHSM ++/* fhsm.c */ ++ ++static inline pid_t au_fhsm_pid(struct au_fhsm *fhsm) ++{ ++ pid_t pid; ++ ++ spin_lock(&fhsm->fhsm_spin); ++ pid = fhsm->fhsm_pid; ++ spin_unlock(&fhsm->fhsm_spin); ++ ++ return pid; ++} ++ ++void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force); ++void au_fhsm_wrote_all(struct super_block *sb, int force); ++int au_fhsm_fd(struct super_block *sb, int oflags); ++int au_fhsm_br_alloc(struct au_branch *br); ++void au_fhsm_fin(struct super_block *sb); ++void au_fhsm_init(struct au_sbinfo *sbinfo); ++void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec); ++void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo); ++#else ++AuStubVoid(au_fhsm_wrote, struct super_block *sb, aufs_bindex_t bindex, ++ int force) ++AuStubVoid(au_fhsm_wrote_all, struct super_block *sb, int force) ++AuStub(int, au_fhsm_fd, return -EOPNOTSUPP, struct super_block *sb, int oflags) ++AuStub(pid_t, au_fhsm_pid, return 0, struct au_fhsm *fhsm); ++AuStubInt0(au_fhsm_br_alloc, struct au_branch *br); ++AuStubVoid(au_fhsm_fin, struct super_block *sb) ++AuStubVoid(au_fhsm_init, struct au_sbinfo *sbinfo) ++AuStubVoid(au_fhsm_set, struct au_sbinfo *sbinfo, unsigned int sec) ++AuStubVoid(au_fhsm_show, struct seq_file *seq, struct au_sbinfo *sbinfo) ++#endif ++ +/* ---------------------------------------------------------------------- */ + +static inline struct au_sbinfo *au_sbi(struct super_block *sb) @@ -26044,7 +27283,9 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + +static inline int si_pid_test(struct super_block *sb) +{ -+ pid_t bit = si_pid_bit(); ++ pid_t bit; ++ ++ bit = si_pid_bit(); + if (bit < PID_MAX_DEFAULT) + return test_bit(bit, au_sbi(sb)->au_si_pid.bitmap); + else @@ -26053,7 +27294,9 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + +static inline void si_pid_set(struct super_block *sb) +{ -+ pid_t bit = si_pid_bit(); ++ pid_t bit; ++ ++ bit = si_pid_bit(); + if (bit < PID_MAX_DEFAULT) { + AuDebugOn(test_bit(bit, au_sbi(sb)->au_si_pid.bitmap)); + set_bit(bit, au_sbi(sb)->au_si_pid.bitmap); @@ -26064,7 +27307,9 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + +static inline void si_pid_clr(struct super_block *sb) +{ -+ pid_t bit = si_pid_bit(); ++ pid_t bit; ++ ++ bit = si_pid_bit(); + if (bit < PID_MAX_DEFAULT) { + AuDebugOn(!test_bit(bit, au_sbi(sb)->au_si_pid.bitmap)); + clear_bit(bit, au_sbi(sb)->au_si_pid.bitmap); @@ -26094,7 +27339,9 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + +static inline int si_noflush_read_trylock(struct super_block *sb) +{ -+ int locked = __si_read_trylock(sb); ++ int locked; ++ ++ locked = __si_read_trylock(sb); + if (locked) + si_pid_set(sb); + return locked; @@ -26108,7 +27355,9 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h + +static inline int si_noflush_write_trylock(struct super_block *sb) +{ -+ int locked = __si_write_trylock(sb); ++ int locked; ++ ++ locked = __si_write_trylock(sb); + if (locked) + si_pid_set(sb); + return locked; @@ -26216,7 +27465,7 @@ diff -urN /usr/share/empty/fs/aufs/super.h linux/fs/aufs/super.h +#endif /* __AUFS_SUPER_H__ */ diff -urN /usr/share/empty/fs/aufs/sysaufs.c linux/fs/aufs/sysaufs.c --- /usr/share/empty/fs/aufs/sysaufs.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/sysaufs.c 2014-06-24 00:14:06.789386337 +0200 ++++ linux/fs/aufs/sysaufs.c 2014-01-30 21:10:02.857481956 +0100 @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -26324,8 +27573,8 @@ diff -urN /usr/share/empty/fs/aufs/sysaufs.c linux/fs/aufs/sysaufs.c +} diff -urN /usr/share/empty/fs/aufs/sysaufs.h linux/fs/aufs/sysaufs.h --- /usr/share/empty/fs/aufs/sysaufs.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/sysaufs.h 2014-06-24 00:14:06.789386337 +0200 -@@ -0,0 +1,103 @@ ++++ linux/fs/aufs/sysaufs.h 2014-08-14 10:15:45.131942973 +0200 +@@ -0,0 +1,107 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -26397,6 +27646,10 @@ diff -urN /usr/share/empty/fs/aufs/sysaufs.h linux/fs/aufs/sysaufs.h +int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb); +ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, + char *buf); ++long au_brinfo_ioctl(struct file *file, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_brinfo_compat_ioctl(struct file *file, unsigned long arg); ++#endif + +void sysaufs_br_init(struct au_branch *br); +void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); @@ -26431,8 +27684,8 @@ diff -urN /usr/share/empty/fs/aufs/sysaufs.h linux/fs/aufs/sysaufs.h +#endif /* __SYSAUFS_H__ */ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c --- /usr/share/empty/fs/aufs/sysfs.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/sysfs.c 2014-06-24 00:14:06.789386337 +0200 -@@ -0,0 +1,296 @@ ++++ linux/fs/aufs/sysfs.c 2014-08-14 10:15:45.131942973 +0200 +@@ -0,0 +1,372 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -26454,6 +27707,7 @@ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c + * sysfs interface + */ + ++#include +#include +#include "aufs.h" + @@ -26518,7 +27772,7 @@ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c + struct path path; + struct dentry *root; + struct au_branch *br; -+ char *perm; ++ au_br_perm_str_t perm; + + AuDbg("b%d\n", bindex); + @@ -26532,23 +27786,16 @@ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c + path.mnt = au_br_mnt(br); + path.dentry = au_h_dptr(root, bindex); + au_seq_path(seq, &path); -+ di_read_unlock(root, !AuLock_IR); -+ perm = au_optstr_br_perm(br->br_perm); -+ if (perm) { -+ err = seq_printf(seq, "=%s\n", perm); -+ kfree(perm); -+ if (err == -1) -+ err = -E2BIG; -+ } else -+ err = -ENOMEM; ++ au_optstr_br_perm(&perm, br->br_perm); ++ err = seq_printf(seq, "=%s\n", perm.a); + break; + case AuBrSysfs_BRID: + err = seq_printf(seq, "%d\n", br->br_id); -+ di_read_unlock(root, !AuLock_IR); -+ if (err == -1) -+ err = -E2BIG; + break; + } ++ di_read_unlock(root, !AuLock_IR); ++ if (err == -1) ++ err = -E2BIG; + + return err; +} @@ -26657,6 +27904,88 @@ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c + +/* ---------------------------------------------------------------------- */ + ++static int au_brinfo(struct super_block *sb, union aufs_brinfo __user *arg) ++{ ++ int err; ++ int16_t brid; ++ aufs_bindex_t bindex, bend; ++ size_t sz; ++ char *buf; ++ struct seq_file *seq; ++ struct au_branch *br; ++ ++ si_read_lock(sb, AuLock_FLUSH); ++ bend = au_sbend(sb); ++ err = bend + 1; ++ if (!arg) ++ goto out; ++ ++ err = -ENOMEM; ++ buf = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!buf)) ++ goto out; ++ ++ seq = au_seq(buf, PAGE_SIZE); ++ err = PTR_ERR(seq); ++ if (IS_ERR(seq)) ++ goto out_buf; ++ ++ sz = sizeof(*arg) - offsetof(union aufs_brinfo, path); ++ for (bindex = 0; bindex <= bend; bindex++, arg++) { ++ err = !access_ok(VERIFY_WRITE, arg, sizeof(*arg)); ++ if (unlikely(err)) ++ break; ++ ++ br = au_sbr(sb, bindex); ++ brid = br->br_id; ++ BUILD_BUG_ON(sizeof(brid) != sizeof(arg->id)); ++ err = __put_user(brid, &arg->id); ++ if (unlikely(err)) ++ break; ++ ++ BUILD_BUG_ON(sizeof(br->br_perm) != sizeof(arg->perm)); ++ err = __put_user(br->br_perm, &arg->perm); ++ if (unlikely(err)) ++ break; ++ ++ au_seq_path(seq, &br->br_path); ++ err = seq_putc(seq, '\0'); ++ if (!err && seq->count <= sz) { ++ err = copy_to_user(arg->path, seq->buf, seq->count); ++ seq->count = 0; ++ if (unlikely(err)) ++ break; ++ } else { ++ err = -E2BIG; ++ goto out_seq; ++ } ++ } ++ if (unlikely(err)) ++ err = -EFAULT; ++ ++out_seq: ++ kfree(seq); ++out_buf: ++ free_page((unsigned long)buf); ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++long au_brinfo_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_brinfo(file->f_dentry->d_sb, (void __user *)arg); ++} ++ ++#ifdef CONFIG_COMPAT ++long au_brinfo_compat_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_brinfo(file->f_dentry->d_sb, compat_ptr(arg)); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ +void sysaufs_br_init(struct au_branch *br) +{ + int i; @@ -26731,8 +28060,8 @@ diff -urN /usr/share/empty/fs/aufs/sysfs.c linux/fs/aufs/sysfs.c +} diff -urN /usr/share/empty/fs/aufs/sysrq.c linux/fs/aufs/sysrq.c --- /usr/share/empty/fs/aufs/sysrq.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/sysrq.c 2014-06-24 00:14:06.789386337 +0200 -@@ -0,0 +1,154 @@ ++++ linux/fs/aufs/sysrq.c 2014-08-14 10:15:45.131942973 +0200 +@@ -0,0 +1,157 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -26810,6 +28139,7 @@ diff -urN /usr/share/empty/fs/aufs/sysrq.c linux/fs/aufs/sysrq.c +#if 1 + { + struct inode *i; ++ + pr("isolated inode\n"); + spin_lock(&inode_sb_list_lock); + list_for_each_entry(i, &sb->s_inodes, i_sb_list) { @@ -26826,6 +28156,7 @@ diff -urN /usr/share/empty/fs/aufs/sysrq.c linux/fs/aufs/sysrq.c + spin_lock(&files->spin); + hlist_for_each_entry(finfo, &files->head, fi_hlist) { + umode_t mode; ++ + file = finfo->fi_file; + mode = file_inode(file)->i_mode; + if (!special_file(mode)) @@ -26883,14 +28214,15 @@ diff -urN /usr/share/empty/fs/aufs/sysrq.c linux/fs/aufs/sysrq.c +void au_sysrq_fin(void) +{ + int err; ++ + err = unregister_sysrq_key(*aufs_sysrq_key, &au_sysrq_op); + if (unlikely(err)) + pr_err("err %d (ignored)\n", err); +} diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c --- /usr/share/empty/fs/aufs/vdir.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/vdir.c 2014-06-24 00:14:06.789386337 +0200 -@@ -0,0 +1,887 @@ ++++ linux/fs/aufs/vdir.c 2014-08-14 10:15:45.131942973 +0200 +@@ -0,0 +1,889 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -26969,8 +28301,10 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c +{ + struct hlist_head *head; + unsigned int u; ++ size_t sz; + -+ head = kmalloc(sizeof(*nhash->nh_head) * num_hash, gfp); ++ sz = sizeof(*nhash->nh_head) * num_hash; ++ head = kmalloc(sz, gfp); + if (head) { + nhash->nh_num = num_hash; + nhash->nh_head = head; @@ -27780,7 +29114,7 @@ diff -urN /usr/share/empty/fs/aufs/vdir.c linux/fs/aufs/vdir.c +} diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c --- /usr/share/empty/fs/aufs/vfsub.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/vfsub.c 2014-06-24 00:14:06.789386337 +0200 ++++ linux/fs/aufs/vfsub.c 2014-08-14 10:16:04.515942371 +0200 @@ -0,0 +1,782 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -28566,8 +29900,8 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.c linux/fs/aufs/vfsub.c +} diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h --- /usr/share/empty/fs/aufs/vfsub.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/vfsub.h 2014-06-24 00:14:06.789386337 +0200 -@@ -0,0 +1,282 @@ ++++ linux/fs/aufs/vfsub.h 2014-08-14 10:15:45.131942973 +0200 +@@ -0,0 +1,284 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -28675,6 +30009,7 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h +static inline int vfsub_mnt_want_write(struct vfsmount *mnt) +{ + int err; ++ + lockdep_off(); + err = mnt_want_write(mnt); + lockdep_on(); @@ -28787,6 +30122,7 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h +static inline long vfsub_truncate(struct path *path, loff_t length) +{ + long err; ++ + lockdep_off(); + err = vfs_truncate(path, length); + lockdep_on(); @@ -28852,8 +30188,8 @@ diff -urN /usr/share/empty/fs/aufs/vfsub.h linux/fs/aufs/vfsub.h +#endif /* __AUFS_VFSUB_H__ */ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c --- /usr/share/empty/fs/aufs/wbr_policy.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/wbr_policy.c 2014-06-24 00:14:06.789386337 +0200 -@@ -0,0 +1,756 @@ ++++ linux/fs/aufs/wbr_policy.c 2014-08-14 10:15:45.131942973 +0200 +@@ -0,0 +1,765 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -29021,6 +30357,7 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c + au_set_ibend(inode, bdst); + au_set_h_iptr(inode, bdst, au_igrab(h_inode), + au_hi_flags(inode, /*isdir*/1)); ++ au_fhsm_wrote(dentry->d_sb, bdst, /*force*/0); + goto out; /* success */ + + /* revert */ @@ -29532,12 +30869,10 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c +} + +/* bottom up */ -+static int au_wbr_copyup_bu(struct dentry *dentry) ++int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t bstart) +{ + int err; -+ aufs_bindex_t bstart; + -+ bstart = au_dbstart(dentry); + err = au_wbr_bu(dentry->d_sb, bstart); + AuDbg("b%d\n", err); + if (err > bstart) @@ -29547,6 +30882,16 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c + return err; +} + ++static int au_wbr_copyup_bu(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bstart; ++ ++ bstart = au_dbstart(dentry); ++ err = au_wbr_do_copyup_bu(dentry, bstart); ++ return err; ++} ++ +/* ---------------------------------------------------------------------- */ + +struct au_wbr_copyup_operations au_wbr_copyup_ops[] = { @@ -29612,8 +30957,8 @@ diff -urN /usr/share/empty/fs/aufs/wbr_policy.c linux/fs/aufs/wbr_policy.c +}; diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c --- /usr/share/empty/fs/aufs/whout.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/whout.c 2014-06-24 00:14:06.789386337 +0200 -@@ -0,0 +1,1052 @@ ++++ linux/fs/aufs/whout.c 2014-08-14 10:15:45.131942973 +0200 +@@ -0,0 +1,1056 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -29679,8 +31024,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c + * test if the @wh_name exists under @h_parent. + * @try_sio specifies the necessary of super-io. + */ -+int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, -+ struct au_branch *br, int try_sio) ++int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio) +{ + int err; + struct dentry *wh_dentry; @@ -29688,7 +31032,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c + if (!try_sio) + wh_dentry = vfsub_lkup_one(wh_name, h_parent); + else -+ wh_dentry = au_sio_lkup_one(wh_name, h_parent, br); ++ wh_dentry = au_sio_lkup_one(wh_name, h_parent); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) + goto out; @@ -29714,13 +31058,13 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c +/* + * test if the @h_dentry sets opaque or not. + */ -+int au_diropq_test(struct dentry *h_dentry, struct au_branch *br) ++int au_diropq_test(struct dentry *h_dentry) +{ + int err; + struct inode *h_dir; + + h_dir = h_dentry->d_inode; -+ err = au_wh_test(h_dentry, &diropq_name, br, ++ err = au_wh_test(h_dentry, &diropq_name, + au_test_h_perm_sio(h_dir, MAY_EXEC)); + return err; +} @@ -29764,7 +31108,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c + qs.name = name; + for (i = 0; i < 3; i++) { + sprintf(p, "%.*x", AUFS_WH_TMP_LEN, cnt++); -+ dentry = au_sio_lkup_one(&qs, h_parent, br); ++ dentry = au_sio_lkup_one(&qs, h_parent); + if (IS_ERR(dentry) || !dentry->d_inode) + goto out_name; + dput(dentry); @@ -30207,6 +31551,8 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c + wbr_wh_write_unlock(wbr); + au_hn_imtx_unlock(hdir); + di_read_unlock(a->sb->s_root, AuLock_IR); ++ if (!err) ++ au_fhsm_wrote(a->sb, bindex, /*force*/0); + +out: + if (wbr) @@ -30294,6 +31640,8 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c + + /* return this error in this context */ + err = vfsub_create(h_dir, &h_path, WH_MASK, /*want_excl*/true); ++ if (!err) ++ au_fhsm_wrote(sb, bindex, /*force*/0); + +out: + wbr_wh_read_unlock(wbr); @@ -30418,9 +31766,10 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c + wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, au_sbr(sb, bindex)); + if (!IS_ERR(wh_dentry) && !wh_dentry->d_inode) { + err = link_or_create_wh(sb, bindex, wh_dentry); -+ if (!err) ++ if (!err) { + au_set_dbwh(dentry, bindex); -+ else { ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ } else { + dput(wh_dentry); + wh_dentry = ERR_PTR(err); + } @@ -30668,8 +32017,8 @@ diff -urN /usr/share/empty/fs/aufs/whout.c linux/fs/aufs/whout.c +} diff -urN /usr/share/empty/fs/aufs/whout.h linux/fs/aufs/whout.h --- /usr/share/empty/fs/aufs/whout.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/whout.h 2014-06-24 00:14:06.789386337 +0200 -@@ -0,0 +1,86 @@ ++++ linux/fs/aufs/whout.h 2014-08-14 10:15:45.131942973 +0200 +@@ -0,0 +1,85 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -30701,9 +32050,8 @@ diff -urN /usr/share/empty/fs/aufs/whout.h linux/fs/aufs/whout.h +/* whout.c */ +int au_wh_name_alloc(struct qstr *wh, const struct qstr *name); +struct au_branch; -+int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, -+ struct au_branch *br, int try_sio); -+int au_diropq_test(struct dentry *h_dentry, struct au_branch *br); ++int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio); ++int au_diropq_test(struct dentry *h_dentry); +struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, + struct qstr *prefix); +int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br); @@ -30758,7 +32106,7 @@ diff -urN /usr/share/empty/fs/aufs/whout.h linux/fs/aufs/whout.h +#endif /* __AUFS_WHOUT_H__ */ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c --- /usr/share/empty/fs/aufs/wkq.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/wkq.c 2014-06-24 00:14:06.789386337 +0200 ++++ linux/fs/aufs/wkq.c 2014-08-14 10:16:04.515942371 +0200 @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -30975,7 +32323,7 @@ diff -urN /usr/share/empty/fs/aufs/wkq.c linux/fs/aufs/wkq.c +} diff -urN /usr/share/empty/fs/aufs/wkq.h linux/fs/aufs/wkq.h --- /usr/share/empty/fs/aufs/wkq.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/wkq.h 2014-06-24 00:14:06.789386337 +0200 ++++ linux/fs/aufs/wkq.h 2014-01-30 21:10:02.860815399 +0100 @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima @@ -31070,8 +32418,8 @@ diff -urN /usr/share/empty/fs/aufs/wkq.h linux/fs/aufs/wkq.h +#endif /* __AUFS_WKQ_H__ */ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c --- /usr/share/empty/fs/aufs/xino.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/aufs/xino.c 2014-06-24 00:14:06.792719853 +0200 -@@ -0,0 +1,1312 @@ ++++ linux/fs/aufs/xino.c 2014-08-14 10:16:04.515942371 +0200 +@@ -0,0 +1,1316 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -32072,6 +33420,8 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + return fop->read; + if (fop->aio_read) + return do_sync_read; ++ if (fop->read_iter) ++ return new_sync_read; + return ERR_PTR(-ENOSYS); +} + @@ -32083,6 +33433,8 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c + return fop->write; + if (fop->aio_write) + return do_sync_write; ++ if (fop->write_iter) ++ return new_sync_write; + return ERR_PTR(-ENOSYS); +} + @@ -32386,8 +33738,8 @@ diff -urN /usr/share/empty/fs/aufs/xino.c linux/fs/aufs/xino.c +} diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/linux/aufs_type.h --- /usr/share/empty/include/uapi/linux/aufs_type.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/include/uapi/linux/aufs_type.h 2014-06-24 00:14:06.792719853 +0200 -@@ -0,0 +1,281 @@ ++++ linux/include/uapi/linux/aufs_type.h 2014-08-14 10:16:04.522609267 +0200 +@@ -0,0 +1,380 @@ +/* + * Copyright (C) 2005-2014 Junjiro R. Okajima + * @@ -32429,7 +33781,7 @@ diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/lin + +#include + -+#define AUFS_VERSION "3.15-20140623" ++#define AUFS_VERSION "3.16-20140811" + +/* todo? move this to linux-2.6.19/include/magic.h */ +#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') @@ -32483,6 +33835,7 @@ diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/lin +#define AUFS_WKQ_NAME AUFS_NAME "d" +#define AUFS_MFS_DEF_SEC 30 /* seconds */ +#define AUFS_MFS_MAX_SEC 3600 /* seconds */ ++#define AUFS_FHSM_CACHE_DEF_SEC 30 /* seconds */ +#define AUFS_PLINK_WARN 50 /* number of plinks in a single bucket */ + +/* pseudo-link maintenace under /proc */ @@ -32506,9 +33859,78 @@ diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/lin +#define AUFS_BRPERM_RW "rw" +#define AUFS_BRPERM_RO "ro" +#define AUFS_BRPERM_RR "rr" ++#define AUFS_BRATTR_COO_REG "coo_reg" ++#define AUFS_BRATTR_COO_ALL "coo_all" ++#define AUFS_BRATTR_FHSM "fhsm" ++#define AUFS_BRATTR_UNPIN "unpin" +#define AUFS_BRRATTR_WH "wh" +#define AUFS_BRWATTR_NLWH "nolwh" -+#define AUFS_BRATTR_UNPIN "unpin" ++#define AUFS_BRWATTR_MOO "moo" ++ ++#define AuBrPerm_RW 1 /* writable, hardlinkable wh */ ++#define AuBrPerm_RO (1 << 1) /* readonly */ ++#define AuBrPerm_RR (1 << 2) /* natively readonly */ ++#define AuBrPerm_Mask (AuBrPerm_RW | AuBrPerm_RO | AuBrPerm_RR) ++ ++#define AuBrAttr_COO_REG (1 << 3) /* copy-up on open */ ++#define AuBrAttr_COO_ALL (1 << 4) ++#define AuBrAttr_COO_Mask (AuBrAttr_COO_REG | AuBrAttr_COO_ALL) ++ ++#define AuBrAttr_FHSM (1 << 5) /* file-based hsm */ ++#define AuBrAttr_UNPIN (1 << 6) /* rename-able top dir of ++ branch */ ++ ++#define AuBrRAttr_WH (1 << 7) /* whiteout-able */ ++#define AuBrRAttr_Mask AuBrRAttr_WH ++ ++#define AuBrWAttr_NoLinkWH (1 << 8) /* un-hardlinkable whiteouts */ ++#define AuBrWAttr_MOO (1 << 9) /* move-up on open */ ++#define AuBrWAttr_Mask (AuBrWAttr_NoLinkWH | AuBrWAttr_MOO) ++ ++#define AuBrAttr_CMOO_Mask (AuBrAttr_COO_Mask | AuBrWAttr_MOO) ++ ++#ifdef __KERNEL__ ++#ifndef CONFIG_AUFS_FHSM ++#undef AuBrAttr_FHSM ++#define AuBrAttr_FHSM 0 ++#endif ++#endif ++ ++/* the longest combination */ ++#define AuBrPermStrSz sizeof(AUFS_BRPERM_RW \ ++ "+" AUFS_BRATTR_COO_REG \ ++ "+" AUFS_BRATTR_FHSM \ ++ "+" AUFS_BRATTR_UNPIN \ ++ "+" AUFS_BRWATTR_NLWH) ++ ++typedef struct { ++ char a[AuBrPermStrSz]; ++} au_br_perm_str_t; ++ ++static inline int au_br_writable(int brperm) ++{ ++ return brperm & AuBrPerm_RW; ++} ++ ++static inline int au_br_whable(int brperm) ++{ ++ return brperm & (AuBrPerm_RW | AuBrRAttr_WH); ++} ++ ++static inline int au_br_wh_linkable(int brperm) ++{ ++ return !(brperm & AuBrWAttr_NoLinkWH); ++} ++ ++static inline int au_br_cmoo(int brperm) ++{ ++ return brperm & AuBrAttr_CMOO_Mask; ++} ++ ++static inline int au_br_fhsm(int brperm) ++{ ++ return brperm & AuBrAttr_FHSM; ++} + +/* ---------------------------------------------------------------------- */ + @@ -32518,14 +33940,11 @@ diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/lin + AuCtl_RDU, + AuCtl_RDU_INO, + -+ /* pathconf wrapper */ -+ AuCtl_WBR_FD, -+ -+ /* busy inode */ -+ AuCtl_IBUSY, -+ -+ /* move-down */ -+ AuCtl_MVDOWN ++ AuCtl_WBR_FD, /* pathconf wrapper */ ++ AuCtl_IBUSY, /* busy inode */ ++ AuCtl_MVDOWN, /* move-down */ ++ AuCtl_BR, /* info about branches */ ++ AuCtl_FHSM_FD /* connection for fhsm */ +}; + +/* borrowed from linux/include/linux/kernel.h */ @@ -32639,22 +34058,52 @@ diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/lin +#define AUFS_MVDOWN_ROUPPER_R (1 << 6) /* did on upper RO */ +#define AUFS_MVDOWN_BRID_UPPER (1 << 7) /* upper brid */ +#define AUFS_MVDOWN_BRID_LOWER (1 << 8) /* lower brid */ -+/* will be added more */ ++#define AUFS_MVDOWN_FHSM_LOWER (1 << 9) /* find fhsm attr for lower */ ++#define AUFS_MVDOWN_STFS (1 << 10) /* req. stfs */ ++#define AUFS_MVDOWN_STFS_FAILED (1 << 11) /* output: stfs is unusable */ ++#define AUFS_MVDOWN_BOTTOM (1 << 12) /* output: no more lowers */ + ++/* index for move-down */ +enum { + AUFS_MVDOWN_UPPER, + AUFS_MVDOWN_LOWER, + AUFS_MVDOWN_NARRAY +}; + ++/* ++ * additional info of move-down ++ * number of free blocks and inodes. ++ * subset of struct kstatfs, but smaller and always 64bit. ++ */ ++struct aufs_stfs { ++ uint64_t f_blocks; ++ uint64_t f_bavail; ++ uint64_t f_files; ++ uint64_t f_ffree; ++}; ++ ++struct aufs_stbr { ++ int16_t brid; /* optional input */ ++ int16_t bindex; /* output */ ++ struct aufs_stfs stfs; /* output when AUFS_MVDOWN_STFS set */ ++} __aligned(8); ++ +struct aufs_mvdown { -+ uint32_t flags; ++ uint32_t flags; /* input/output */ ++ struct aufs_stbr stbr[AUFS_MVDOWN_NARRAY]; /* input/output */ ++ int8_t au_errno; /* output */ ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++union aufs_brinfo { ++ /* PATH_MAX may differ between kernel-space and user-space */ ++ char _spacer[4096]; + struct { -+ int16_t bindex; -+ int16_t brid; -+ } a[AUFS_MVDOWN_NARRAY]; -+ int8_t au_errno; -+ /* will be added more */ ++ int16_t id; ++ int perm; ++ char path[0]; ++ }; +} __aligned(8); + +/* ---------------------------------------------------------------------- */ @@ -32667,12 +34116,14 @@ diff -urN /usr/share/empty/include/uapi/linux/aufs_type.h linux/include/uapi/lin +#define AUFS_CTL_IBUSY _IOWR(AuCtlType, AuCtl_IBUSY, struct aufs_ibusy) +#define AUFS_CTL_MVDOWN _IOWR(AuCtlType, AuCtl_MVDOWN, \ + struct aufs_mvdown) ++#define AUFS_CTL_BRINFO _IOW(AuCtlType, AuCtl_BR, union aufs_brinfo) ++#define AUFS_CTL_FHSM_FD _IOW(AuCtlType, AuCtl_FHSM_FD, int) + +#endif /* __AUFS_TYPE_H__ */ -aufs3.15 loopback patch +aufs3.16 loopback patch diff --git a/drivers/block/loop.c b/drivers/block/loop.c -index 138104b..227f7fa 100644 +index 30efd68..77b31b4 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -514,7 +514,7 @@ out: @@ -32867,10 +34318,10 @@ index 90df5d6..cb91822 100644 unsigned lo_blocksize; void *key_data; diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c -index 510919e..f9317c9 100644 +index 24ced51..69fa5cc 100644 --- a/fs/aufs/f_op.c +++ b/fs/aufs/f_op.c -@@ -345,7 +345,7 @@ static ssize_t aufs_splice_read(struct file *file, loff_t *ppos, +@@ -367,7 +367,7 @@ static ssize_t aufs_splice_read(struct file *file, loff_t *ppos, err = -EINVAL; h_file = au_hf_top(file); get_file(h_file); @@ -32929,10 +34380,10 @@ index da8b756..28cb7ea 100644 #endif /* __KERNEL__ */ diff --git a/fs/aufs/super.c b/fs/aufs/super.c -index b609e5a..e3909ed 100644 +index 45146eb..fccd7d6 100644 --- a/fs/aufs/super.c +++ b/fs/aufs/super.c -@@ -807,7 +807,10 @@ static const struct super_operations aufs_sop = { +@@ -809,7 +809,10 @@ static const struct super_operations aufs_sop = { .statfs = aufs_statfs, .put_super = aufs_put_super, .sync_fs = aufs_sync_fs, @@ -32945,10 +34396,10 @@ index b609e5a..e3909ed 100644 /* ---------------------------------------------------------------------- */ diff --git a/include/linux/fs.h b/include/linux/fs.h -index 3ff3e89..13017e6 100644 +index 2f32b35..f94f0e6 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h -@@ -1554,6 +1554,10 @@ struct super_operations { +@@ -1561,6 +1561,10 @@ struct super_operations { int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t); long (*nr_cached_objects)(struct super_block *, int); long (*free_cached_objects)(struct super_block *, long, int); diff --git a/kernel-imq.patch b/kernel-imq.patch index 6f4c7b2d..12bd3d3b 100644 --- a/kernel-imq.patch +++ b/kernel-imq.patch @@ -1295,10 +1295,10 @@ index f66f346..d699b19 100644 #ifdef CONFIG_BRIDGE_NETFILTER struct nf_bridge_info *nf_bridge; #endif -@@ -490,6 +499,9 @@ struct sk_buff { - */ - __u8 encapsulation:1; - /* 6/8 bit hole (depending on ndisc_nodetype presence) */ +@@ -490,6 +490,9 @@ struct sk_buff { + __u8 csum_valid:1; + __u8 csum_complete_sw:1; + /* 3/5 bit hole (depending on ndisc_nodetype presence) */ +#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) + __u8 imq_flags:IMQ_F_BITS; +#endif diff --git a/kernel-multiarch.config b/kernel-multiarch.config index 0a4e1466..52387c5c 100644 --- a/kernel-multiarch.config +++ b/kernel-multiarch.config @@ -380,6 +380,7 @@ CFAG12864B_RATE i386=20 x86_64=20 #- #- *** FILE: drivers/base/Kconfig *** #- +UEVENT_HELPER all=y UEVENT_HELPER_PATH all="" DEVTMPFS all=y DEVTMPFS_MOUNT all=y @@ -391,7 +392,15 @@ FW_LOADER_USER_HELPER all=y DEBUG_DRIVER all=n DEBUG_DEVRES all=n #- file drivers/base/regmap/Kconfig goes here +DMA_CMA all=y #- Default contiguous memory area size: +CMA_SIZE_MBYTES all=16 +CMA_SIZE_SEL_MBYTES all=y +CMA_SIZE_SEL_PERCENTAGE all=n +CMA_SIZE_SEL_MIN all=n +CMA_SIZE_SEL_MAX all=n +CMA_ALIGNMENT all=8 +CMA_AREAS all=7 #- #- *** FILE: drivers/bcma/Kconfig *** @@ -643,10 +652,12 @@ TCG_XEN all=m #- *** FILE: drivers/clk/Kconfig *** #- COMMON_CLK_WM831X all=m +#- file drivers/clk/versatile/Kconfig goes here COMMON_CLK_SI5351 all=m #- file drivers/clk/qcom/Kconfig goes here #- file drivers/clk/bcm/Kconfig goes here #- file drivers/clk/mvebu/Kconfig goes here +#- file drivers/clk/samsung/Kconfig goes here #- #- *** FILE: drivers/connector/Kconfig *** @@ -687,6 +698,7 @@ CPU_IDLE i386=y sparc64=n x86_64=y CPU_IDLE_MULTIPLE_DRIVERS all=y CPU_IDLE_GOV_LADDER all=y #- file drivers/cpuidle/Kconfig.arm goes here +#- file drivers/cpuidle/Kconfig.mips goes here #- file drivers/cpuidle/Kconfig.powerpc goes here #- @@ -908,6 +920,7 @@ GPIO_VIPERBOARD all=m DRM all=m DRM_LOAD_EDID_FIRMWARE all=y #- file drivers/gpu/drm/i2c/Kconfig goes here +#- file drivers/gpu/drm/bridge/Kconfig goes here DRM_TDFX all=m DRM_R128 all=m DRM_RADEON all=m @@ -936,7 +949,6 @@ DRM_SAVAGE all=m #- file drivers/gpu/drm/msm/Kconfig goes here #- file drivers/gpu/drm/tegra/Kconfig goes here #- file drivers/gpu/drm/panel/Kconfig goes here -#- file drivers/gpu/drm/bridge/Kconfig goes here #- #- *** FILE: drivers/gpu/drm/ast/Kconfig *** @@ -1089,6 +1101,7 @@ SONY_FF all=y HID_SPEEDLINK all=m HID_STEELSERIES all=m HID_SUNPLUS all=m +HID_RMI all=m HID_GREENASIA all=m GREENASIA_FF all=y HID_HYPERV_MOUSE all=m @@ -1128,6 +1141,7 @@ USB_MOUSE all=n #- *** FILE: drivers/hsi/Kconfig *** #- HSI all=m +#- file drivers/hsi/controllers/Kconfig goes here #- file drivers/hsi/clients/Kconfig goes here #- @@ -1234,11 +1248,13 @@ SENSORS_LM95245 all=m SENSORS_PC87360 all=m SENSORS_PC87427 all=m SENSORS_NTC_THERMISTOR all=m +SENSORS_NCT6683 all=m SENSORS_NCT6775 all=m SENSORS_PCF8591 all=m #- file drivers/hwmon/pmbus/Kconfig goes here SENSORS_SHT15 all=m SENSORS_SHT21 all=m +SENSORS_SHTC1 all=m SENSORS_SIS5595 all=m SENSORS_DME1737 all=m SENSORS_EMC1403 all=m @@ -1373,6 +1389,7 @@ I2C_VIPERBOARD all=m #- Other I2C/SMBus bus drivers I2C_ELEKTOR i386=m I2C_PCA_ISA all=m +I2C_CROS_EC_TUNNEL all=m SCx200_I2C i386=m SCx200_I2C_SCL i386=12 SCx200_I2C_SDA i386=13 @@ -1488,6 +1505,7 @@ IIO_CONSUMERS_PER_TRIGGER all=2 #- file drivers/iio/orientation/Kconfig goes here #- file drivers/iio/trigger/Kconfig goes here #- file drivers/iio/pressure/Kconfig goes here +#- file drivers/iio/proximity/Kconfig goes here #- file drivers/iio/temperature/Kconfig goes here #- @@ -1497,6 +1515,7 @@ BMA180 all=m HID_SENSOR_ACCEL_3D all=m IIO_ST_ACCEL_3AXIS all=m KXSD9 all=m +MMA8452 all=m #- #- *** FILE: drivers/iio/adc/Kconfig *** @@ -1508,6 +1527,7 @@ AD7791 all=m AD7793 all=m AD7887 all=m AD7923 all=m +AD799X all=m MAX1363 all=m MCP320X all=m MCP3422 all=m @@ -1606,17 +1626,25 @@ IIO_ST_MAGN_3AXIS all=m #- *** FILE: drivers/iio/orientation/Kconfig *** #- HID_SENSOR_INCLINOMETER_3D all=m +HID_SENSOR_DEVICE_ROTATION all=m #- #- *** FILE: drivers/iio/pressure/Kconfig *** #- HID_SENSOR_PRESS all=m +MPL115 all=m MPL3115 all=m IIO_ST_PRESS all=m +#- +#- *** FILE: drivers/iio/proximity/Kconfig *** +#- +AS3935 all=m + #- #- *** FILE: drivers/iio/temperature/Kconfig *** #- +MLX90614 all=m TMP006 all=m #- @@ -1861,6 +1889,7 @@ INPUT_MMA8450 all=m INPUT_MPU3050 all=m INPUT_APANEL all=m INPUT_GP2A all=m +INPUT_GPIO_BEEPER all=m INPUT_GPIO_TILT_POLLED all=m INPUT_WISTRON_BTNS i386=m INPUT_ATLAS_BTNS i386=m x86_64=m @@ -2073,11 +2102,11 @@ ISDN_DRV_ACT2000 all=m #- #- *** FILE: drivers/isdn/capi/Kconfig *** #- -ISDN_DRV_AVMB1_VERBOSE_REASON all=y sparc=n sparc64=n CAPI_TRACE all=y ISDN_CAPI_CAPI20 all=m ISDN_CAPI_MIDDLEWARE all=y ISDN_CAPI_CAPIDRV all=m +ISDN_CAPI_CAPIDRV_VERBOSE all=y #- #- *** FILE: drivers/isdn/gigaset/Kconfig *** @@ -2209,7 +2238,6 @@ LEDS_LP8501 all=m LEDS_CLEVO_MAIL all=m LEDS_PCA955X all=m LEDS_PCA963X all=m -LEDS_PCA9685 all=m LEDS_WM831X_STATUS all=m LEDS_WM8350 all=m LEDS_DA903X all=m @@ -2225,6 +2253,7 @@ LEDS_MC13783 all=m LEDS_TCA6507 all=m LEDS_LM355x all=m LEDS_OT200 all=m +#- LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) LEDS_BLINKM all=m #- LED Triggers #- file drivers/leds/trigger/Kconfig goes here @@ -2986,6 +3015,7 @@ USB_GSPCA all=m USB_GSPCA_BENQ all=m USB_GSPCA_CONEX all=m USB_GSPCA_CPIA1 all=m +USB_GSPCA_DTCS033 all=m USB_GSPCA_ETOMS all=m USB_GSPCA_FINEPIX all=m USB_GSPCA_JEILINJ all=m @@ -3168,6 +3198,7 @@ MEMSTICK_TIFM_MS all=m MEMSTICK_JMICRON_38X all=m MEMSTICK_R592 all=m MEMSTICK_REALTEK_PCI all=m +MEMSTICK_REALTEK_USB all=m #- #- *** FILE: drivers/message/fusion/Kconfig *** @@ -3424,7 +3455,9 @@ MMC_CB710 all=m MMC_VIA_SDMMC all=m MMC_VUB300 all=m MMC_USHC all=m +MMC_USDHI6ROL0 all=m MMC_REALTEK_PCI all=m +MMC_REALTEK_USB all=m #- #- *** FILE: drivers/mtd/Kconfig *** @@ -3457,6 +3490,7 @@ MTD_SWAP all=m #- file drivers/mtd/nand/Kconfig goes here #- file drivers/mtd/onenand/Kconfig goes here #- file drivers/mtd/lpddr/Kconfig goes here +#- file drivers/mtd/spi-nor/Kconfig goes here #- file drivers/mtd/ubi/Kconfig goes here #- @@ -3580,6 +3614,11 @@ MTD_ONENAND_GENERIC all=m MTD_ONENAND_OTP all=n alpha=y i386=y x86_64=y MTD_ONENAND_2X_PROGRAM all=y +#- +#- *** FILE: drivers/mtd/spi-nor/Kconfig *** +#- +MTD_SPI_NOR all=m + #- #- *** FILE: drivers/mtd/ubi/Kconfig *** #- @@ -3685,13 +3724,13 @@ CAN_SLCAN all=m CAN_DEV all=m CAN_CALC_BITTIMING all=y CAN_LEDS all=y -CAN_MCP251X all=m CAN_JANZ_ICAN3 all=m PCH_CAN all=m #- file drivers/net/can/mscan/Kconfig goes here #- file drivers/net/can/sja1000/Kconfig goes here #- file drivers/net/can/c_can/Kconfig goes here #- file drivers/net/can/cc770/Kconfig goes here +#- file drivers/net/can/spi/Kconfig goes here #- file drivers/net/can/usb/Kconfig goes here #- file drivers/net/can/softing/Kconfig goes here CAN_DEBUG_DEVICES all=n @@ -3731,11 +3770,17 @@ CAN_TSCAN1 all=m CAN_SOFTING all=m CAN_SOFTING_CS all=m +#- +#- *** FILE: drivers/net/can/spi/Kconfig *** +#- +CAN_MCP251X all=m + #- #- *** FILE: drivers/net/can/usb/Kconfig *** #- CAN_EMS_USB all=m CAN_ESD_USB2 all=m +CAN_GS_USB all=m CAN_KVASER_USB all=m CAN_PEAK_USB all=m CAN_8DEV_USB all=m @@ -3800,6 +3845,7 @@ DNET all=m #- file drivers/net/ethernet/faraday/Kconfig goes here #- file drivers/net/ethernet/freescale/Kconfig goes here #- file drivers/net/ethernet/fujitsu/Kconfig goes here +#- file drivers/net/ethernet/hisilicon/Kconfig goes here #- file drivers/net/ethernet/hp/Kconfig goes here #- file drivers/net/ethernet/ibm/Kconfig goes here #- file drivers/net/ethernet/intel/Kconfig goes here @@ -4153,6 +4199,7 @@ QLCNIC all=m QLCNIC_SRIOV all=y QLCNIC_DCB all=y QLCNIC_VXLAN all=y +QLCNIC_HWMON all=y QLGE all=m NETXEN_NIC all=m sparc=n @@ -4651,6 +4698,9 @@ WIL6210_TRACING all=y #- B43 all=m B43_BCMA all=y +B43_BUSES_BCMA_AND_SSB all=y +B43_BUSES_BCMA all=n +B43_BUSES_SSB all=n B43_PCMCIA all=y B43_SDIO all=y B43_PHY_N all=y @@ -4874,6 +4924,7 @@ NFC_PORT100 all=m #- file drivers/nfc/pn544/Kconfig goes here #- file drivers/nfc/microread/Kconfig goes here #- file drivers/nfc/nfcmrvl/Kconfig goes here +#- file drivers/nfc/st21nfca/Kconfig goes here #- #- *** FILE: drivers/nfc/microread/Kconfig *** @@ -4895,6 +4946,12 @@ NFC_PN544 all=m NFC_PN544_I2C all=m NFC_PN544_MEI all=m +#- +#- *** FILE: drivers/nfc/st21nfca/Kconfig *** +#- +NFC_ST21NFCA all=m +NFC_ST21NFCA_I2C all=m + #- #- *** FILE: drivers/ntb/Kconfig *** #- @@ -5020,9 +5077,11 @@ PINMUX all=y PINCONF all=y DEBUG_PINCTRL all=n PINCTRL_BAYTRAIL all=y +#- file drivers/pinctrl/berlin/Kconfig goes here #- file drivers/pinctrl/mvebu/Kconfig goes here #- file drivers/pinctrl/sh-pfc/Kconfig goes here #- file drivers/pinctrl/spear/Kconfig goes here +#- file drivers/pinctrl/sunxi/Kconfig goes here #- file drivers/pinctrl/vt8500/Kconfig goes here #- @@ -5043,6 +5102,7 @@ ASUS_LAPTOP i386=m x86_64=m DELL_LAPTOP all=m DELL_WMI all=m DELL_WMI_AIO all=m +DELL_SMO8800 all=m FUJITSU_LAPTOP all=m FUJITSU_LAPTOP_DEBUG all=n FUJITSU_TABLET all=m @@ -5254,6 +5314,7 @@ REGULATOR_LP3971 all=m REGULATOR_LP3972 all=m REGULATOR_LP872X all=m REGULATOR_LP8755 all=m +REGULATOR_LTC3589 all=m REGULATOR_MAX1586 all=m REGULATOR_MAX8649 all=m REGULATOR_MAX8660 all=m @@ -5334,6 +5395,7 @@ RTC_DRV_RV3029C2 all=m RTC_DRV_M41T93 all=m RTC_DRV_M41T94 all=m RTC_DRV_DS1305 all=m +RTC_DRV_DS1343 all=m RTC_DRV_DS1347 all=m RTC_DRV_DS1390 all=m RTC_DRV_MAX6902 all=m @@ -5342,6 +5404,7 @@ RTC_DRV_RS5C348 all=m RTC_DRV_DS3234 all=m RTC_DRV_PCF2123 all=m RTC_DRV_RX4581 all=m +RTC_DRV_MCP795 all=m #- Platform RTC drivers RTC_DRV_CMOS all=y RTC_DRV_DS1286 all=m @@ -5370,6 +5433,7 @@ RTC_DRV_PS3 ppc64=m RTC_DRV_PCAP all=m RTC_DRV_MC13XXX all=m RTC_DRV_MOXART all=m +RTC_DRV_XGENE all=m #- HID Sensor RTC drivers RTC_DRV_HID_SENSOR_TIME all=m @@ -5738,9 +5802,9 @@ STAGING all=y #- file drivers/staging/rtl8192e/Kconfig goes here #- file drivers/staging/rtl8712/Kconfig goes here #- file drivers/staging/rtl8188eu/Kconfig goes here +#- file drivers/staging/rtl8192ee/Kconfig goes here #- file drivers/staging/rtl8723au/Kconfig goes here #- file drivers/staging/rtl8821ae/Kconfig goes here -#- file drivers/staging/rts5139/Kconfig goes here #- file drivers/staging/rts5208/Kconfig goes here #- file drivers/staging/frontier/Kconfig goes here #- file drivers/staging/phison/Kconfig goes here @@ -5759,7 +5823,6 @@ STAGING all=y #- file drivers/staging/xgifb/Kconfig goes here #- file drivers/staging/tidspbridge/Kconfig goes here #- file drivers/staging/quickstart/Kconfig goes here -#- file drivers/staging/sbe-2t3e3/Kconfig goes here #- file drivers/staging/keucr/Kconfig goes here #- file drivers/staging/bcm/Kconfig goes here #- file drivers/staging/ft1000/Kconfig goes here @@ -5786,6 +5849,7 @@ STAGING all=y #- file drivers/staging/dgap/Kconfig goes here #- file drivers/staging/gs_fpgaboot/Kconfig goes here #- file drivers/staging/nokia_h4p/Kconfig goes here +#- file drivers/staging/skein/Kconfig goes here #- file drivers/staging/unisys/Kconfig goes here #- @@ -6048,7 +6112,6 @@ AD7291 all=m AD7606 all=m AD7606_IFACE_PARALLEL all=m AD7606_IFACE_SPI all=m -AD799X all=m AD7780 all=m AD7816 all=m AD7192 all=m @@ -6290,6 +6353,11 @@ RTLLIB_CRYPTO_WEP all=m #- RTL8192E all=m +#- +#- *** FILE: drivers/staging/rtl8192ee/Kconfig *** +#- +R8192EE all=m + #- #- *** FILE: drivers/staging/rtl8192u/Kconfig *** #- @@ -6305,7 +6373,6 @@ R8712U all=m #- R8723AU all=m 8723AU_AP_MODE all=y -8723AU_P2P all=y 8723AU_BT_COEXIST all=y #- @@ -6313,23 +6380,12 @@ R8723AU all=m #- R8821AE all=m -#- -#- *** FILE: drivers/staging/rts5139/Kconfig *** -#- -RTS5139 all=m -RTS5139_DEBUG all=n - #- #- *** FILE: drivers/staging/rts5208/Kconfig *** #- RTS5208 all=m RTS5208_DEBUG all=n -#- -#- *** FILE: drivers/staging/sbe-2t3e3/Kconfig *** -#- -SBE_2T3E3 all=m - #- #- *** FILE: drivers/staging/sep/Kconfig *** #- @@ -6347,6 +6403,11 @@ NET_VENDOR_SILICOM all=y SBYPASS all=m BPCTL all=m +#- +#- *** FILE: drivers/staging/skein/Kconfig *** +#- +CRYPTO_SKEIN all=y + #- #- *** FILE: drivers/staging/slicoss/Kconfig *** #- @@ -6479,6 +6540,7 @@ THERMAL_EMULATION all=n INTEL_POWERCLAMP all=m X86_PKG_TEMP_THERMAL all=m ACPI_INT3403_THERMAL all=m +INTEL_SOC_DTS_THERMAL all=m #- file drivers/thermal/ti-soc-thermal/Kconfig goes here #- file drivers/thermal/samsung/Kconfig goes here @@ -6581,6 +6643,7 @@ SERIAL_SGI_IOC3 ia64=m SERIAL_OF_PLATFORM ppc=m ppc64=m SERIAL_OF_PLATFORM_NWPSERIAL powerpc=m SERIAL_SCCNXP all=m +SERIAL_SC16IS7XX all=m SERIAL_TIMBERDALE all=m SERIAL_ALTERA_JTAGUART all=m SERIAL_ALTERA_UART all=m @@ -6595,6 +6658,7 @@ SERIAL_RP2 all=m SERIAL_RP2_NR_UARTS all=32 SERIAL_FSL_LPUART all=m SERIAL_ST_ASC all=m +SERIAL_MEN_Z135 all=m #- #- *** FILE: drivers/uio/Kconfig *** @@ -6668,7 +6732,6 @@ USB_TMC all=m #- #- *** FILE: drivers/usb/core/Kconfig *** #- -USB_DEBUG all=n USB_ANNOUNCE_NEW_DEVICES all=y #- Miscellaneous USB options USB_DEFAULT_PERSIST all=y @@ -6676,11 +6739,13 @@ USB_DYNAMIC_MINORS all=y sparc64=n USB_OTG all=y USB_OTG_WHITELIST all=y USB_OTG_BLACKLIST_HUB all=n +USB_OTG_FSM all=m #- #- *** FILE: drivers/usb/dwc2/Kconfig *** #- USB_DWC2 all=m +#- Gadget mode requires USB Gadget support to be enabled USB_DWC2_DEBUG all=n USB_DWC2_TRACK_MISSED_SOFS all=n @@ -6713,7 +6778,6 @@ USB_GR_UDC all=m USB_R8A66597 all=m USB_RENESAS_USBHS_UDC all=m USB_PXA27X all=n -USB_S3C_HSOTG all=m USB_MV_UDC all=m USB_MV_U3D all=m USB_M66592 all=m @@ -6785,6 +6849,7 @@ USB_ISP1760_HCD all=m USB_ISP1362_HCD all=m USB_FUSBH200_HCD all=m USB_FOTG210_HCD all=m +USB_MAX3421_HCD all=m USB_OHCI_HCD all=m USB_OHCI_HCD_PPC_OF_BE ppc=y ppc64=y USB_OHCI_HCD_PPC_OF_LE ppc=y ppc64=n @@ -6859,7 +6924,6 @@ USB_MUSB_HDRC all=n #- *** FILE: drivers/usb/phy/Kconfig *** #- USB_PHY all=y -USB_OTG_FSM all=m AB8500_USB all=m NOP_USB_XCEIV all=m AM335X_PHY_USB all=m @@ -7009,6 +7073,7 @@ VHOST_SCSI all=m #- file drivers/char/agp/Kconfig goes here #- file drivers/gpu/vga/Kconfig goes here #- file drivers/gpu/host1x/Kconfig goes here +#- file drivers/gpu/ipu-v3/Kconfig goes here #- file drivers/gpu/drm/Kconfig goes here #- file drivers/video/fbdev/Kconfig goes here #- file drivers/video/backlight/Kconfig goes here @@ -7347,8 +7412,6 @@ SMSC_SCH311X_WDT all=m SMSC37B787_WDT i386=m x86_64=m VIA_WDT all=m W83627HF_WDT i386=m x86_64=m -W83697HF_WDT i386=m x86_64=m -W83697UG_WDT i386=m x86_64=m W83877F_WDT i386=m x86_64=m W83977F_WDT i386=m x86_64=m MACHZ_WDT i386=m x86_64=m @@ -7508,6 +7571,11 @@ AFS_FS all=m AFS_DEBUG all=n AFS_FSCACHE all=y +#- +#- *** FILE: fs/aufs/Kconfig *** +#- +AUFS_FHSM all=y + #- #- *** FILE: fs/autofs4/Kconfig *** #- @@ -8020,6 +8088,7 @@ SWAP all=y SYSVIPC all=y SYSVIPC_SYSCTL all=y POSIX_MQUEUE all=y +CROSS_MEMORY_ATTACH all=y FHANDLE all=y USELIB all=y AUDIT all=y @@ -8208,6 +8277,7 @@ KPROBE_EVENT all=y UPROBE_EVENT all=y FTRACE_STARTUP_TEST all=n MMIOTRACE x86=n +TRACEPOINT_BENCHMARK all=n RING_BUFFER_BENCHMARK all=m RING_BUFFER_STARTUP_TEST all=n @@ -8314,6 +8384,7 @@ DEBUG_KOBJECT all=n DEBUG_KOBJECT_RELEASE all=n DEBUG_BUGVERBOSE all=y DEBUG_LIST all=n +DEBUG_PI_LIST all=n DEBUG_SG all=n DEBUG_NOTIFIERS all=n DEBUG_CREDENTIALS all=n @@ -8345,6 +8416,7 @@ BUILD_DOCSRC all=n DMA_API_DEBUG all=n TEST_MODULE all=n TEST_USER_COPY all=n +TEST_BPF all=n #- file samples/Kconfig goes here #- file lib/Kconfig.kgdb goes here @@ -8415,7 +8487,6 @@ HWPOISON_INJECT all=m TRANSPARENT_HUGEPAGE all=y TRANSPARENT_HUGEPAGE_ALWAYS all=y TRANSPARENT_HUGEPAGE_MADVISE all=n -CROSS_MEMORY_ATTACH all=y CLEANCACHE all=y FRONTSWAP all=y CMA all=y @@ -8596,6 +8667,7 @@ BRIDGE_VLAN_FILTERING all=y #- *** FILE: net/bridge/netfilter/Kconfig *** #- NF_TABLES_BRIDGE all=m +NFT_BRIDGE_META all=m BRIDGE_NF_EBTABLES all=m BRIDGE_EBT_BROUTE all=m BRIDGE_EBT_T_FILTER all=m @@ -9369,7 +9441,8 @@ INTEGRITY_ASYMMETRIC_KEYS all=y #- *** FILE: security/integrity/evm/Kconfig *** #- EVM all=y -EVM_HMAC_VERSION all=2 +EVM_ATTR_FSUUID all=y +EVM_EXTRA_SMACK_XATTRS all=y #- #- *** FILE: security/integrity/ima/Kconfig *** @@ -9528,6 +9601,8 @@ SND_DICE all=m SND_FIREWIRE_SPEAKERS all=m SND_ISIGHT all=m SND_SCS1X all=m +SND_FIREWORKS all=m +SND_BEBOB all=m #- #- *** FILE: sound/isa/Kconfig *** @@ -9780,7 +9855,9 @@ SND_SOC_AK4554 all=m SND_SOC_AK4641 all=m SND_SOC_AK4642 all=m SND_SOC_AK5386 all=m +SND_SOC_ALC5623 all=m SND_SOC_CS42L52 all=m +SND_SOC_CS42L56 all=m SND_SOC_CS42L73 all=m SND_SOC_CS4270 all=m SND_SOC_CS4271 all=m @@ -9795,6 +9872,7 @@ SND_SOC_PCM512x_SPI all=m SND_SOC_SGTL5000 all=m SND_SOC_SIRF_AUDIO_CODEC all=m SND_SOC_SPDIF all=m +SND_SOC_STA350 all=m SND_SOC_TAS5086 all=m SND_SOC_TLV320AIC3X all=m SND_SOC_WM1250_EV1 all=m @@ -9825,10 +9903,18 @@ SND_DESIGNWARE_I2S all=m #- #- *** FILE: sound/soc/fsl/Kconfig *** #- +#- Common SoC Audio options for Freescale CPUs: +SND_SOC_FSL_SAI all=m +SND_SOC_FSL_SSI all=m +SND_SOC_FSL_SPDIF all=m +SND_SOC_FSL_ESAI all=m +SND_SOC_IMX_AUDMUX all=m +#- SoC Audio support for Freescale PPC boards: SND_SOC_MPC5200_I2S all=m SND_SOC_MPC5200_AC97 powerpc=m SND_MPC52xx_SOC_PCM030 powerpc=m SND_MPC52xx_SOC_EFIKA powerpc=m +#- SoC Audio support for Freescale i.MX boards: #- #- *** FILE: sound/soc/generic/Kconfig *** @@ -9841,6 +9927,7 @@ SND_SIMPLE_CARD all=m SND_SOC_INTEL_SST all=m SND_SOC_INTEL_HASWELL_MACH all=m SND_SOC_INTEL_BYT_RT5640_MACH all=m +SND_SOC_INTEL_BYT_MAX98090_MACH all=m #- #- *** FILE: sound/sparc/Kconfig *** @@ -9869,6 +9956,7 @@ SND_USB_CAIAQ_INPUT all=y sparc64=n SND_USB_US122L all=m SND_USB_6FIRE all=m SND_USB_HIFACE all=m +SND_BCD2000 all=m #- #- *** FILE: usr/Kconfig *** @@ -9879,12 +9967,23 @@ RD_BZIP2 all=y RD_LZMA all=y RD_XZ all=y RD_LZO all=y -INITRAMFS_COMPRESSION_NONE all=y -INITRAMFS_COMPRESSION_GZIP all=n -INITRAMFS_COMPRESSION_BZIP2 all=n -INITRAMFS_COMPRESSION_LZMA all=n #- #- *** PROBABLY REMOVED OPTIONS *** #- +8723AU_P2P all=y +EVM_HMAC_VERSION all=2 EXPERIMENTAL all=y +INITRAMFS_COMPRESSION_BZIP2 all=n +INITRAMFS_COMPRESSION_GZIP all=n +INITRAMFS_COMPRESSION_LZMA all=n +INITRAMFS_COMPRESSION_NONE all=y +ISDN_DRV_AVMB1_VERBOSE_REASON all=y sparc=n sparc64=n +LEDS_PCA9685 all=m +RTS5139 all=m +RTS5139_DEBUG all=n +SBE_2T3E3 all=m +USB_DEBUG all=n +USB_S3C_HSOTG all=m +W83697HF_WDT i386=m x86_64=m +W83697UG_WDT i386=m x86_64=m diff --git a/kernel-small_fixes.patch b/kernel-small_fixes.patch index 59f4a4bb..28517b8b 100644 --- a/kernel-small_fixes.patch +++ b/kernel-small_fixes.patch @@ -27,160 +27,3 @@ fi done -diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c -index 7a0c800..ec5ebbb 100644 ---- a/drivers/net/ethernet/realtek/r8169.c -+++ b/drivers/net/ethernet/realtek/r8169.c -@@ -6927,6 +6927,14 @@ rtl_init_one(struct pci_dev *pdev, const - for (i = 0; i < ETH_ALEN; i++) - dev->dev_addr[i] = RTL_R8(MAC0 + i); - -+ if (!is_valid_ether_addr(dev->dev_addr)) { -+ /* Report it and use a random ethernet address instead */ -+ netdev_err(dev, "Invalid MAC address: %pM\n", dev->dev_addr); -+ random_ether_addr(dev->dev_addr); -+ netdev_info(dev, "Using random MAC address: %pM\n", -+ dev->dev_addr); -+ } -+ - SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops); - dev->watchdog_timeo = RTL8169_TX_TIMEOUT; - -commit 110dc24ad2ae4e9b94b08632fe1eb2fcdff83045 -Author: Dave Chinner -Date: Tue May 20 08:18:09 2014 +1000 - - xfs: log vector rounding leaks log space - - The addition of direct formatting of log items into the CIL - linear buffer added alignment restrictions that the start of each - vector needed to be 64 bit aligned. Hence padding was added in - xlog_finish_iovec() to round up the vector length to ensure the next - vector started with the correct alignment. - - This adds a small number of bytes to the size of - the linear buffer that is otherwise unused. The issue is that we - then use the linear buffer size to determine the log space used by - the log item, and this includes the unused space. Hence when we - account for space used by the log item, it's more than is actually - written into the iclogs, and hence we slowly leak this space. - - This results on log hangs when reserving space, with threads getting - stuck with these stack traces: - - Call Trace: - [] schedule+0x29/0x70 - [] xlog_grant_head_wait+0xa2/0x1a0 - [] xlog_grant_head_check+0xbd/0x140 - [] xfs_log_reserve+0x103/0x220 - [] xfs_trans_reserve+0x2f5/0x310 - ..... - - The 4 bytes is significant. Brain Foster did all the hard work in - tracking down a reproducable leak to inode chunk allocation (it went - away with the ikeep mount option). His rough numbers were that - creating 50,000 inodes leaked 11 log blocks. This turns out to be - roughly 800 inode chunks or 1600 inode cluster buffers. That - works out at roughly 4 bytes per cluster buffer logged, and at that - I started looking for a 4 byte leak in the buffer logging code. - - What I found was that a struct xfs_buf_log_format structure for an - inode cluster buffer is 28 bytes in length. This gets rounded up to - 32 bytes, but the vector length remains 28 bytes. Hence the CIL - ticket reservation is decremented by 32 bytes (via lv->lv_buf_len) - for that vector rather than 28 bytes which are written into the log. - - The fix for this problem is to separately track the bytes used by - the log vectors in the item and use that instead of the buffer - length when accounting for the log space that will be used by the - formatted log item. - - Again, thanks to Brian Foster for doing all the hard work and long - hours to isolate this leak and make finding the bug relatively - simple. - - Signed-off-by: Dave Chinner - Reviewed-by: Christoph Hellwig - Reviewed-by: Brian Foster - Signed-off-by: Dave Chinner - -diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h -index 2c40044..84e0deb 100644 ---- a/fs/xfs/xfs_log.h -+++ b/fs/xfs/xfs_log.h -@@ -24,7 +24,8 @@ struct xfs_log_vec { - struct xfs_log_iovec *lv_iovecp; /* iovec array */ - struct xfs_log_item *lv_item; /* owner */ - char *lv_buf; /* formatted buffer */ -- int lv_buf_len; /* size of formatted buffer */ -+ int lv_bytes; /* accounted space in buffer */ -+ int lv_buf_len; /* aligned size of buffer */ - int lv_size; /* size of allocated lv */ - }; - -@@ -52,15 +53,21 @@ xlog_prepare_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec **vecp, - return vec->i_addr; - } - -+/* -+ * We need to make sure the next buffer is naturally aligned for the biggest -+ * basic data type we put into it. We already accounted for this padding when -+ * sizing the buffer. -+ * -+ * However, this padding does not get written into the log, and hence we have to -+ * track the space used by the log vectors separately to prevent log space hangs -+ * due to inaccurate accounting (i.e. a leak) of the used log space through the -+ * CIL context ticket. -+ */ - static inline void - xlog_finish_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec *vec, int len) - { -- /* -- * We need to make sure the next buffer is naturally aligned for the -- * biggest basic data type we put into it. We already accounted for -- * this when sizing the buffer. -- */ - lv->lv_buf_len += round_up(len, sizeof(uint64_t)); -+ lv->lv_bytes += len; - vec->i_len = len; - } - -diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c -index 7e54553..de835da 100644 ---- a/fs/xfs/xfs_log_cil.c -+++ b/fs/xfs/xfs_log_cil.c -@@ -97,7 +97,7 @@ xfs_cil_prepare_item( - { - /* Account for the new LV being passed in */ - if (lv->lv_buf_len != XFS_LOG_VEC_ORDERED) { -- *diff_len += lv->lv_buf_len; -+ *diff_len += lv->lv_bytes; - *diff_iovecs += lv->lv_niovecs; - } - -@@ -111,7 +111,7 @@ xfs_cil_prepare_item( - else if (old_lv != lv) { - ASSERT(lv->lv_buf_len != XFS_LOG_VEC_ORDERED); - -- *diff_len -= old_lv->lv_buf_len; -+ *diff_len -= old_lv->lv_bytes; - *diff_iovecs -= old_lv->lv_niovecs; - kmem_free(old_lv); - } -@@ -239,7 +239,7 @@ xlog_cil_insert_format_items( - * that the space reservation accounting is correct. - */ - *diff_iovecs -= lv->lv_niovecs; -- *diff_len -= lv->lv_buf_len; -+ *diff_len -= lv->lv_bytes; - } else { - /* allocate new data chunk */ - lv = kmem_zalloc(buf_size, KM_SLEEP|KM_NOFS); -@@ -259,6 +259,7 @@ xlog_cil_insert_format_items( - - /* The allocated data region lies beyond the iovec region */ - lv->lv_buf_len = 0; -+ lv->lv_bytes = 0; - lv->lv_buf = (char *)lv + buf_size - nbytes; - ASSERT(IS_ALIGNED((unsigned long)lv->lv_buf, sizeof(uint64_t))); - diff --git a/kernel.spec b/kernel.spec index c9241388..21eded8d 100644 --- a/kernel.spec +++ b/kernel.spec @@ -69,8 +69,8 @@ %endif %define rel 1 -%define basever 3.15 -%define postver .8 +%define basever 3.16 +%define postver .1 # define this to '-%{basever}' for longterm branch %define versuffix %{nil} @@ -113,10 +113,10 @@ Epoch: 3 License: GPL v2 Group: Base/Kernel Source0: http://www.kernel.org/pub/linux/kernel/v3.x/linux-%{basever}.tar.xz -# Source0-md5: 97ca1625bb40368dc41b9a7971549071 +# Source0-md5: 5c569ed649a0c9711879f333e90c5386 %if "%{postver}" != ".0" Patch0: http://www.kernel.org/pub/linux/kernel/v3.x/patch-%{version}.xz -# Patch0-md5: f1d3ed3137ecbb37ec520748bd65dac0 +# Patch0-md5: 9da4b0f5e343455b8141bcfa47e88cf5 %endif Source1: kernel.sysconfig