struct buffer_head *nilfs_grab_buffer(struct inode *inode, struct address_space *mapping, unsigned long blkoff, unsigned long b_state) { int blkbits = inode->i_blkbits; pgoff_t index = blkoff >> (PAGE_CACHE_SHIFT - blkbits); struct page *page, *opage; struct buffer_head *bh, *obh; page = grab_cache_page(mapping, index); if (unlikely(!page)) return NULL; bh = __nilfs_get_page_block(page, blkoff, index, blkbits, b_state); if (unlikely(!bh)) { unlock_page(page); page_cache_release(page); return NULL; } if (!buffer_uptodate(bh) && mapping->assoc_mapping != NULL) { /* * Shadow page cache uses assoc_mapping to point its original * page cache. The following code tries the original cache * if the given cache is a shadow and it didn't hit. */ opage = find_lock_page(mapping->assoc_mapping, index); if (!opage) return bh; obh = __nilfs_get_page_block(opage, blkoff, index, blkbits, b_state); if (buffer_uptodate(obh)) { nilfs_copy_buffer(bh, obh); if (buffer_dirty(obh)) { nilfs_mark_buffer_dirty(bh); if (!buffer_nilfs_node(bh) && NILFS_MDT(inode)) nilfs_mdt_mark_dirty(inode); } } brelse(obh); unlock_page(opage); page_cache_release(opage); } return bh; }
/** * nilfs_btnode_commit_change_key * commit the change_key operation prepared by prepare_change_key(). */ void nilfs_btnode_commit_change_key(struct address_space *btnc, struct nilfs_btnode_chkey_ctxt *ctxt) { struct buffer_head *obh = ctxt->bh, *nbh = ctxt->newbh; __u64 oldkey = ctxt->oldkey, newkey = ctxt->newkey; struct page *opage; if (oldkey == newkey) return; if (nbh == NULL) { /* blocksize == pagesize */ opage = obh->b_page; if (unlikely(oldkey != opage->index)) NILFS_PAGE_BUG(opage, "invalid oldkey %lld (newkey=%lld)", (unsigned long long)oldkey, (unsigned long long)newkey); if (!test_set_buffer_dirty(obh) && TestSetPageDirty(opage)) BUG(); WRITE_LOCK_IRQ(&btnc->tree_lock); radix_tree_delete(&btnc->page_tree, oldkey); radix_tree_tag_set(&btnc->page_tree, newkey, PAGECACHE_TAG_DIRTY); WRITE_UNLOCK_IRQ(&btnc->tree_lock); opage->index = obh->b_blocknr = newkey; unlock_page(opage); } else { nilfs_copy_buffer(nbh, obh); nilfs_btnode_mark_dirty(nbh); nbh->b_blocknr = newkey; ctxt->bh = nbh; nilfs_btnode_delete(obh); /* will decrement bh->b_count */ } }
void nilfs_btnode_commit_change_key(struct address_space *btnc, struct nilfs_btnode_chkey_ctxt *ctxt) { struct buffer_head *obh = ctxt->bh, *nbh = ctxt->newbh; __u64 oldkey = ctxt->oldkey, newkey = ctxt->newkey; struct page *opage; if (oldkey == newkey) return; if (nbh == NULL) { opage = obh->b_page; if (unlikely(oldkey != opage->index)) NILFS_PAGE_BUG(opage, "invalid oldkey %lld (newkey=%lld)", (unsigned long long)oldkey, (unsigned long long)newkey); mark_buffer_dirty(obh); spin_lock_irq(&btnc->tree_lock); radix_tree_delete(&btnc->page_tree, oldkey); radix_tree_tag_set(&btnc->page_tree, newkey, PAGECACHE_TAG_DIRTY); spin_unlock_irq(&btnc->tree_lock); opage->index = obh->b_blocknr = newkey; unlock_page(opage); } else { nilfs_copy_buffer(nbh, obh); mark_buffer_dirty(nbh); nbh->b_blocknr = newkey; ctxt->bh = nbh; nilfs_btnode_delete(obh); } }