]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 7 Aug 2015 05:34:51 +0000 (22:34 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 7 Aug 2015 05:34:51 +0000 (22:34 -0700)
added patches:
freeing-unlinked-file-indefinitely-delayed.patch

queue-3.10/freeing-unlinked-file-indefinitely-delayed.patch [new file with mode: 0644]
queue-3.10/series

diff --git a/queue-3.10/freeing-unlinked-file-indefinitely-delayed.patch b/queue-3.10/freeing-unlinked-file-indefinitely-delayed.patch
new file mode 100644 (file)
index 0000000..cff0698
--- /dev/null
@@ -0,0 +1,89 @@
+From 75a6f82a0d10ef8f13cd8fe7212911a0252ab99e Mon Sep 17 00:00:00 2001
+From: Al Viro <viro@ZenIV.linux.org.uk>
+Date: Wed, 8 Jul 2015 02:42:38 +0100
+Subject: freeing unlinked file indefinitely delayed
+
+From: Al Viro <viro@ZenIV.linux.org.uk>
+
+commit 75a6f82a0d10ef8f13cd8fe7212911a0252ab99e upstream.
+
+       Normally opening a file, unlinking it and then closing will have
+the inode freed upon close() (provided that it's not otherwise busy and
+has no remaining links, of course).  However, there's one case where that
+does *not* happen.  Namely, if you open it by fhandle with cold dcache,
+then unlink() and close().
+
+       In normal case you get d_delete() in unlink(2) notice that dentry
+is busy and unhash it; on the final dput() it will be forcibly evicted from
+dcache, triggering iput() and inode removal.  In this case, though, we end
+up with *two* dentries - disconnected (created by open-by-fhandle) and
+regular one (used by unlink()).  The latter will have its reference to inode
+dropped just fine, but the former will not - it's considered hashed (it
+is on the ->s_anon list), so it will stay around until the memory pressure
+will finally do it in.  As the result, we have the final iput() delayed
+indefinitely.  It's trivial to reproduce -
+
+void flush_dcache(void)
+{
+        system("mount -o remount,rw /");
+}
+
+static char buf[20 * 1024 * 1024];
+
+main()
+{
+        int fd;
+        union {
+                struct file_handle f;
+                char buf[MAX_HANDLE_SZ];
+        } x;
+        int m;
+
+        x.f.handle_bytes = sizeof(x);
+        chdir("/root");
+        mkdir("foo", 0700);
+        fd = open("foo/bar", O_CREAT | O_RDWR, 0600);
+        close(fd);
+        name_to_handle_at(AT_FDCWD, "foo/bar", &x.f, &m, 0);
+        flush_dcache();
+        fd = open_by_handle_at(AT_FDCWD, &x.f, O_RDWR);
+        unlink("foo/bar");
+        write(fd, buf, sizeof(buf));
+        system("df .");                        /* 20Mb eaten */
+        close(fd);
+        system("df .");                        /* should've freed those 20Mb */
+        flush_dcache();
+        system("df .");                        /* should be the same as #2 */
+}
+
+will spit out something like
+Filesystem     1K-blocks   Used Available Use% Mounted on
+/dev/root         322023 303843      1131 100% /
+Filesystem     1K-blocks   Used Available Use% Mounted on
+/dev/root         322023 303843      1131 100% /
+Filesystem     1K-blocks   Used Available Use% Mounted on
+/dev/root         322023 283282     21692  93% /
+- inode gets freed only when dentry is finally evicted (here we trigger
+than by remount; normally it would've happened in response to memory
+pressure hell knows when).
+
+Acked-by: J. Bruce Fields <bfields@fieldses.org>
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/dcache.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/fs/dcache.c
++++ b/fs/dcache.c
+@@ -520,6 +520,9 @@ repeat:
+               return;
+       }
++      if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED))
++              goto kill_it;
++
+       if (dentry->d_flags & DCACHE_OP_DELETE) {
+               if (dentry->d_op->d_delete(dentry))
+                       goto kill_it;
index ff962f6c2557e3ae4c95c53f7cf03d3b6d002cdb..f858ec4eec4ccb081fd94bb495ce0fd0ef22a274 100644 (file)
@@ -1 +1,2 @@
 mm-avoid-setting-up-anonymous-pages-into-file-mapping.patch
+freeing-unlinked-file-indefinitely-delayed.patch