[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#850884: overlayfs does not implement inotify interfaces correctly



Package: linux-source-4.8
Severity: important
Tags: patch

When using tail on the liveCD some updates are not reported. This seems to be
triggered by tail using inotify to identify modified files. Overlayfs does not
appear to be implementing inotify quite the way you might hope reporting only
against the underlying filesystems.

^^ This is the description of the original bug filed 2011-10-26 by
Andy Whitcroft. (https://bugs.launchpad.net/ubuntu/+source/linux/+bug/882147)

It still applies and the bug is still present and still renders live isos
unusable to a degree. One could say it's a "non-feature" but i would still
call it bug. Unfortunately debian-live-isos are bitten by this too.

The applied patch is the basicly the patch in the bugreport and applies to
kernel 4.8 - and solve the problem with live isos.

Cheers Alf 

-- System Information:
Debian Release: stretch/sid
  APT prefers buildd-unstable
  APT policy: (500, 'buildd-unstable'), (500, 'unstable'), (500, 'testing'), (500, 'stable'), (1, 'experimental')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 4.9.2-towo.1-siduction-amd64 (SMP w/8 CPU cores; PREEMPT)
Locale: LANG=de_DE.utf8, LC_CTYPE=de_DE.utf8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
diff --git a/fs/notify/inotify/Kconfig b/fs/notify/inotify/Kconfig
index b981fc0..1ccd92e 100644
--- a/fs/notify/inotify/Kconfig
+++ b/fs/notify/inotify/Kconfig
@@ -15,3 +15,12 @@ config INOTIFY_USER
 	  For more information, see <file:Documentation/filesystems/inotify.txt>
 
 	  If unsure, say Y.
+
+config INOTIFY_STACKFS
+	bool "Inotify support for stackable filesystem"
+	select INOTIFY_USER
+	default y
+	---help---
+	  Say Y here to enable inotify support for stackable filesystem.
+
+	  If unsure, say N.
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index 60f954a..3daff50 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -24,6 +24,7 @@
 
 #include <linux/file.h>
 #include <linux/fs.h> /* struct inode */
+#include <linux/mount.h>
 #include <linux/fsnotify_backend.h>
 #include <linux/idr.h>
 #include <linux/init.h> /* fs_initcall */
@@ -86,6 +86,94 @@
 };
 #endif /* CONFIG_SYSCTL */
 
+#ifdef CONFIG_INOTIFY_STACKFS
+
+static DEFINE_RWLOCK(inotify_fs_lock);
+static LIST_HEAD(inotify_fs_list);
+
+static inline struct file_system_type* peek_fs_type(struct path *path)
+{
+	return path->mnt->mnt_sb->s_type;
+}
+
+static struct inotify_stackfs* inotify_get_stackfs(struct path *path)
+{
+	struct file_system_type *fs;
+	struct inotify_stackfs *fse, *ret = NULL;
+
+	fs = peek_fs_type(path);
+
+	read_lock(&inotify_fs_lock);
+	list_for_each_entry(fse, &inotify_fs_list, list) {
+		if (fse->fs_type == fs) {
+			ret = fse;
+			break;
+		}
+	}
+	read_unlock(&inotify_fs_lock);
+
+	return ret;
+}
+
+static inline void inotify_put_stackfs(struct inotify_stackfs *fs)
+{
+}
+
+int inotify_register_stackfs(struct inotify_stackfs *fs)
+{
+	int ret = 0;
+	struct inotify_stackfs *fse;
+
+	BUG_ON(IS_ERR_OR_NULL(fs->fs_type));
+	BUG_ON(IS_ERR_OR_NULL(fs->func));
+
+	INIT_LIST_HEAD(&fs->list);
+
+	write_lock(&inotify_fs_lock);
+	list_for_each_entry(fse, &inotify_fs_list, list) {
+		if (fse->fs_type == fs->fs_type) {
+			write_unlock(&inotify_fs_lock);
+			ret = -EBUSY;
+			goto out;
+		}
+	}
+	list_add_tail(&fs->list, &inotify_fs_list);
+	write_unlock(&inotify_fs_lock);
+
+out:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(inotify_register_stackfs);
+
+void inotify_unregister_stackfs(struct inotify_stackfs *fs)
+{
+	struct inotify_stackfs *fse, *n;
+
+	write_lock(&inotify_fs_lock);
+	list_for_each_entry_safe(fse, n, &inotify_fs_list, list) {
+		if (fse == fs) {
+			list_del(&fse->list);
+			break;
+		}
+	}
+	write_unlock(&inotify_fs_lock);
+}
+EXPORT_SYMBOL_GPL(inotify_unregister_stackfs);
+
+#else
+
+static inline struct inotify_stackfs* inotify_get_stackfs(struct path *path)
+{
+	return NULL;
+}
+
+static inline void inotify_put_stackfs(struct inotify_stackfs *fs)
+{
+}
+
+#endif /* CONFIG_INOTIFY_STACKFS */
+
+
 static inline __u32 inotify_arg_to_mask(u32 arg)
 {
 	__u32 mask;
@@ -329,7 +417,7 @@
 /*
  * find_inode - resolve a user-given path to a specific inode
  */
-static int inotify_find_inode(const char __user *dirname, struct path *path, unsigned flags)
+static inline int __inotify_find_inode(const char __user *dirname, struct path *path, unsigned flags)
 {
 	int error;
 
@@ -343,6 +431,27 @@
 	return error;
 }
 
+static int inotify_find_inode(const char __user *dirname, struct path *path, unsigned flags)
+{
+	int ret;
+	struct path tpath;
+	struct inotify_stackfs *fse;
+
+	ret = __inotify_find_inode(dirname, &tpath, flags);
+	if (ret)
+		return ret;
+	fse = inotify_get_stackfs(&tpath);
+	if (fse == NULL) {
+		*path = tpath;
+		return 0;
+	}
+	ret = fse->func(path, &tpath);
+	inotify_put_stackfs(fse);
+	path_put(&tpath);
+
+	return ret;
+}
+
 static int inotify_add_to_idr(struct idr *idr, spinlock_t *idr_lock,
 			      struct inotify_inode_mark *i_mark)
 {
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 9473e79..4af5048 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -19,6 +19,7 @@
 #include <linux/sched.h>
 #include <linux/statfs.h>
 #include <linux/seq_file.h>
+#include <linux/inotify.h>
 #include <linux/posix_acl_xattr.h>
 #include "overlayfs.h"
 
@@ -1395,13 +1396,39 @@
 };
 MODULE_ALIAS_FS("overlay");
 
+static int ovl_inotify_path(struct path *dst, struct path *src)
+{
+	ovl_path_real(src->dentry, dst);
+
+	path_get(dst);
+
+	return 0;
+}
+
+static struct inotify_stackfs ovl_inotify = {
+	.fs_type	= &ovl_fs_type,
+	.func		= ovl_inotify_path,
+};
+
 static int __init ovl_init(void)
 {
-	return register_filesystem(&ovl_fs_type);
+	int ret;
+
+	ret = register_filesystem(&ovl_fs_type);
+	if (ret)
+		return ret;
+	ret = inotify_register_stackfs(&ovl_inotify);
+	if (ret) {
+		pr_err("overlayfs: hook inotify error\n");
+		unregister_filesystem(&ovl_fs_type);
+	}
+
+	return ret;
 }
 
 static void __exit ovl_exit(void)
 {
+	inotify_unregister_stackfs(&ovl_inotify);
 	unregister_filesystem(&ovl_fs_type);
 }
 
diff --git a/include/linux/inotify.h b/include/linux/inotify.h
index 23aede0..2c4d7a1 100644
--- a/include/linux/inotify.h
+++ b/include/linux/inotify.h
@@ -8,6 +8,8 @@
 
 #include <linux/sysctl.h>
 #include <uapi/linux/inotify.h>
+#include <linux/list.h>
+#include <linux/fs.h>
 
 extern struct ctl_table inotify_table[]; /* for sysctl */
 
@@ -19,4 +21,30 @@ extern struct ctl_table inotify_table[]; /* for sysctl */
 			  IN_DONT_FOLLOW | IN_EXCL_UNLINK | IN_MASK_ADD | \
 			  IN_ISDIR | IN_ONESHOT)
 
+typedef int (*inotify_path_proc)(struct path *dst, struct path *src);
+
+struct inotify_stackfs {
+	struct list_head	list;		/* entry in inotify_fs_list */
+	struct file_system_type	*fs_type;	/* registed file_system_type */	
+	inotify_path_proc	func;		/* registed callback function */
+};
+
+#ifdef CONFIG_INOTIFY_STACKFS
+
+extern int inotify_register_stackfs(struct inotify_stackfs *fs);
+extern void inotify_unregister_stackfs(struct inotify_stackfs *fs);
+
+#else
+
+static inline int inotify_register_stackfs(struct inotify_stackfs *fs)
+{
+	return 0;
+}
+
+static inline void inotify_unregister_stackfs(struct inotify_stackfs *fs)
+{
+}
+
+#endif	/* CONFIG_INOTIFY_STACKFS */
+
 #endif	/* _LINUX_INOTIFY_H */

Reply to: