meta name='generator' content='cgit v1.2.2'/>
aboutsummaryrefslogblamecommitdiffstats
path: root/fs/btrfs/disk-io.c
blob: a0d41e713f3caff2fbfe4ddfad4acd907bb1d7ad (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

















                                                                    
                     
                         
                              
                       
                             
                            
                              
                            
                          
                          
                         
                   

                    
                        
                        
                    
                       
                         
                    
                     
                             
 
                                                
                                                      
                                                  
 

                                               




                                                                            





                                   
                     
                              
                               
  
 




                                                                 



                              

                                                   

                       
                                
                               

  

































                                                                          



                                                                   


                                                                          
 



                                                                       
                                  
                                                        


                                                                               
                                            
                         
         
                                    
 





                                        
                          
                                
                            
                                                                          
 
                                   

                                              


                                             
                                    
                                                                
                         
                                


                                                                         
                                   
                 
                         

                                    
         
                                     


                                  

                  

 

                                                                              
                                       






                                              



                                                                       


                                                                              


                                                                  








                                               
                                    

                                
                         


                                                                        
                        
                                 






                                                                       







                                                                     


                                      
                                                                      

                                      
                                                          
 
                                                                    







                                                                                  

                                                             


                                 
                                                               
         

                                             


                 





                                                                          













                                                                              






                                                                          
                
                                                  
    


                                                                  

 



                                                                    

                                                                   
                                                                        









                                                                             

                                                                        
                                   
 

                                                                           
                                    
                                   
 
                             
                                            
                                   
         

                    
 
  

                                                                             
   
 
                                                                        
 
                                    
                                                         



                                 

                
                                                      





                                                 

                          
                                                                   

                                                                               
                    

                                              



                                     



                                  

                           

                                             
 
                                     
    




                               


















                                                                          








                                                                        
                                                                            







                                                                     
                    





                                                      
 
                                 

                          
                                                                   
 
                                              
                                   





                                                                      
                           


                                     

                                                                  
                           
                           

                         
                                              



                                                                          


                           

                                             

                                                        
                                           

                           


                                                   


                               
                   

 
                                                       


                                                      
 
                                  
                               

                                                

                                         





                                                                              







                                                                        

 

                                                                    
 
                                    





                                                          
                               

                             
                                       


                                           


                 
                                                                  
 




                                                                    
 

                                                                 

                                                  

 











                                                                    


                                       
                  


                                                                   
 
                                                  

                              
                                               
 

                                                              

                                                     
                                                                   
                                                                    






                                                                   


                     

                                                                           
                                                

                                                                   










                                                  






                                                      
                              
                                     
 
                                               



                                                       
                                                            
 
                                                              




                                                                           


                 






                                              
                                          







                                                                   


                                                                    
 

                                                                    
                                                            
           


                                
 


                                                                                
          

                                                                    
           
                                                                           

 
                                                                              
                                                                         
 





                                                                
                                    



                                                                              
                                                                   
                                                    
         
 



                                                                         
                                                                 
                                                                 

                                                            

 

                                                                            
                                    



                                                                     
                                                      



                                                                     
 









                                                                       
         



                               
 



                                                          

                                                
                                             
                                                                       
                              
                                                        



                                     

                                                                
                                       
                                 
         


                                                                       
                                                               
 

                                                      

                                                                   
 
                                                                
 

                                    
                
 
                                                   
                         
 

                                                         
 
                                                                   
                 
                         

                                                    




                                          
 


                   
                                                                         
 

                                                      

                                                  
                                

                                                                                



                                          

 


                                                     
                                           

                                               


                                          

                                                                            
 

                                                               
                    
 
                                                                    
                 
                         
                                                                
                                                                 
                                
                   

 





















                                                                           


                                                                           
                                                                              




                                                                           
                                                                         

 
                                                                          
                                                                        










                                                                    
 
                                                                           
 
                     
                                                              
                   
 

 
                                                                               
                                               
 
                                                               
                                           
                                                          
                                              
 







                                                                                
 

                                                                           
                                                                         
                                               
         


                 
                                                                   
                                                                
                                                      
                                     
 
                          
                                 


                                      
                                      
                           

                              
                                

                                  
                                   
                          
                           
                                        

                                          
                                           
                                         
                                         
                                         
                                          
                                          
                                     







                                                       

                                                                        
 

                                                             
                                                                         
                                                             
                                                       
                                                

                                 
                                           





                                                      


                 
                                                            

                                                             
                                                       

                
                      
                       
 
                                                              

                                                                  

                                                                      

                               

                    
                                                             

                                                                               
                                                            
                            
                                                  


                 



                                                              


                                                                  

                
                           

                         
                   







                                                                            




                                               

                                                            







                                      

                                                                          


                                                          
                                   


                                                
                                        







                                                                  





                                                                         

                           

                                                                              



                                      
 




                                                                      
                          





                                                                         



































                                                              
                                                                  



                                  







                                                                            
                                
                                
                       
                      

                    
                                                
                  
                                        
                                          
                                                             

                                                                    


                                            
                         

         
                                                              

                                                                  



                                                                       





                                                                         
         

                              

                                      

                                    
 
                                                             

                                                                               
                                                            
                                                  
                            

                                                          
                                   
 


                    














                                                                      

                                                                            



                                



                                                             



                                                            

                                                           

                                                 

                                                                    
                                                   


                            





                                                                             
                                                                         

                            
 
                                                        

                                                




                                                            

                                                                       
                                      



                                                   
                  




                                           
         





                                                             
                                           
 
                    


                            





                                                                    

                                                             





                                                             
 


                            

                                                       
                                               


                                    
 

                                         
                                               



                                    
                           
                    
      
 




                                                                            

                                     
 
                                                                           

                                  








                                                             





                                                                           



                                                           
                                                                           


                                  
                                                             
                                      
                                                     


         
                                                                               
 
                            

                                        
                                      

                   
                                                      
                         



                                          









                                                                       









                                                                           
                                   
 
                                               
                                  
                                                                     
                                    

                                          
                       
         
 




                                                      



                                                                       

 



                                                                  

                                                                              








                                                                   

                                 
                           
         
 
                                                            






                                                     

































                                                                   


                   




                                                                        
 
                        

                                      
                  
 


                                                               
 
                                                                           



                                                                          

                                                                   
                                                                






                                                     
                              

 









                                                                     





                                                                    






































                                                                      
 






                                                                          

                                                            
 
















                                                                        
                                                     

                                                                  
 



                       
                       
                       
                     
                                  
                               
                                                                           
                                                           

                                                                         
                                                                         
                                                         
                                                                 
                                                          
                                                                          
                                                          
                                                                        
                                                        

                                         
                
                          
 
                                             
 
                                                     
                                                     


                              



















                                                              
                                             
                                             
                                          
                                                  
                                                     
                                                       
                                                
                                                 
                                                 
                                                      
 
                                                   

                                           
                                       

                                         
                                         
                                                      
                                             
                                                   
                                                  
                                                      
                                                       
                                               
                         
                                      
                                          
                                    
 

                                                                    
 


                                                      


                                                  

                                                                 





                                                                        
                                                             

                                                                          
                                                               
                                                                    

                                                             



                                                                          
 




                                                           


                                                         
                                                       
                                                                        


                                                                        
                                 
 
 
                                          
                                                       
                                             
                                          

                                                        
                                           
                                                
                                         



                                                              
                                                            
                                                        
                                                         
 
                                                       
                                                        
 
 
                                                           
                
                               
 
                                                                              

                                                                
                   
 
                                                                         
 
                                          
                                          
                               
 


                                                      
                               
         
 




                                                                   
                                                     
                              
                               

         





                                                                     




                                                                        
                                                     
                              
                               
         
                                                         




                                                                       

                                                       
 


                                                                  
                                                              

                                                              





                                                                        
 
                                          
                                     
 


                                                  


                                                                

                                                                      

                                                                          
                                                                        
                                                      





                                                             

                                                    






                                                                  
 
                                                  
                                                         
                                                           
                                                        



                                                                   
 
                                                                     

                                                                       
 


                                                        
                                                        


                                           
                                           


                                                        
 

                                                              
                                                                                

                                    
 
                                          
                                              
                                            
                  

                                                                       
                                    
         


                                                                               
                                                                   





                                                                              
                                                                  
                                  




                                                                               

                                                                      
 
                                                                      

                                                                         
 
                                          
                                                
                                            
                  

                                                                               

                                     
 

                                              

                                                                         
                                                        
 
                                                    
                                                                       
                                                                 
                             
                                     




                                                                              

                                                                    

                                                     
                                                                           
                
                                    



                                                                     

                                      
                                  
 


                                                                       
                                   


                                   

                                             
                                         
                                                   


                                                                        

                                                                          
                                             
                                    



                                                                        
                                                 
                                  
 







                                                                            
                                                    

                                                              
                                                  

                                                                        


                                                


                                                                              
 






                                                                              

                                                                      

                                                             




                                                             
         
 


                                                 
                                         
                                                          

                            
 



                                                   

                                                                          
                                        
 
                         
 

                                                   
             
                                               







                                                                       

                                            



                                                   

                                              
                                                     
               
                                            
                                                   

                                             
                                                    
               
                                                    
                                                       

                                                    
                                                         
                                                               
                                                          
                                                     
          
                                                                 
                                   
 
                                                 
                                                        
         
                                   

                                                   
     


                           

                          
                         
                            

 











                                                                             


                                                                           





                                          








































                                                                         










                                                                     


































                                                                          
                                           








                                                                       









                                                                     



                                                                        



                                                                      
                                                         
                                   

                                                










                                                                               
                                                                 

                                                
                                                                

                         
                                                        

                 
                        
                                 




                                                              
 
                               
                                 
                                     
                                        

                        

                             
                  
 
                                                                             

                                                       

                                              


                                                                  
                                                  



                                       
                                                            

                                 
                                                               







                                                                               
                                                                               
 


                                                                             
                                                                             

                                       
         
                                        

                                                                          

                      
 
                         
                                                  

                                 
                                                            

                                 


                                                                             
         
                                                                    
                                        

                                                                          

                      


                 

                                                               
 
                
 
                                                  
                   

 
                                                                              
 
                                                 

                                                                  
                                                   



                                                        






                                                   



                                                       

                                              
                          
                    

 
                                                      




                                   













                                                                   
                   




                                                                      
                                         
                                                             


                 
 
                                                         
 


                                   
                
 





                                                                          

                                                                     

                                                                   





                                                      
 



                                               
 
                                                  
                                        
                                                    
                                                 
                                                    

                                                            


                                                           
                    
 
                                               















                                                         

                                                                             
         
 


                             
                                      
                                                                           
                                                                    
         
                                            

                                                                                
         
 









                                                                   
 
                                               
 
                              
 
                                   
 
                                                    
                                                       

                                                    
                                                         
                                                               
                                                          
                                                     
 
                                                 
                                                        
 
                                   
                                                   
 
                                    
                                  

                                   
                                  


                 
                                                                        
 
                
                                                                   







                                                                          


                                                        
 
                                                                   
                                                                         

                                               
 

                                                       
                                                                                

                                                               
                      
 
                                      
                                                   

                                                                       
                                                       

                                                                       

                           






                                                                           

 
                                                                         
 



                                                                      
                      
                                                
 
                                         

                       

                                                        

                                                   
                                                                             
         
               
 
 
                                                                    
 
                                                                                
                
                                                                           
                     
                                                              
                   
 
 


                                                  
                                                       













                                                                  
                                                             









                                                                       






                               
                                                   
                                                            
                                                           
                                                 

                                                                    
  
/*
 * Copyright (C) 2007 Oracle.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License v2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 021110-1307, USA.
 */

#include <linux/fs.h>
#include <linux/blkdev.h>
#include <linux/scatterlist.h>
#include <linux/swap.h>
#include <linux/radix-tree.h>
#include <linux/writeback.h>
#include <linux/buffer_head.h>
#include <linux/workqueue.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/crc32c.h>
#include "compat.h"
#include "ctree.h"
#include "disk-io.h"
#include "transaction.h"
#include "btrfs_inode.h"
#include "volumes.h"
#include "print-tree.h"
#include "async-thread.h"
#include "locking.h"
#include "tree-log.h"
#include "free-space-cache.h"

static struct extent_io_ops btree_extent_io_ops;
static void end_workqueue_fn(struct btrfs_work *work);
static void free_fs_root(struct btrfs_root *root);

static atomic_t btrfs_bdi_num = ATOMIC_INIT(0);

/*
 * end_io_wq structs are used to do processing in task context when an IO is
 * complete.  This is used during reads to verify checksums, and it is used
 * by writes to insert metadata for new file extents after IO is complete.
 */
struct end_io_wq {
	struct bio *bio;
	bio_end_io_t *end_io;
	void *private;
	struct btrfs_fs_info *info;
	int error;
	int metadata;
	struct list_head list;
	struct btrfs_work work;
};

/*
 * async submit bios are used to offload expensive checksumming
 * onto the worker threads.  They checksum file and metadata bios
 * just before they are sent down the IO stack.
 */
struct async_submit_bio {
	struct inode *inode;
	struct bio *bio;
	struct list_head list;
	extent_submit_bio_hook_t *submit_bio_start;
	extent_submit_bio_hook_t *submit_bio_done;
	int rw;
	int mirror_num;
	unsigned long bio_flags;
	struct btrfs_work work;
};

/* These are used to set the lockdep class on the extent buffer locks.
 * The class is set by the readpage_end_io_hook after the buffer has
 * passed csum validation but before the pages are unlocked.
 *
 * The lockdep class is also set by btrfs_init_new_buffer on freshly
 * allocated blocks.
 *
 * The class is based on the level in the tree block, which allows lockdep
 * to know that lower nodes nest inside the locks of higher nodes.
 *
 * We also add a check to make sure the highest level of the tree is
 * the same as our lockdep setup here.  If BTRFS_MAX_LEVEL changes, this
 * code needs update as well.
 */
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# if BTRFS_MAX_LEVEL != 8
#  error
# endif
static struct lock_class_key btrfs_eb_class[BTRFS_MAX_LEVEL + 1];
static const char *btrfs_eb_name[BTRFS_MAX_LEVEL + 1] = {
	/* leaf */
	"btrfs-extent-00",
	"btrfs-extent-01",
	"btrfs-extent-02",
	"btrfs-extent-03",
	"btrfs-extent-04",
	"btrfs-extent-05",
	"btrfs-extent-06",
	"btrfs-extent-07",
	/* highest possible level */
	"btrfs-extent-08",
};
#endif

/*
 * extents on the btree inode are pretty simple, there's one extent
 * that covers the entire device
 */
static struct extent_map *btree_get_extent(struct inode *inode,
		struct page *page, size_t page_offset, u64 start, u64 len,
		int create)
{
	struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
	struct extent_map *em;
	int ret;

	read_lock(&em_tree->lock);
	em = lookup_extent_mapping(em_tree, start, len);
	if (em) {
		em->bdev =
			BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
		read_unlock(&em_tree->lock);
		goto out;
	}
	read_unlock(&em_tree->lock);

	em = alloc_extent_map(GFP_NOFS);
	if (!em) {
		em = ERR_PTR(-ENOMEM);
		goto out;
	}
	em->start = 0;
	em->len = (u64)-1;
	em->block_len = (u64)-1;
	em->block_start = 0;
	em->bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;

	write_lock(&em_tree->lock);
	ret = add_extent_mapping(em_tree, em);
	if (ret == -EEXIST) {
		u64 failed_start = em->start;
		u64 failed_len = em->len;

		free_extent_map(em);
		em = lookup_extent_mapping(em_tree, start, len);
		if (em) {
			ret = 0;
		} else {
			em = lookup_extent_mapping(em_tree, failed_start,
						   failed_len);
			ret = -EIO;
		}
	} else if (ret) {
		free_extent_map(em);
		em = NULL;
	}
	write_unlock(&em_tree->lock);

	if (ret)
		em = ERR_PTR(ret);
out:
	return em;
}

u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len)
{
	return crc32c(seed, data, len);
}

