Merge branch 'urgent' of git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia-2.6
[pandora-kernel.git] / fs / nilfs2 / btnode.c
index 447ce47..f78ab10 100644 (file)
@@ -96,10 +96,12 @@ nilfs_btnode_create_block(struct address_space *btnc, __u64 blocknr)
 }
 
 int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
-                             sector_t pblocknr, struct buffer_head **pbh)
+                             sector_t pblocknr, int mode,
+                             struct buffer_head **pbh, sector_t *submit_ptr)
 {
        struct buffer_head *bh;
        struct inode *inode = NILFS_BTNC_I(btnc);
+       struct page *page;
        int err;
 
        bh = nilfs_grab_buffer(inode, btnc, blocknr, 1 << BH_NILFS_Node);
@@ -107,6 +109,7 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
                return -ENOMEM;
 
        err = -EEXIST; /* internal code */
+       page = bh->b_page;
 
        if (buffer_uptodate(bh) || buffer_dirty(bh))
                goto found;
@@ -125,7 +128,16 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
                        }
                }
        }
-       lock_buffer(bh);
+
+       if (mode == READA) {
+               if (pblocknr != *submit_ptr + 1 || !trylock_buffer(bh)) {
+                       err = -EBUSY; /* internal code */
+                       brelse(bh);
+                       goto out_locked;
+               }
+       } else { /* mode == READ */
+               lock_buffer(bh);
+       }
        if (buffer_uptodate(bh)) {
                unlock_buffer(bh);
                err = -EEXIST; /* internal code */
@@ -136,15 +148,16 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
        bh->b_blocknr = pblocknr; /* set block address for read */
        bh->b_end_io = end_buffer_read_sync;
        get_bh(bh);
-       submit_bh(READ, bh);
+       submit_bh(mode, bh);
        bh->b_blocknr = blocknr; /* set back to the given block address */
+       *submit_ptr = pblocknr;
        err = 0;
 found:
        *pbh = bh;
 
 out_locked:
-       unlock_page(bh->b_page);
-       page_cache_release(bh->b_page);
+       unlock_page(page);
+       page_cache_release(page);
        return err;
 }