mtd/fs/jffs2 build.c,1.61,1.62 wbuf.c,1.77,1.78
Artem Bityuckiy
dedekind at infradead.org
Fri Nov 19 08:41:19 EST 2004
Update of /home/cvs/mtd/fs/jffs2
In directory phoenix.infradead.org:/tmp/cvs-serv4648/fs/jffs2
Modified Files:
build.c wbuf.c
Log Message:
Bugfix: fix the race bug when a writed and reader concurrently access
the wbuf. Introduce new rw semaphore to fix this.
Index: build.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/build.c,v
retrieving revision 1.61
retrieving revision 1.62
diff -u -r1.61 -r1.62
--- build.c 18 Nov 2004 11:17:41 -0000 1.61
+++ build.c 19 Nov 2004 13:41:16 -0000 1.62
@@ -326,6 +326,7 @@
init_MUTEX(&c->alloc_sem);
init_MUTEX(&c->erase_free_sem);
+ init_rwsem(&c->wbuf_sem);
init_waitqueue_head(&c->erase_wait);
init_waitqueue_head(&c->inocache_wq);
spin_lock_init(&c->erase_completion_lock);
Index: wbuf.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/wbuf.c,v
retrieving revision 1.77
retrieving revision 1.78
diff -u -r1.77 -r1.78
--- wbuf.c 16 Nov 2004 20:36:12 -0000 1.77
+++ wbuf.c 19 Nov 2004 13:41:16 -0000 1.78
@@ -399,7 +399,7 @@
1: Pad, do not adjust nextblock free_size
2: Pad, adjust nextblock free_size
*/
-static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
+static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad, int alloc_wbuf_sem)
{
int ret;
size_t retlen;
@@ -415,8 +415,11 @@
BUG();
}
+ if (alloc_wbuf_sem)
+ down_write(&c->wbuf_sem);
+
if(!c->wbuf || !c->wbuf_len)
- return 0;
+ goto exit;
/* claim remaining space on the page
this happens, if we have a change to a new block,
@@ -469,7 +472,7 @@
jffs2_wbuf_recover(c);
- return ret;
+ goto exit;
}
spin_lock(&c->erase_completion_lock);
@@ -508,6 +511,9 @@
/* adjust write buffer offset, else we get a non contiguous write bug */
c->wbuf_ofs += c->wbuf_pagesize;
c->wbuf_len = 0;
+exit:
+ if (alloc_wbuf_sem)
+ up_write(&c->wbuf_sem);
return 0;
}
@@ -536,7 +542,7 @@
if (c->unchecked_size) {
/* GC won't make any progress for a while */
D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n"));
- ret = __jffs2_flush_wbuf(c, 2);
+ ret = __jffs2_flush_wbuf(c, 2, 1);
} else while (old_wbuf_len &&
old_wbuf_ofs == c->wbuf_ofs) {
@@ -548,7 +554,7 @@
if (ret) {
/* GC failed. Flush it with padding instead */
down(&c->alloc_sem);
- ret = __jffs2_flush_wbuf(c, 2);
+ ret = __jffs2_flush_wbuf(c, 2, 1);
break;
}
down(&c->alloc_sem);
@@ -563,10 +569,9 @@
/* Pad write-buffer to end and write it, wasting space. */
int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c)
{
- return __jffs2_flush_wbuf(c, 1);
+ return __jffs2_flush_wbuf(c, 1, 1);
}
-
#define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) )
#define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) )
int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino)
@@ -586,6 +591,8 @@
if (!c->wbuf)
return jffs2_flash_direct_writev(c, invecs, count, to, retlen);
+ down_write(&c->wbuf_sem);
+
/* If wbuf_ofs is not initialized, set it to target address */
if (c->wbuf_ofs == 0xFFFFFFFF) {
c->wbuf_ofs = PAGE_DIV(to);
@@ -614,12 +621,12 @@
/* It's a write to a new block */
if (c->wbuf_len) {
D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs));
- ret = jffs2_flush_wbuf_pad(c);
+ ret = __jffs2_flush_wbuf(c, 1, 1);
if (ret) {
/* the underlying layer has to check wbuf_len to do the cleanup */
D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret));
*retlen = 0;
- return ret;
+ goto exit;
}
}
/* set pointer to new block */
@@ -645,7 +652,6 @@
invec = 0;
outvec = 0;
-
/* Fill writebuffer first, if already in use */
if (c->wbuf_len) {
uint32_t invec_ofs = 0;
@@ -680,14 +686,14 @@
}
/* write buffer is full, flush buffer */
- ret = __jffs2_flush_wbuf(c, 0);
+ ret = __jffs2_flush_wbuf(c, 0, 0);
if (ret) {
/* the underlying layer has to check wbuf_len to do the cleanup */
D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret));
/* Retlen zero to make sure our caller doesn't mark the space dirty.
We've already done everything that's necessary */
*retlen = 0;
- return ret;
+ goto exit;
}
outvec_to += donelen;
c->wbuf_ofs = outvec_to;
@@ -731,7 +737,6 @@
if (splitvec != -1) {
uint32_t remainder;
- int ret;
remainder = outvecs[splitvec].iov_len - split_ofs;
outvecs[splitvec].iov_len = split_ofs;
@@ -747,7 +752,7 @@
c->wbuf is empty.
*/
*retlen = donelen;
- return ret;
+ goto exit;
}
donelen += wbuf_retlen;
@@ -786,7 +791,11 @@
if (c->wbuf_len && ino)
jffs2_wbuf_dirties_inode(c, ino);
- return 0;
+ ret = 0;
+
+exit:
+ up_write(&c->wbuf_sem);
+ return ret;
}
/*
@@ -815,6 +824,8 @@
/* Read flash */
if (!jffs2_can_mark_obsolete(c)) {
+ down_read(&c->wbuf_sem);
+
if (jffs2_cleanmarker_oob(c))
ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
else
@@ -840,23 +851,23 @@
/* if no writebuffer available or write buffer empty, return */
if (!c->wbuf_pagesize || !c->wbuf_len)
- return ret;
+ goto exit;
/* if we read in a different block, return */
if ( (ofs & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) )
- return ret;
+ goto exit;
if (ofs >= c->wbuf_ofs) {
owbf = (ofs - c->wbuf_ofs); /* offset in write buffer */
if (owbf > c->wbuf_len) /* is read beyond write buffer ? */
- return ret;
+ goto exit;
lwbf = c->wbuf_len - owbf; /* number of bytes to copy */
if (lwbf > len)
lwbf = len;
} else {
orbf = (c->wbuf_ofs - ofs); /* offset in read buffer */
if (orbf > len) /* is write beyond write buffer ? */
- return ret;
+ goto exit;
lwbf = len - orbf; /* number of bytes to copy */
if (lwbf > c->wbuf_len)
lwbf = c->wbuf_len;
@@ -864,6 +875,8 @@
if (lwbf > 0)
memcpy(buf+orbf,c->wbuf+owbf,lwbf);
+exit:
+ up_read(&c->wbuf_sem);
return ret;
}
More information about the linux-mtd-cvs
mailing list