vfs: Don't exchange short filenames unconditionally. (Closes: #763700)

svn path=/dists/sid/linux/; revision=21937
This commit is contained in:
Ben Hutchings 2014-10-10 02:24:26 +00:00
parent 1d43044d99
commit 53daffe22c
4 changed files with 160 additions and 0 deletions

2
debian/changelog vendored
View File

@ -225,6 +225,8 @@ linux (3.16.5-1) UNRELEASED; urgency=low
* radeon: Don't check for installed firmware if driver is built-in
(Closes: #763305)
* Bump ABI to 3
* vfs: fold swapping ->d_name.hash into switch_names()
* vfs: Don't exchange "short" filenames unconditionally. (Closes: #763700)
[ Aurelien Jarno ]
* [arm64] Change RTC_DRV_PL031 and RTC_DRV_XGENE from modules to built-ins

View File

@ -0,0 +1,41 @@
From: Linus Torvalds <torvalds@linux-foundation.org>
Date: Wed, 24 Sep 2014 12:27:39 -0700
Subject: fold swapping ->d_name.hash into switch_names()
Origin: https://git.kernel.org/linus/a28ddb87cdddb0db57466ba7f59f831002f4340c
and do it along with ->d_name.len there
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
[bwh: Backported to 3.16: change __d_materialise_dentry() as well]
---
fs/dcache.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -2441,7 +2441,7 @@ static void switch_names(struct dentry *
}
}
}
- swap(dentry->d_name.len, target->d_name.len);
+ swap(dentry->d_name.hash_len, target->d_name.hash_len);
}
static void dentry_lock_for_move(struct dentry *dentry, struct dentry *target)
@@ -2540,7 +2540,6 @@ static void __d_move(struct dentry *dent
/* Switch the names.. */
switch_names(dentry, target);
- swap(dentry->d_name.hash, target->d_name.hash);
/* ... and switch the parents */
if (IS_ROOT(dentry)) {
@@ -2679,7 +2678,6 @@ static void __d_materialise_dentry(struc
dparent = dentry->d_parent;
switch_names(dentry, anon);
- swap(dentry->d_name.hash, anon->d_name.hash);
dentry->d_parent = dentry;
list_del_init(&dentry->d_u.d_child);

View File

@ -0,0 +1,115 @@
From: Mikhail Efremov <sem@altlinux.org>
Date: Wed, 24 Sep 2014 22:14:33 +0400
Subject: vfs: Don't exchange "short" filenames unconditionally.
Origin: https://git.kernel.org/linus/d2fa4a8476b911782f7e5167db18770222ac40c3
Only exchange source and destination filenames
if flags contain RENAME_EXCHANGE.
In case if executable file was running and replaced by
other file /proc/PID/exe should still show correct file name,
not the old name of the file by which it was replaced.
The scenario when this bug manifests itself was like this:
* ALT Linux uses rpm and start-stop-daemon;
* during a package upgrade rpm creates a temporary file
for an executable to rename it upon successful unpacking;
* start-stop-daemon is run subsequently and it obtains
the (nonexistant) temporary filename via /proc/PID/exe
thus failing to identify the running process.
Note that "long" filenames (> DNAiME_INLINE_LEN) are still
exchanged without RENAME_EXCHANGE and this behaviour exists
long enough (should be fixed too apparently).
So this patch is just an interim workaround that restores
behavior for "short" names as it was before changes
introduced by commit da1ce0670c14 ("vfs: add cross-rename").
See https://lkml.org/lkml/2014/9/7/6 for details.
AV: the comments about being more careful with ->d_name.hash
than with ->d_name.name are from back in 2.3.40s; they
became obsolete by 2.3.60s, when we started to unhash the
target instead of swapping hash chain positions followed
by d_delete() as we used to do when dcache was first
introduced.
Acked-by: Miklos Szeredi <mszeredi@suse.cz>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: linux-fsdevel@vger.kernel.org
Cc: stable@vger.kernel.org
Fixes: da1ce0670c14 "vfs: add cross-rename"
Signed-off-by: Mikhail Efremov <sem@altlinux.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
[bwh: Backported to 3.16:
- Adjust context
- Change __d_materialise_dentry() as well]
---
fs/dcache.c | 27 ++++++++++++++++++---------
1 file changed, 18 insertions(+), 9 deletions(-)
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -2401,7 +2401,8 @@ void dentry_update_name_case(struct dent
}
EXPORT_SYMBOL(dentry_update_name_case);
-static void switch_names(struct dentry *dentry, struct dentry *target)
+static void switch_names(struct dentry *dentry, struct dentry *target,
+ bool exchange)
{
if (dname_external(target)) {
if (dname_external(dentry)) {
@@ -2435,6 +2436,12 @@ static void switch_names(struct dentry *
*/
unsigned int i;
BUILD_BUG_ON(!IS_ALIGNED(DNAME_INLINE_LEN, sizeof(long)));
+ if (!exchange) {
+ memcpy(dentry->d_iname, target->d_name.name,
+ target->d_name.len + 1);
+ dentry->d_name.hash_len = target->d_name.hash_len;
+ return;
+ }
for (i = 0; i < DNAME_INLINE_LEN / sizeof(long); i++) {
swap(((long *) &dentry->d_iname)[i],
((long *) &target->d_iname)[i]);
@@ -2484,12 +2491,15 @@ static void dentry_unlock_parents_for_mo
* When switching names, the actual string doesn't strictly have to
* be preserved in the target - because we're dropping the target
* anyway. As such, we can just do a simple memcpy() to copy over
- * the new name before we switch.
- *
- * Note that we have to be a lot more careful about getting the hash
- * switched - we have to switch the hash value properly even if it
- * then no longer matches the actual (corrupted) string of the target.
- * The hash value has to match the hash queue that the dentry is on..
+ * the new name before we switch, unless we are going to rehash
+ * it. Note that if we *do* unhash the target, we are not allowed
+ * to rehash it without giving it a new name/hash key - whether
+ * we swap or overwrite the names here, resulting name won't match
+ * the reality in filesystem; it's only there for d_path() purposes.
+ * Note that all of this is happening under rename_lock, so the
+ * any hash lookup seeing it in the middle of manipulations will
+ * be discarded anyway. So we do not care what happens to the hash
+ * key in that case.
*/
/*
* __d_move - move a dentry
@@ -2539,7 +2549,7 @@ static void __d_move(struct dentry *dent
list_del(&target->d_u.d_child);
/* Switch the names.. */
- switch_names(dentry, target);
+ switch_names(dentry, target, exchange);
/* ... and switch the parents */
if (IS_ROOT(dentry)) {
@@ -2677,7 +2687,7 @@ static void __d_materialise_dentry(struc
dparent = dentry->d_parent;
- switch_names(dentry, anon);
+ switch_names(dentry, anon, false);
dentry->d_parent = dentry;
list_del_init(&dentry->d_u.d_child);

View File

@ -135,3 +135,5 @@ debian/revert-staging-sm7xxfb-remove-driver.patch
features/all/sfc-Adding-PCI-ID-for-Solarflare-7000-series-40G-net.patch
features/all/sfc-Add-40G-link-capability-decoding.patch
bugfix/s390/s390-3215-fix-tty-output-containing-tabs.patch
bugfix/all/fold-swapping-d_name.hash-into-switch_names.patch
bugfix/all/vfs-Don-t-exchange-short-filenames-unconditionally.patch