diff options
| author | Andrew Morton <akpm@zip.com.au> | 2002-05-05 01:10:16 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-05-05 01:10:16 -0700 |
| commit | 46c709c0c03b148ec55db561230ce39fbdae00f6 (patch) | |
| tree | 79498f60104d54072ec3a7ea94a31c688e3eb5e5 /fs/buffer.c | |
| parent | d028eab535bd8c1597391fd850f93501ff06f044 (diff) | |
[PATCH] handle concurrent block_write_full_page and set_page_dirty
set_page_dirty() runs without the page lock. So
__block_write_full_page() needs to be able to cope with the page's
buffers being dirtied concurrently, on another CPU.
Do this with careful ordering and a test-and-set.
Diffstat (limited to 'fs/buffer.c')
| -rw-r--r-- | fs/buffer.c | 25 |
1 files changed, 14 insertions, 11 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index 8db1bd8f0b84..aa1864f94bb9 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1288,6 +1288,16 @@ static int __block_write_full_page(struct inode *inode, (1 << BH_Dirty)|(1 << BH_Uptodate)); } + /* + * Be very careful. We have no exclusion from __set_page_dirty_buffers + * here, and the (potentially unmapped) buffers may become dirty at + * any time. If a buffer becomes dirty here after we've inspected it + * then we just miss that fact, and the page stays dirty. + * + * Buffers outside i_size may be dirtied by __set_page_dirty_buffers; + * handle that here by just cleaning them. + */ + block = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits); head = page_buffers(page); bh = head; @@ -1298,15 +1308,11 @@ static int __block_write_full_page(struct inode *inode, */ do { if (block > last_block) { - if (buffer_dirty(bh)) - buffer_error(); + clear_buffer_dirty(bh); if (buffer_mapped(bh)) buffer_error(); /* - * NOTE: this buffer can only be marked uptodate - * because we know that block_write_full_page has - * zeroed it out. That seems unnecessary and may go - * away. + * The buffer was zeroed by block_write_full_page() */ set_buffer_uptodate(bh); } else if (!buffer_mapped(bh) && buffer_dirty(bh)) { @@ -1327,11 +1333,9 @@ static int __block_write_full_page(struct inode *inode, do { get_bh(bh); - if (buffer_dirty(bh)) { + if (buffer_mapped(bh) && buffer_dirty(bh)) { lock_buffer(bh); - if (buffer_dirty(bh)) { - if (!buffer_mapped(bh)) - buffer_error(); + if (test_clear_buffer_dirty(bh)) { if (!buffer_uptodate(bh)) buffer_error(); set_buffer_async_io(bh); @@ -1353,7 +1357,6 @@ static int __block_write_full_page(struct inode *inode, do { struct buffer_head *next = bh->b_this_page; if (buffer_async(bh)) { - clear_buffer_dirty(bh); submit_bh(WRITE, bh); nr_underway++; } |
