void nilfs_vinode_debug(const char *fname, int line, struct inode *inode,
			const char *m, ...)
{
	struct nilfs_inode_info *ii;
	int n = 0, len;
	char b[MSIZ];
	va_list args;

	len = snprintf(b, MSIZ, "VINODE %p ", inode);
	va_start(args, m);
	len += vsnprintf(b + len, MSIZ - len, m, args);
	va_end(args);

	if (inode == NULL) {
		printk(KERN_DEBUG "%s: inode=NULL %s at %d\n", m, fname, line);
		return;
	}
	ii = NILFS_I(inode);
	len += snprintf(b + len, MSIZ - len, ": current %p ino=%lu nlink=%u "
			"count=%u mode=0%o mapping=%p i_bh=%p",
			current, inode->i_ino, inode->i_nlink,
			atomic_read(&inode->i_count), inode->i_mode,
			inode->i_mapping, ii->i_bh);

	len += snprintf(b + len, MSIZ - len, " %s(%d) i_state=", fname, line);
	TEST_INODE_STATE(inode, DIRTY_SYNC, b, MSIZ, n, len);
	TEST_INODE_STATE(inode, DIRTY_DATASYNC, b, MSIZ, n, len);
	TEST_INODE_STATE(inode, DIRTY_PAGES, b, MSIZ, n, len);
	TEST_INODE_STATE(inode, LOCK, b, MSIZ, n, len);
	TEST_INODE_STATE(inode, FREEING, b, MSIZ, n, len);
	TEST_INODE_STATE(inode, CLEAR, b, MSIZ, n, len);
	TEST_INODE_STATE(inode, NEW, b, MSIZ, n, len);
#ifdef I_WILL_FREE
	TEST_INODE_STATE(inode, WILL_FREE, b, MSIZ, n, len);
#endif

	if (ii->i_state) {
		n = 0;
		len += snprintf(b + len, MSIZ - len, " vi_state=");
		TEST_NILFS_INODE_STATE(ii, NEW, b, MSIZ, n, len);
		TEST_NILFS_INODE_STATE(ii, DIRTY, b, MSIZ, n, len);
		TEST_NILFS_INODE_STATE(ii, QUEUED, b, MSIZ, n, len);
		TEST_NILFS_INODE_STATE(ii, BUSY, b, MSIZ, n, len);
		TEST_NILFS_INODE_STATE(ii, COLLECTED, b, MSIZ, n, len);
		TEST_NILFS_INODE_STATE(ii, UPDATED, b, MSIZ, n, len);
		TEST_NILFS_INODE_STATE(ii, INODE_DIRTY, b, MSIZ, n, len);
		TEST_NILFS_INODE_STATE(ii, BMAP, b, MSIZ, n, len);
		TEST_NILFS_INODE_STATE(ii, GCINODE, b, MSIZ, n, len);
		TEST_NILFS_INODE_STATE(ii, GCDAT, b, MSIZ, n, len);
	}

	printk(KERN_DEBUG "%s\n", b);
	if (ii->i_bh)
		BH_DEBUG(ii->i_bh, "ibh");
}
/**
 * nilfs_btnode_delete - delete B-tree node buffer
 * @bh: buffer to be deleted
 *
 * nilfs_btnode_delete() invalidates the specified buffer and delete the page
 * including the buffer if the page gets unbusy.
 */
void nilfs_btnode_delete(struct buffer_head *bh)
{
	struct address_space *mapping;
	struct page *page = bh->b_page;
	pgoff_t index = page_index(page);
	int still_dirty;

	page_cache_get(page);
	lock_page(page);
	wait_on_page_writeback(page);

	if (unlikely(!buffer_mapped(bh)))
		BH_DEBUG(bh, "deleting unused btnode buffer");

	nilfs_forget_buffer(bh);
	still_dirty = PageDirty(page);
	mapping = page->mapping;
	unlock_page(page);
	page_cache_release(page);

	if (!still_dirty && mapping)
		invalidate_inode_pages2_range(mapping, index, index);
}
int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
			      sector_t pblocknr, struct buffer_head **pbh,
			      int newblk)
{
	struct buffer_head *bh;
	struct inode *inode = NILFS_BTNC_I(btnc);
	int err;

	btnode_debug(3, "called: blocknr=%llu pblocknr=%llu new=%d ino=%lu\n",
		     (unsigned long long)blocknr, (unsigned long long)pblocknr,
		     newblk, inode->i_ino);
	bh = nilfs_grab_buffer(inode, btnc, blocknr, 1 << BH_NILFS_Node);
	if (unlikely(!bh))
		return -ENOMEM;

	err = -EEXIST; /* internal code */
	if (newblk) {
		if (unlikely(buffer_mapped(bh) || buffer_uptodate(bh) ||
			     buffer_dirty(bh))) {
			BH_DEBUG(bh, "invalid new bh");
			BUG();
		}
		bh->b_bdev = NILFS_I_NILFS(inode)->ns_bdev;
		bh->b_blocknr = blocknr;
		set_buffer_mapped(bh);
		set_buffer_uptodate(bh);
		goto found;
	}

	if (buffer_uptodate(bh) || buffer_dirty(bh))
		goto found;

	if (pblocknr == 0) {
		pblocknr = blocknr;
		if (inode->i_ino != NILFS_DAT_INO) {
			struct inode *dat =
				nilfs_dat_inode(NILFS_I_NILFS(inode));

			/* blocknr is a virtual block number */
			err = nilfs_dat_translate(dat, blocknr, &pblocknr);
			if (unlikely(err)) {
				brelse(bh);
				btnode_debug(1, "return %d (xlate).\n", err);
				goto out_locked;
			}
		}
	}
	lock_buffer(bh);
	if (buffer_uptodate(bh)) {
		unlock_buffer(bh);
		err = -EEXIST; /* internal code */
		goto found;
	}
	set_buffer_mapped(bh);
	bh->b_bdev = NILFS_I_NILFS(inode)->ns_bdev;
	bh->b_blocknr = pblocknr; /* set block address for read */
	bh->b_end_io = end_buffer_read_sync;
	get_bh(bh);
	submit_bh(READ, bh);
	bh->b_blocknr = blocknr; /* set back to the given block address */
	err = 0;
found:
	*pbh = bh;

out_locked:
	unlock_page(bh->b_page);
	page_cache_release(bh->b_page);
	btnode_debug(3, "done (err=%d)\n", err);
	return err;
}