summaryrefslogtreecommitdiffstats
path: root/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.24/0046-block-fix-infinite-loop-in-__getblk_slow.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.24/0046-block-fix-infinite-loop-in-__getblk_slow.patch')
-rw-r--r--recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.24/0046-block-fix-infinite-loop-in-__getblk_slow.patch116
1 files changed, 116 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.24/0046-block-fix-infinite-loop-in-__getblk_slow.patch b/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.24/0046-block-fix-infinite-loop-in-__getblk_slow.patch
new file mode 100644
index 00000000..6c5d9b8b
--- /dev/null
+++ b/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.24/0046-block-fix-infinite-loop-in-__getblk_slow.patch
@@ -0,0 +1,116 @@
1From 898f4d272514d19aafee8cd66b796c0553fca080 Mon Sep 17 00:00:00 2001
2From: Jeff Moyer <jmoyer@redhat.com>
3Date: Thu, 12 Jul 2012 09:43:14 -0400
4Subject: [PATCH 046/109] block: fix infinite loop in __getblk_slow
5
6commit 91f68c89d8f35fe98ea04159b9a3b42d0149478f upstream.
7
8Commit 080399aaaf35 ("block: don't mark buffers beyond end of disk as
9mapped") exposed a bug in __getblk_slow that causes mount to hang as it
10loops infinitely waiting for a buffer that lies beyond the end of the
11disk to become uptodate.
12
13The problem was initially reported by Torsten Hilbrich here:
14
15 https://lkml.org/lkml/2012/6/18/54
16
17and also reported independently here:
18
19 http://www.sysresccd.org/forums/viewtopic.php?f=13&t=4511
20
21and then Richard W.M. Jones and Marcos Mello noted a few separate
22bugzillas also associated with the same issue. This patch has been
23confirmed to fix:
24
25 https://bugzilla.redhat.com/show_bug.cgi?id=835019
26
27The main problem is here, in __getblk_slow:
28
29 for (;;) {
30 struct buffer_head * bh;
31 int ret;
32
33 bh = __find_get_block(bdev, block, size);
34 if (bh)
35 return bh;
36
37 ret = grow_buffers(bdev, block, size);
38 if (ret < 0)
39 return NULL;
40 if (ret == 0)
41 free_more_memory();
42 }
43
44__find_get_block does not find the block, since it will not be marked as
45mapped, and so grow_buffers is called to fill in the buffers for the
46associated page. I believe the for (;;) loop is there primarily to
47retry in the case of memory pressure keeping grow_buffers from
48succeeding. However, we also continue to loop for other cases, like the
49block lying beond the end of the disk. So, the fix I came up with is to
50only loop when grow_buffers fails due to memory allocation issues
51(return value of 0).
52
53The attached patch was tested by myself, Torsten, and Rich, and was
54found to resolve the problem in call cases.
55
56Signed-off-by: Jeff Moyer <jmoyer@redhat.com>
57Reported-and-Tested-by: Torsten Hilbrich <torsten.hilbrich@secunet.com>
58Tested-by: Richard W.M. Jones <rjones@redhat.com>
59Reviewed-by: Josh Boyer <jwboyer@redhat.com>
60[ Jens is on vacation, taking this directly - Linus ]
61--
62Stable Notes: this patch requires backport to 3.0, 3.2 and 3.3.
63Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
64Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
65---
66 fs/buffer.c | 22 +++++++++++++---------
67 1 files changed, 13 insertions(+), 9 deletions(-)
68
69diff --git a/fs/buffer.c b/fs/buffer.c
70index c807931..4115eca 100644
71--- a/fs/buffer.c
72+++ b/fs/buffer.c
73@@ -1087,6 +1087,9 @@ grow_buffers(struct block_device *bdev, sector_t block, int size)
74 static struct buffer_head *
75 __getblk_slow(struct block_device *bdev, sector_t block, int size)
76 {
77+ int ret;
78+ struct buffer_head *bh;
79+
80 /* Size must be multiple of hard sectorsize */
81 if (unlikely(size & (bdev_logical_block_size(bdev)-1) ||
82 (size < 512 || size > PAGE_SIZE))) {
83@@ -1099,20 +1102,21 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size)
84 return NULL;
85 }
86
87- for (;;) {
88- struct buffer_head * bh;
89- int ret;
90+retry:
91+ bh = __find_get_block(bdev, block, size);
92+ if (bh)
93+ return bh;
94
95+ ret = grow_buffers(bdev, block, size);
96+ if (ret == 0) {
97+ free_more_memory();
98+ goto retry;
99+ } else if (ret > 0) {
100 bh = __find_get_block(bdev, block, size);
101 if (bh)
102 return bh;
103-
104- ret = grow_buffers(bdev, block, size);
105- if (ret < 0)
106- return NULL;
107- if (ret == 0)
108- free_more_memory();
109 }
110+ return NULL;
111 }
112
113 /*
114--
1151.7.7.6
116