void btrfs_csum_final(u32 crc, char *result)
{
	*(__le32 *)result = ~cpu_to_le32(crc);
}

/*
 * compute the csum for a btree block, and either verify it or write it
 * into the csum field of the block.
 */
static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
			   int verify)
{
	u16 csum_size =
		btrfs_super_csum_size(&root->fs_info->super_copy);
	char *result = NULL;
	unsigned long len;
	unsigned long cur_len;
	unsigned long offset = BTRFS_CSUM_SIZE;
	char *map_token = NULL;
	char *kaddr;
	unsigned long map_start;
	unsigned long map_len;
	int err;
	u32 crc = ~(u32)0;
	unsigned long inline_result;

	len = buf->len - offset;
	while (len > 0) {
		err = map_private_extent_buffer(buf, offset, 32,
					&map_token, &kaddr,
					&map_start, &map_len, KM_USER0);
		if (err)
			return 1;
		cur_len = min(len, map_len - (offset - map_start));
		crc = btrfs_csum_data(root, kaddr + offset - map_start,
				      crc, cur_len);
		len -= cur_len;
		offset += cur_len;
		unmap_extent_buffer(buf, map_token, KM_USER0);
	}
	if (csum_size > sizeof(inline_result)) {
		result = kzalloc(csum_size * sizeof(char), GFP_NOFS);
		if (!result)
			return 1;
	} else {
		result = (char *)&inline_result;
	}

	btrfs_csum_final(crc, result);

	if (verify) {
		if (memcmp_extent_buffer(buf, result, 0, csum_size)) {
			u32 val;
			u32 found = 0;
			memcpy(&found, result, csum_size);

			read_extent_buffer(buf, &val, 0, csum_size);
			if (printk_ratelimit()) {
				printk(KERN_INFO "btrfs: %s checksum verify "
				       "failed on %llu wanted %X found %X "
				       "level %d\n",
				       root->fs_info->sb->s_id,
				       (unsigned long long)buf->start, val, found,
				       btrfs_header_level(buf));
			}
			if (result != (char *)&inline_result)
				kfree(result);
			return 1;
		}
	} else {
		write_extent_buffer(buf, result, 0, csum_size);
	}
	if (result != (char *)&inline_result)
		kfree(result);
	return 0;
}

