Message ID | 20110411224452.4a5149da@sf (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
I think the problem here is that memcpy beahviour changed in recent glibc in this regard see here http://lwn.net/Articles/414467/ On Mon, 2011-04-11 at 22:44 +0300, Sergei Trofimovich wrote: > > Fix data corruption caused by memcpy() usage on overlapping data. > > I've observed it first when found out usermode linux crash on btrfs. > > Changes since v2: > - Code style cleanup > - 2 versions of patch: BUG_ON and WARN_ON variants, > _but_ see below why I prefer BUG_ON > > Changes since v1: > > > else > > src_kaddr = dst_kaddr; > > > > + BUG_ON(abs(src_off - dst_off) < len); > > memcpy(dst_kaddr + dst_off, src_kaddr + src_off, len); > > Too eager BUG_ON. Now used only for src_page == dst_page. > > > - if (dst_offset < src_offset) { > > + if (abs(dst_offset - src_offset) >= len) { > > abs() is not a good thing to use un unsigned values. aded helper overlapping_areas. > > On Mon, 11 Apr 2011 11:37:57 -0400 > Josef Bacik <josef@redhat.com> wrote: > > > + { > > you will want to turn that into > > > > if (dst_page != src_page) { > > done > > > Also maybe BUG_ON() is a little strong, since the kernel will do this > > right, it just screws up UML. So maybe just do a WARN_ON() so we notice > > it. Thanks, > > I'm afaid I didn't understand this part. The commit I've found a deviation > was linux's implementation of memcpy (UML uses it as kernel does). Why the > kernel differs to UML in that respect? Seems I don't know/understand something > fundamental here. > So, if data overlaps - it's a moment before data corruption, thus BUG_ON. > > Another thought is (if memcpy semantics differ from standard C's function): > does linux's memcpy guarantee copying direction behaviour? > If it does, then it's really a weird memmove and x86/memcpy_64.S is a bit broken. > > Attached both patches, I personally like BUG_ON variant. > Pick the one you like more :] > > Thanks for the feedback! >
On 04/11/2011 03:44 PM, Sergei Trofimovich wrote: >> Fix data corruption caused by memcpy() usage on overlapping data. >> I've observed it first when found out usermode linux crash on btrfs. > > Changes since v2: > - Code style cleanup > - 2 versions of patch: BUG_ON and WARN_ON variants, > _but_ see below why I prefer BUG_ON > > Changes since v1: > >> else >> src_kaddr = dst_kaddr; >> >> + BUG_ON(abs(src_off - dst_off)< len); >> memcpy(dst_kaddr + dst_off, src_kaddr + src_off, len); > > Too eager BUG_ON. Now used only for src_page == dst_page. > >> - if (dst_offset< src_offset) { >> + if (abs(dst_offset - src_offset)>= len) { > > abs() is not a good thing to use un unsigned values. aded helper overlapping_areas. > > On Mon, 11 Apr 2011 11:37:57 -0400 > Josef Bacik<josef@redhat.com> wrote: > >> + { >> you will want to turn that into >> >> if (dst_page != src_page) { > > done > >> Also maybe BUG_ON() is a little strong, since the kernel will do this >> right, it just screws up UML. So maybe just do a WARN_ON() so we notice >> it. Thanks, > > I'm afaid I didn't understand this part. The commit I've found a deviation > was linux's implementation of memcpy (UML uses it as kernel does). Why the > kernel differs to UML in that respect? Seems I don't know/understand something > fundamental here. > So, if data overlaps - it's a moment before data corruption, thus BUG_ON. > > Another thought is (if memcpy semantics differ from standard C's function): > does linux's memcpy guarantee copying direction behaviour? > If it does, then it's really a weird memmove and x86/memcpy_64.S is a bit broken. > > Attached both patches, I personally like BUG_ON variant. > Pick the one you like more :] > > Thanks for the feedback! > Fair enough, BUG_ON() it is. Repost that version and you can add my Reviewed-by: Josef Bacik <josef@redhat.com> Thanks, Josef -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Mon, 11 Apr 2011 15:50:48 -0400 Josef Bacik <josef@redhat.com> wrote: > On 04/11/2011 03:44 PM, Sergei Trofimovich wrote: > >> Fix data corruption caused by memcpy() usage on overlapping data. > >> I've observed it first when found out usermode linux crash on btrfs. ... > Fair enough, BUG_ON() it is. Repost that version and you can add my > > Reviewed-by: Josef Bacik <josef@redhat.com> Thank you! Added and resent as: http://www.mail-archive.com/linux-btrfs@vger.kernel.org/msg09357.html
Excerpts from Sergei Trofimovich's message of 2011-04-12 17:23:33 -0400: > On Mon, 11 Apr 2011 15:50:48 -0400 > Josef Bacik <josef@redhat.com> wrote: > > > On 04/11/2011 03:44 PM, Sergei Trofimovich wrote: > > >> Fix data corruption caused by memcpy() usage on overlapping data. > > >> I've observed it first when found out usermode linux crash on btrfs. > > ... > > > Fair enough, BUG_ON() it is. Repost that version and you can add my > > > > Reviewed-by: Josef Bacik <josef@redhat.com> > > Thank you! Added and resent as: > http://www.mail-archive.com/linux-btrfs@vger.kernel.org/msg09357.html > This is in the master branch now, please give it another test. Thanks a lot for bisecting down and patching! -chris -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Wed, 13 Apr 2011 07:32:59 -0400 Chris Mason <chris.mason@oracle.com> wrote: > This is in the master branch now, please give it another test. Thanks a > lot for bisecting down and patching! Tested on btrfs-unstable/master. Works correctly. Reverting 3387206f26e1b48703e810175b98611a4fd8e8ea (to make sure) on top of master returns panic. Thank you!
From 51602c049c4583fc7b1ef454f630138f12dba70e Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich <slyfox@gentoo.org> Date: Sun, 10 Apr 2011 23:19:53 +0300 Subject: [PATCH 1/2] btrfs: properly handle overlapping areas in memmove_extent_buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix data corruption caused by memcpy() usage on overlapping data. I've observed it first when found out usermode linux crash on btrfs. ?all chain is the following: ------------[ cut here ]------------ WARNING: at /home/slyfox/linux-2.6/fs/btrfs/extent_io.c:3900 memcpy_extent_buffer+0x1a5/0x219() Call Trace: 6fa39a58: [<601b495e>] _raw_spin_unlock_irqrestore+0x18/0x1c 6fa39a68: [<60029ad9>] warn_slowpath_common+0x59/0x70 6fa39aa8: [<60029b05>] warn_slowpath_null+0x15/0x17 6fa39ab8: [<600efc97>] memcpy_extent_buffer+0x1a5/0x219 6fa39b48: [<600efd9f>] memmove_extent_buffer+0x94/0x208 6fa39bc8: [<600becbf>] btrfs_del_items+0x214/0x473 6fa39c78: [<600ce1b0>] btrfs_delete_one_dir_name+0x7c/0xda 6fa39cc8: [<600dad6b>] __btrfs_unlink_inode+0xad/0x25d 6fa39d08: [<600d7864>] btrfs_start_transaction+0xe/0x10 6fa39d48: [<600dc9ff>] btrfs_unlink_inode+0x1b/0x3b 6fa39d78: [<600e04bc>] btrfs_unlink+0x70/0xef 6fa39dc8: [<6007f0d0>] vfs_unlink+0x58/0xa3 6fa39df8: [<60080278>] do_unlinkat+0xd4/0x162 6fa39e48: [<600517db>] call_rcu_sched+0xe/0x10 6fa39e58: [<600452a8>] __put_cred+0x58/0x5a 6fa39e78: [<6007446c>] sys_faccessat+0x154/0x166 6fa39ed8: [<60080317>] sys_unlink+0x11/0x13 6fa39ee8: [<60016b80>] handle_syscall+0x58/0x70 6fa39f08: [<60021377>] userspace+0x2d4/0x381 6fa39fc8: [<60014507>] fork_handler+0x62/0x69 ---[ end trace 70b0ca2ef0266b93 ]--- http://www.mail-archive.com/linux-btrfs@vger.kernel.org/msg09302.html Signed-off-by: Sergei Trofimovich <slyfox@gentoo.org> --- fs/btrfs/extent_io.c | 14 +++++++++++--- 1 files changed, 11 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 20ddb28..2655aef 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -3885,6 +3885,12 @@ static void move_pages(struct page *dst_page, struct page *src_page, kunmap_atomic(dst_kaddr, KM_USER0); } +static inline bool areas_overlap(unsigned long src, unsigned long dst, unsigned long len) +{ + unsigned long distance = (src > dst) ? src - dst : dst - src; + return distance < len; +} + static void copy_pages(struct page *dst_page, struct page *src_page, unsigned long dst_off, unsigned long src_off, unsigned long len) @@ -3892,10 +3898,12 @@ static void copy_pages(struct page *dst_page, struct page *src_page, char *dst_kaddr = kmap_atomic(dst_page, KM_USER0); char *src_kaddr; - if (dst_page != src_page) + if (dst_page != src_page) { src_kaddr = kmap_atomic(src_page, KM_USER1); - else + } else { src_kaddr = dst_kaddr; + WARN_ON(areas_overlap(src_off, dst_off, len)); + } memcpy(dst_kaddr + dst_off, src_kaddr + src_off, len); kunmap_atomic(dst_kaddr, KM_USER0); @@ -3970,7 +3978,7 @@ void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset, "len %lu len %lu\n", dst_offset, len, dst->len); BUG_ON(1); } - if (dst_offset < src_offset) { + if (!areas_overlap(src_offset, dst_offset, len)) { memcpy_extent_buffer(dst, dst_offset, src_offset, len); return; } -- 1.7.3.4