fs/fat: Do not write unmodified fat entries to disk
The code caches 6 sectors of the FAT. On FAT traversal, the old contents
needs to be flushed to disk, but only if any FAT entries had been modified.
Explicitly flag the buffer on modification.
Currently, creating a new file traverses the whole FAT up to the first
free cluster and rewrites the on-disk blocks.
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>
diff --git a/fs/fat/fat.c b/fs/fat/fat.c
index 826bd85..df9f2b5 100644
--- a/fs/fat/fat.c
+++ b/fs/fat/fat.c
@@ -876,6 +876,7 @@
}
mydata->fatbufnum = -1;
+ mydata->fat_dirty = 0;
mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE);
if (mydata->fatbuf == NULL) {
debug("Error: allocating memory\n");
diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c
index 961ccd8..babe9c8 100644
--- a/fs/fat/fat_write.c
+++ b/fs/fat/fat_write.c
@@ -104,13 +104,19 @@
/*
* Write fat buffer into block device
*/
-static int flush_fat_buffer(fsdata *mydata)
+static int flush_dirty_fat_buffer(fsdata *mydata)
{
int getsize = FATBUFBLOCKS;
__u32 fatlength = mydata->fatlength;
__u8 *bufptr = mydata->fatbuf;
__u32 startblock = mydata->fatbufnum * FATBUFBLOCKS;
+ debug("debug: evicting %d, dirty: %d\n", mydata->fatbufnum,
+ (int)mydata->fat_dirty);
+
+ if ((!mydata->fat_dirty) || (mydata->fatbufnum == -1))
+ return 0;
+
startblock += mydata->fat_sect;
if (getsize > fatlength)
@@ -130,6 +136,7 @@
return -1;
}
}
+ mydata->fat_dirty = 0;
return 0;
}
@@ -186,10 +193,8 @@
startblock += mydata->fat_sect; /* Offset from start of disk */
/* Write back the fatbuf to the disk */
- if (mydata->fatbufnum != -1) {
- if (flush_fat_buffer(mydata) < 0)
- return -1;
- }
+ if (flush_dirty_fat_buffer(mydata) < 0)
+ return -1;
if (disk_read(startblock, getsize, bufptr) < 0) {
debug("Error reading FAT blocks\n");
@@ -494,10 +499,8 @@
if (getsize > fatlength)
getsize = fatlength;
- if (mydata->fatbufnum != -1) {
- if (flush_fat_buffer(mydata) < 0)
- return -1;
- }
+ if (flush_dirty_fat_buffer(mydata) < 0)
+ return -1;
if (disk_read(startblock, getsize, bufptr) < 0) {
debug("Error reading FAT blocks\n");
@@ -506,6 +509,9 @@
mydata->fatbufnum = bufnum;
}
+ /* Mark as dirty */
+ mydata->fat_dirty = 1;
+
/* Set the actual entry */
switch (mydata->fatsize) {
case 32:
@@ -645,7 +651,7 @@
dir_curclust = dir_newclust;
- if (flush_fat_buffer(mydata) < 0)
+ if (flush_dirty_fat_buffer(mydata) < 0)
return;
memset(get_dentfromdir_block, 0x00,
@@ -675,7 +681,7 @@
}
/* Flush fat buffer */
- if (flush_fat_buffer(mydata) < 0)
+ if (flush_dirty_fat_buffer(mydata) < 0)
return -1;
return 0;
@@ -1011,6 +1017,7 @@
}
mydata->fatbufnum = -1;
+ mydata->fat_dirty = 0;
mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE);
if (mydata->fatbuf == NULL) {
debug("Error: allocating memory\n");
@@ -1111,7 +1118,7 @@
debug("attempt to write 0x%llx bytes\n", *actwrite);
/* Flush fat buffer */
- ret = flush_fat_buffer(mydata);
+ ret = flush_dirty_fat_buffer(mydata);
if (ret) {
printf("Error: flush fat buffer\n");
goto exit;