diff options
author | Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz> | 2014-01-28 18:11:33 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-02-02 19:24:07 -0500 |
commit | 1c0b8a7a62c3d3ebf53a8e40cc6da22f5e192d63 (patch) | |
tree | 3ecae7ff3391cfcd628c2d78acee83a78e9de66e /fs | |
parent | 2cbe5c76fc5e38e9af4b709593146e4b8272b69e (diff) |
hpfs: optimize quad buffer loading
HPFS needs to load 4 consecutive 512-byte sectors when accessing the
directory nodes or bitmaps. We can't switch to 2048-byte block size
because files are allocated in the units of 512-byte sectors.
Previously, the driver would allocate a 2048-byte area using kmalloc,
copy the data from four buffers to this area and eventually copy them
back if they were modified.
In the current implementation of the buffer cache, buffers are allocated
in the pagecache. That means that 4 consecutive 512-byte buffers are
stored in consecutive areas in the kernel address space. So, we don't
need to allocate extra memory and copy the content of the buffers there.
This patch optimizes the code to avoid copying the buffers. It checks
if the four buffers are stored in contiguous memory - if they are not,
it falls back to allocating a 2048-byte area and copying data there.
Signed-off-by: Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/hpfs/buffer.c | 96 |
1 files changed, 50 insertions, 46 deletions
diff --git a/fs/hpfs/buffer.c b/fs/hpfs/buffer.c index 4d0a1afa058c..139ef1684d07 100644 --- a/fs/hpfs/buffer.c +++ b/fs/hpfs/buffer.c | |||
@@ -86,7 +86,6 @@ void *hpfs_get_sector(struct super_block *s, unsigned secno, struct buffer_head | |||
86 | void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffer_head *qbh, | 86 | void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffer_head *qbh, |
87 | int ahead) | 87 | int ahead) |
88 | { | 88 | { |
89 | struct buffer_head *bh; | ||
90 | char *data; | 89 | char *data; |
91 | 90 | ||
92 | hpfs_lock_assert(s); | 91 | hpfs_lock_assert(s); |
@@ -100,34 +99,32 @@ void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffe | |||
100 | 99 | ||
101 | hpfs_prefetch_sectors(s, secno, 4 + ahead); | 100 | hpfs_prefetch_sectors(s, secno, 4 + ahead); |
102 | 101 | ||
102 | if (!(qbh->bh[0] = sb_bread(s, secno + 0))) goto bail0; | ||
103 | if (!(qbh->bh[1] = sb_bread(s, secno + 1))) goto bail1; | ||
104 | if (!(qbh->bh[2] = sb_bread(s, secno + 2))) goto bail2; | ||
105 | if (!(qbh->bh[3] = sb_bread(s, secno + 3))) goto bail3; | ||
106 | |||
107 | if (likely(qbh->bh[1]->b_data == qbh->bh[0]->b_data + 1 * 512) && | ||
108 | likely(qbh->bh[2]->b_data == qbh->bh[0]->b_data + 2 * 512) && | ||
109 | likely(qbh->bh[3]->b_data == qbh->bh[0]->b_data + 3 * 512)) { | ||
110 | return qbh->data = qbh->bh[0]->b_data; | ||
111 | } | ||
112 | |||
103 | qbh->data = data = kmalloc(2048, GFP_NOFS); | 113 | qbh->data = data = kmalloc(2048, GFP_NOFS); |
104 | if (!data) { | 114 | if (!data) { |
105 | printk("HPFS: hpfs_map_4sectors: out of memory\n"); | 115 | printk("HPFS: hpfs_map_4sectors: out of memory\n"); |
106 | goto bail; | 116 | goto bail4; |
107 | } | 117 | } |
108 | 118 | ||
109 | qbh->bh[0] = bh = sb_bread(s, secno); | 119 | memcpy(data + 0 * 512, qbh->bh[0]->b_data, 512); |
110 | if (!bh) | 120 | memcpy(data + 1 * 512, qbh->bh[1]->b_data, 512); |
111 | goto bail0; | 121 | memcpy(data + 2 * 512, qbh->bh[2]->b_data, 512); |
112 | memcpy(data, bh->b_data, 512); | 122 | memcpy(data + 3 * 512, qbh->bh[3]->b_data, 512); |
113 | |||
114 | qbh->bh[1] = bh = sb_bread(s, secno + 1); | ||
115 | if (!bh) | ||
116 | goto bail1; | ||
117 | memcpy(data + 512, bh->b_data, 512); | ||
118 | |||
119 | qbh->bh[2] = bh = sb_bread(s, secno + 2); | ||
120 | if (!bh) | ||
121 | goto bail2; | ||
122 | memcpy(data + 2 * 512, bh->b_data, 512); | ||
123 | |||
124 | qbh->bh[3] = bh = sb_bread(s, secno + 3); | ||
125 | if (!bh) | ||
126 | goto bail3; | ||
127 | memcpy(data + 3 * 512, bh->b_data, 512); | ||
128 | 123 | ||
129 | return data; | 124 | return data; |
130 | 125 | ||
126 | bail4: | ||
127 | brelse(qbh->bh[3]); | ||
131 | bail3: | 128 | bail3: |
132 | brelse(qbh->bh[2]); | 129 | brelse(qbh->bh[2]); |
133 | bail2: | 130 | bail2: |
@@ -135,9 +132,6 @@ void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffe | |||
135 | bail1: | 132 | bail1: |
136 | brelse(qbh->bh[0]); | 133 | brelse(qbh->bh[0]); |
137 | bail0: | 134 | bail0: |
138 | kfree(data); | ||
139 | printk("HPFS: hpfs_map_4sectors: read error\n"); | ||
140 | bail: | ||
141 | return NULL; | 135 | return NULL; |
142 | } | 136 | } |
143 | 137 | ||
@@ -155,44 +149,54 @@ void *hpfs_get_4sectors(struct super_block *s, unsigned secno, | |||
155 | return NULL; | 149 | return NULL; |
156 | } | 150 | } |
157 | 151 | ||
158 | /*return hpfs_map_4sectors(s, secno, qbh, 0);*/ | 152 | if (!hpfs_get_sector(s, secno + 0, &qbh->bh[0])) goto bail0; |
153 | if (!hpfs_get_sector(s, secno + 1, &qbh->bh[1])) goto bail1; | ||
154 | if (!hpfs_get_sector(s, secno + 2, &qbh->bh[2])) goto bail2; | ||
155 | if (!hpfs_get_sector(s, secno + 3, &qbh->bh[3])) goto bail3; | ||
156 | |||
157 | if (likely(qbh->bh[1]->b_data == qbh->bh[0]->b_data + 1 * 512) && | ||
158 | likely(qbh->bh[2]->b_data == qbh->bh[0]->b_data + 2 * 512) && | ||
159 | likely(qbh->bh[3]->b_data == qbh->bh[0]->b_data + 3 * 512)) { | ||
160 | return qbh->data = qbh->bh[0]->b_data; | ||
161 | } | ||
162 | |||
159 | if (!(qbh->data = kmalloc(2048, GFP_NOFS))) { | 163 | if (!(qbh->data = kmalloc(2048, GFP_NOFS))) { |
160 | printk("HPFS: hpfs_get_4sectors: out of memory\n"); | 164 | printk("HPFS: hpfs_get_4sectors: out of memory\n"); |
161 | return NULL; | 165 | goto bail4; |
162 | } | 166 | } |
163 | if (!(hpfs_get_sector(s, secno, &qbh->bh[0]))) goto bail0; | ||
164 | if (!(hpfs_get_sector(s, secno + 1, &qbh->bh[1]))) goto bail1; | ||
165 | if (!(hpfs_get_sector(s, secno + 2, &qbh->bh[2]))) goto bail2; | ||
166 | if (!(hpfs_get_sector(s, secno + 3, &qbh->bh[3]))) goto bail3; | ||
167 | memcpy(qbh->data, qbh->bh[0]->b_data, 512); | ||
168 | memcpy(qbh->data + 512, qbh->bh[1]->b_data, 512); | ||
169 | memcpy(qbh->data + 2*512, qbh->bh[2]->b_data, 512); | ||
170 | memcpy(qbh->data + 3*512, qbh->bh[3]->b_data, 512); | ||
171 | return qbh->data; | 167 | return qbh->data; |
172 | 168 | ||
173 | bail3: brelse(qbh->bh[2]); | 169 | bail4: |
174 | bail2: brelse(qbh->bh[1]); | 170 | brelse(qbh->bh[3]); |
175 | bail1: brelse(qbh->bh[0]); | 171 | bail3: |
176 | bail0: | 172 | brelse(qbh->bh[2]); |
173 | bail2: | ||
174 | brelse(qbh->bh[1]); | ||
175 | bail1: | ||
176 | brelse(qbh->bh[0]); | ||
177 | bail0: | ||
177 | return NULL; | 178 | return NULL; |
178 | } | 179 | } |
179 | 180 | ||
180 | 181 | ||
181 | void hpfs_brelse4(struct quad_buffer_head *qbh) | 182 | void hpfs_brelse4(struct quad_buffer_head *qbh) |
182 | { | 183 | { |
183 | brelse(qbh->bh[3]); | 184 | if (unlikely(qbh->data != qbh->bh[0]->b_data)) |
184 | brelse(qbh->bh[2]); | 185 | kfree(qbh->data); |
185 | brelse(qbh->bh[1]); | ||
186 | brelse(qbh->bh[0]); | 186 | brelse(qbh->bh[0]); |
187 | kfree(qbh->data); | 187 | brelse(qbh->bh[1]); |
188 | brelse(qbh->bh[2]); | ||
189 | brelse(qbh->bh[3]); | ||
188 | } | 190 | } |
189 | 191 | ||
190 | void hpfs_mark_4buffers_dirty(struct quad_buffer_head *qbh) | 192 | void hpfs_mark_4buffers_dirty(struct quad_buffer_head *qbh) |
191 | { | 193 | { |
192 | memcpy(qbh->bh[0]->b_data, qbh->data, 512); | 194 | if (unlikely(qbh->data != qbh->bh[0]->b_data)) { |
193 | memcpy(qbh->bh[1]->b_data, qbh->data + 512, 512); | 195 | memcpy(qbh->bh[0]->b_data, qbh->data + 0 * 512, 512); |
194 | memcpy(qbh->bh[2]->b_data, qbh->data + 2 * 512, 512); | 196 | memcpy(qbh->bh[1]->b_data, qbh->data + 1 * 512, 512); |
195 | memcpy(qbh->bh[3]->b_data, qbh->data + 3 * 512, 512); | 197 | memcpy(qbh->bh[2]->b_data, qbh->data + 2 * 512, 512); |
198 | memcpy(qbh->bh[3]->b_data, qbh->data + 3 * 512, 512); | ||
199 | } | ||
196 | mark_buffer_dirty(qbh->bh[0]); | 200 | mark_buffer_dirty(qbh->bh[0]); |
197 | mark_buffer_dirty(qbh->bh[1]); | 201 | mark_buffer_dirty(qbh->bh[1]); |
198 | mark_buffer_dirty(qbh->bh[2]); | 202 | mark_buffer_dirty(qbh->bh[2]); |