History

ps3flash: Cache the last accessed FLASH chunk

Add support for caching, to reduce FLASH wear when writing using small blocksizes. As we also don't care anymore about heads and tails in case of partial writes, this greatly simplifies the code for handling writes. Note: We don't bother caching reads smaller than the FLASH chunk size (256 KiB).

Geert Uytterhoeven committed 17 years ago

Commit 6bd57f21 parent a4e623f1 file · +104 −105Browse files

Showing the changes to drivers/char/ps3flash.c (1 of 1 file). Show all

Unified · Split

drivers/char/ps3flash.c+104−105
@@ -33,13 +33,16 @@ · 32 unmodified lines
3333
3434 struct ps3flash_private {
3535 struct mutex mutex; /* Bounce buffer mutex */
36+ u64 chunk_sectors;
37+ int tag; /* Start sector of buffer, -1 if invalid */
38+ bool dirty;
3639 };
3740
3841 static struct ps3_storage_device *ps3flash_dev;
3942
40−static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev,
41− u64 lpar, u64 start_sector,
42− u64 sectors, int write)
43+static int ps3flash_read_write_sectors(struct ps3_storage_device *dev,
44+ u64 lpar, u64 start_sector, u64 sectors,
45+ int write)
4346 {
4447 u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors,
4548 write);
@@ -48,33 +51,55 @@ static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev, · 2 unmodified lines
4851 __LINE__, write ? "write" : "read", res);
4952 return -EIO;
5053 }
51− return sectors;
54+ return 0;
5255 }
5356
54−static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev,
55− u64 start_sector, u64 sectors,
56− unsigned int sector_offset)
57+static int ps3flash_writeback(struct ps3_storage_device *dev)
5758 {
58− u64 max_sectors, lpar;
59+ struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
60+ int res;
5961
60− max_sectors = dev->bounce_size / dev->blk_size;
61− if (sectors > max_sectors) {
62− dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %llu\n",
63− __func__, __LINE__, max_sectors);
64− sectors = max_sectors;
65− }
62+ if (!priv->dirty || priv->tag < 0)
63+ return 0;
64+
65+ res = ps3flash_read_write_sectors(dev, dev->bounce_lpar, priv->tag,
66+ priv->chunk_sectors, 1);
67+ if (res)
68+ return res;
6669
67− lpar = dev->bounce_lpar + sector_offset * dev->blk_size;
68− return ps3flash_read_write_sectors(dev, lpar, start_sector, sectors,
69− 0);
70+ priv->dirty = false;
71+ return 0;
7072 }
7173
72−static ssize_t ps3flash_write_chunk(struct ps3_storage_device *dev,
73− u64 start_sector)
74+static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector,
75+ u64 sectors)
7476 {
75− u64 sectors = dev->bounce_size / dev->blk_size;
76− return ps3flash_read_write_sectors(dev, dev->bounce_lpar, start_sector,
77− sectors, 1);
77+ struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
78+ unsigned int tag, offset;
79+ u64 lpar;
80+ int res;
81+
82+ offset = start_sector % priv->chunk_sectors;
83+ tag = start_sector - offset;
84+ if (tag == priv->tag)
85+ return 0;
86+
87+ res = ps3flash_writeback(dev);
88+ if (res)
89+ return res;
90+
91+ priv->tag = -1;
92+
93+ lpar = dev->bounce_lpar + offset * dev->blk_size;
94+ res = ps3flash_read_write_sectors(dev, lpar, start_sector, sectors, 0);
95+ if (res)
96+ return res;
97+
98+ /* We don't bother caching reads smaller than the chunk size */
99+ if (sectors == priv->chunk_sectors)
100+ priv->tag = tag;
101+
102+ return 0;
78103 }
79104
80105 static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
@@ -109,8 +134,8 @@ static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf, · 28 unmodified lines
109134 {
110135 struct ps3_storage_device *dev = ps3flash_dev;
111136 struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
112− u64 size, start_sector, end_sector, offset;
113− ssize_t sectors_read;
137+ u64 size, start_sector, end_sector, offset, sectors;
138+ int res;
114139 size_t remaining, n;
115140 const void *src;
116141
@@ -130,30 +155,29 @@ static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf, · 13 unmodified lines
130155 }
131156
132157 start_sector = *pos / dev->blk_size;
133− offset = *pos % dev->blk_size;
158+ offset = *pos % dev->bounce_size;
134159 end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size);
135160
136161 remaining = count;
137162 do {
163+ sectors = min(end_sector - start_sector,
164+ priv->chunk_sectors -
165+ start_sector % priv->chunk_sectors);
166+
138167 mutex_lock(&priv->mutex);
139168
140− sectors_read = ps3flash_read_sectors(dev, start_sector,
141− end_sector-start_sector,
142− 0);
143− if (sectors_read < 0) {
144− mutex_unlock(&priv->mutex);
169+ res = ps3flash_fetch(dev, start_sector, sectors);
170+ if (res)
145171 goto fail;
146− }
147172
148− n = min_t(u64, remaining, sectors_read*dev->blk_size-offset);
149− src = dev->bounce_buf+offset;
173+ n = min_t(u64, remaining, dev->bounce_size - offset);
174+ src = dev->bounce_buf + offset;
150175 dev_dbg(&dev->sbd.core,
151176 "%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n",
152177 __func__, __LINE__, n, src, userbuf, kernelbuf);
153178 if (userbuf) {
154179 if (copy_to_user(userbuf, src, n)) {
155− mutex_unlock(&priv->mutex);
156− sectors_read = -EFAULT;
180+ res = -EFAULT;
157181 goto fail;
158182 }
159183 userbuf += n;
@@ -167,14 +191,15 @@ static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf, · 7 unmodified lines
167191
168192 *pos += n;
169193 remaining -= n;
170− start_sector += sectors_read;
194+ start_sector += sectors;
171195 offset = 0;
172196 } while (remaining > 0);
173197
174198 return count;
175199
176200 fail:
177− return sectors_read;
201+ mutex_unlock(&priv->mutex);
202+ return res;
178203 }
179204
180205 static ssize_t ps3flash_write(const char __user *userbuf,
@@ -182,11 +207,9 @@ static ssize_t ps3flash_write(const char __user *userbuf, · 1 unmodified line
182207 {
183208 struct ps3_storage_device *dev = ps3flash_dev;
184209 struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
185− u64 size, chunk_sectors, start_write_sector, end_write_sector,
186− end_read_sector, start_read_sector, head, tail, offset;
187− ssize_t res;
210+ u64 size, sector, offset;
211+ int res = 0;
188212 size_t remaining, n;
189− unsigned int sec_off;
190213 void *dst;
191214
192215 dev_dbg(&dev->sbd.core,
@@ -204,71 +227,23 @@ static ssize_t ps3flash_write(const char __user *userbuf, · 11 unmodified lines
204227 count = size - *pos;
205228 }
206229
207− chunk_sectors = dev->bounce_size / dev->blk_size;
208−
209− start_write_sector = *pos / dev->bounce_size * chunk_sectors;
230+ sector = *pos / dev->bounce_size * priv->chunk_sectors;
210231 offset = *pos % dev->bounce_size;
211− end_write_sector = DIV_ROUND_UP(*pos + count, dev->bounce_size) *
212− chunk_sectors;
213−
214− end_read_sector = DIV_ROUND_UP(*pos, dev->blk_size);
215− start_read_sector = (*pos + count) / dev->blk_size;
216−
217− /*
218− * As we have to write in 256 KiB chunks, while we can read in blk_size
219− * (usually 512 bytes) chunks, we perform the following steps:
220− * 1. Read from start_write_sector to end_read_sector ("head")
221− * 2. Read from start_read_sector to end_write_sector ("tail")
222− * 3. Copy data to buffer
223− * 4. Write from start_write_sector to end_write_sector
224− * All of this is complicated by using only one 256 KiB bounce buffer.
225− */
226−
227− head = end_read_sector - start_write_sector;
228− tail = end_write_sector - start_read_sector;
229232
230233 remaining = count;
231234 do {
235+ n = min_t(u64, remaining, dev->bounce_size - offset);
236+
232237 mutex_lock(&priv->mutex);
233238
234− if (end_read_sector >= start_read_sector) {
235− /* Merge head and tail */
236− dev_dbg(&dev->sbd.core,
237− "Merged head and tail: %llu sectors at %llu\n",
238− chunk_sectors, start_write_sector);
239− res = ps3flash_read_sectors(dev, start_write_sector,
240− chunk_sectors, 0);
241− if (res < 0)
242− goto fail;
243− } else {
244− if (head) {
245− /* Read head */
246− dev_dbg(&dev->sbd.core,
247− "head: %llu sectors at %llu\n", head,
248− start_write_sector);
249− res = ps3flash_read_sectors(dev,
250− start_write_sector,
251− head, 0);
252− if (res < 0)
253− goto fail;
254− }
255− if (start_read_sector <
256− start_write_sector+chunk_sectors) {
257− /* Read tail */
258− dev_dbg(&dev->sbd.core,
259− "tail: %llu sectors at %llu\n", tail,
260− start_read_sector);
261− sec_off = start_read_sector-start_write_sector;
262− res = ps3flash_read_sectors(dev,
263− start_read_sector,
264− tail, sec_off);
265− if (res < 0)
266− goto fail;
267− }
268− }
239+ if (n != dev->bounce_size)
240+ res = ps3flash_fetch(dev, sector, priv->chunk_sectors);
241+ else if (sector != priv->tag)
242+ res = ps3flash_writeback(dev);
243+ if (res)
244+ goto fail;
269245
270− n = min_t(u64, remaining, dev->bounce_size-offset);
271− dst = dev->bounce_buf+offset;
246+ dst = dev->bounce_buf + offset;
272247 dev_dbg(&dev->sbd.core,
273248 "%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p\n",
274249 __func__, __LINE__, n, userbuf, kernelbuf, dst);
@@ -284,16 +259,14 @@ static ssize_t ps3flash_write(const char __user *userbuf, · 9 unmodified lines
284259 kernelbuf += n;
285260 }
286261
287− res = ps3flash_write_chunk(dev, start_write_sector);
288− if (res < 0)
289− goto fail;
262+ priv->tag = sector;
263+ priv->dirty = true;
290264
291265 mutex_unlock(&priv->mutex);
292266
293267 *pos += n;
294268 remaining -= n;
295− start_write_sector += chunk_sectors;
296− head = 0;
269+ sector += priv->chunk_sectors;
297270 offset = 0;
298271 } while (remaining > 0);
299272
@@ -324,9 +297,31 @@ static ssize_t ps3flash_kernel_read(void *buf, size_t count, loff_t pos) · 24 unmodified lines
324297 static ssize_t ps3flash_kernel_write(const void *buf, size_t count,
325298 loff_t pos)
326299 {
327− return ps3flash_write(NULL, buf, count, &pos);
300+ ssize_t res;
301+ int wb;
302+
303+ res = ps3flash_write(NULL, buf, count, &pos);
304+ if (res < 0)
305+ return res;
306+
307+ /* Make kernel writes synchronous */
308+ wb = ps3flash_writeback(ps3flash_dev);
309+ if (wb)
310+ return wb;
311+
312+ return res;
328313 }
329314
315+static int ps3flash_flush(struct file *file, fl_owner_t id)
316+{
317+ return ps3flash_writeback(ps3flash_dev);
318+}
319+
320+static int ps3flash_fsync(struct file *file, struct dentry *dentry,
321+ int datasync)
322+{
323+ return ps3flash_writeback(ps3flash_dev);
324+}
330325
331326 static irqreturn_t ps3flash_interrupt(int irq, void *data)
332327 {
@@ -356,6 +351,8 @@ static const struct file_operations ps3flash_fops = { · 23 unmodified lines
356351 .llseek = ps3flash_llseek,
357352 .read = ps3flash_user_read,
358353 .write = ps3flash_user_write,
354+ .flush = ps3flash_flush,
355+ .fsync = ps3flash_fsync,
359356 };
360357
361358 static const struct ps3_os_area_flash_ops ps3flash_kernel_ops = {
@@ -411,9 +408,11 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev) · 49 unmodified lines
411408
412409 ps3_system_bus_set_drvdata(&dev->sbd, priv);
413410 mutex_init(&priv->mutex);
411+ priv->tag = -1;
414412
415413 dev->bounce_size = ps3flash_bounce_buffer.size;
416414 dev->bounce_buf = ps3flash_bounce_buffer.address;
415+ priv->chunk_sectors = dev->bounce_size / dev->blk_size;
417416
418417 error = ps3stor_setup(dev, ps3flash_interrupt);
419418 if (error)