/*
 * we can't consider a given block up to date unless the transid of the
 * block matches the transid in the parent node's pointer.  This is how we
 * detect blocks that either didn't get written at all or got written
 * in the wrong place.
 */
static int verify_parent_transid(struct extent_io_tree *io_tree,
				 struct extent_buffer *eb, u64 parent_transid)
{
	int ret;

	if (!parent_transid || btrfs_header_generation(eb) == parent_transid)
		return 0;

	lock_extent(io_tree, eb->start, eb->start + eb->len - 1, GFP_NOFS);
	if (extent_buffer_uptodate(io_tree, eb) &&
	    btrfs_header_generation(eb) == parent_transid) {
		ret = 0;
		goto out;
	}
	if (printk_ratelimit()) {
		printk("parent transid verify failed on %llu wanted %llu "
		       "found %llu\n",
		       (unsigned long long)eb->start,
		       (unsigned long long)parent_transid,
		       (unsigned long long)btrfs_header_generation(eb));
	}
	ret = 1;
	clear_extent_buffer_uptodate(io_tree, eb);
out:
	unlock_extent(io_tree, eb->start, eb->start + eb->len - 1,
		      GFP_NOFS);
	return ret;
}

/*
 * helper to read a given tree block, doing retries as required when
 * the checksums don't match and we have alternate mirrors to try.
 */
