diff options
Diffstat (limited to 'fs/nilfs2/btnode.c')
| -rw-r--r-- | fs/nilfs2/btnode.c | 25 | 
1 files changed, 20 insertions, 5 deletions
| diff --git a/fs/nilfs2/btnode.c b/fs/nilfs2/btnode.c index 0131d83b912d..c034080c334b 100644 --- a/fs/nilfs2/btnode.c +++ b/fs/nilfs2/btnode.c @@ -51,12 +51,21 @@ nilfs_btnode_create_block(struct address_space *btnc, __u64 blocknr)  	bh = nilfs_grab_buffer(inode, btnc, blocknr, BIT(BH_NILFS_Node));  	if (unlikely(!bh)) -		return NULL; +		return ERR_PTR(-ENOMEM);  	if (unlikely(buffer_mapped(bh) || buffer_uptodate(bh) ||  		     buffer_dirty(bh))) { -		brelse(bh); -		BUG(); +		/* +		 * The block buffer at the specified new address was already +		 * in use.  This can happen if it is a virtual block number +		 * and has been reallocated due to corruption of the bitmap +		 * used to manage its allocation state (if not, the buffer +		 * clearing of an abandoned b-tree node is missing somewhere). +		 */ +		nilfs_error(inode->i_sb, +			    "state inconsistency probably due to duplicate use of b-tree node block address %llu (ino=%lu)", +			    (unsigned long long)blocknr, inode->i_ino); +		goto failed;  	}  	memset(bh->b_data, 0, i_blocksize(inode));  	bh->b_bdev = inode->i_sb->s_bdev; @@ -67,6 +76,12 @@ nilfs_btnode_create_block(struct address_space *btnc, __u64 blocknr)  	folio_unlock(bh->b_folio);  	folio_put(bh->b_folio);  	return bh; + +failed: +	folio_unlock(bh->b_folio); +	folio_put(bh->b_folio); +	brelse(bh); +	return ERR_PTR(-EIO);  }  int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr, @@ -217,8 +232,8 @@ retry:  	}  	nbh = nilfs_btnode_create_block(btnc, newkey); -	if (!nbh) -		return -ENOMEM; +	if (IS_ERR(nbh)) +		return PTR_ERR(nbh);  	BUG_ON(nbh == obh);  	ctxt->newbh = nbh; |