static int btree_read_extent_buffer_pages(struct btrfs_root *root,
					  struct extent_buffer *eb,
					  u64 start, u64 parent_transid)
{
	struct extent_io_tree *io_tree;
	int ret;
	int num_copies = 0;
	int mirror_num = 0;

	io_tree = &BTRFS_I(root->fs_info->btree_inode)->io_tree;
	while (1) {
		ret = read_extent_buffer_pages(io_tree, eb, start, 1,
					       btree_get_extent, mirror_num);
		if (!ret &&
		    !verify_parent_transid(io_tree, eb, parent_transid))
			return ret;

		num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
					      eb->start, eb->len);
		if (num_copies == 1)
			return ret;

		mirror_num++;
		if (mirror_num > num_copies)
			return ret;
	}
	return -EIO;
}

/*
 * checksum a dirty tree block before IO.  This has extra checks to make sure
 * we only fill in the checksum field in the first page of a multi-page block
 */

static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
{
	struct extent_io_tree *tree;
	u64 start = (u64)page->index << PAGE_CACHE_SHIFT;
	u64 found_start;
	int found_level;
	unsigned long len;
	struct extent_buffer *eb;
	int ret;

	tree = &BTRFS_I(page->mapping->host)->io_tree;

	if (page->private == EXTENT_PAGE_PRIVATE)
		goto out;
	if (!page->private)
		goto out;
	len = page->private >> 2;
	WARN_ON(len == 0);

	eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS);
	ret = btree_read_extent_buffer_pages(root, eb, start + PAGE_CACHE_SIZE,
					     btrfs_header_generation(eb));
	BUG_ON(ret);
	found_start = btrfs_header_bytenr(eb);
	if (found_start != start) {
		WARN_ON(1);
		goto err;
	}
	if (eb->first_page != page) {
		WARN_ON(1);
		goto err;
	}
	if (!PageUptodate(page)) {
		WARN_ON(1);
		goto err;
	}
	found_level = btrfs_header_level(eb);

	csum_tree_block(root, eb, 0);
err:
	free_extent_buffer(eb);
out:
	return 0;
}

static int check_tree_block_fsid(struct btrfs_root *root,
				 struct extent_buffer *eb)
{
	struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
	u8 fsid[BTRFS_UUID_SIZE];
	int ret = 1;

	read_extent_buffer(eb, fsid, (unsigned long)btrfs_header_fsid(eb),
			   BTRFS_FSID_SIZE);
	while (fs_devices) {
		if (!memcmp(fsid, fs_devices->fsid, BTRFS_FSID_SIZE)) {
			ret = 0;
			break;
		}