@@ -2296,81 +2296,91 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from)
22962296	return  ret ;
22972297}
22982298
2299- static   int  btrfs_setattr (struct  dentry   * dentry ,  struct   iattr   * attr )
2299+ int  btrfs_cont_expand (struct  inode   * inode ,  loff_t   size )
23002300{
2301- 	struct  inode  * inode  =  dentry -> d_inode ;
2301+ 	struct  btrfs_trans_handle  * trans ;
2302+ 	struct  btrfs_root  * root  =  BTRFS_I (inode )-> root ;
2303+ 	struct  extent_io_tree  * io_tree  =  & BTRFS_I (inode )-> io_tree ;
2304+ 	struct  extent_map  * em ;
2305+ 	u64  mask  =  root -> sectorsize  -  1 ;
2306+ 	u64  hole_start  =  (inode -> i_size  +  mask ) &  ~mask ;
2307+ 	u64  block_end  =  (size  +  mask ) &  ~mask ;
2308+ 	u64  last_byte ;
2309+ 	u64  cur_offset ;
2310+ 	u64  hole_size ;
23022311	int  err ;
23032312
2304- 	err  =  inode_change_ok (inode , attr );
2313+ 	if  (size  <= hole_start )
2314+ 		return  0 ;
2315+ 
2316+ 	err  =  btrfs_check_free_space (root , 1 , 0 );
23052317	if  (err )
23062318		return  err ;
23072319
2308- 	if  (S_ISREG (inode -> i_mode ) && 
2309- 	    attr -> ia_valid  &  ATTR_SIZE  &&  attr -> ia_size  >  inode -> i_size ) {
2310- 		struct  btrfs_trans_handle  * trans ;
2311- 		struct  btrfs_root  * root  =  BTRFS_I (inode )-> root ;
2312- 		struct  extent_io_tree  * io_tree  =  & BTRFS_I (inode )-> io_tree ;
2320+ 	btrfs_truncate_page (inode -> i_mapping , inode -> i_size );
23132321
2314- 		u64  mask  =  root -> sectorsize  -  1 ;
2315- 		u64  hole_start  =  (inode -> i_size  +  mask ) &  ~mask ;
2316- 		u64  block_end  =  (attr -> ia_size  +  mask ) &  ~mask ;
2317- 		u64  hole_size ;
2318- 		u64  alloc_hint  =  0 ;
2322+ 	while  (1 ) {
2323+ 		struct  btrfs_ordered_extent  * ordered ;
2324+ 		btrfs_wait_ordered_range (inode , hole_start ,
2325+ 					 block_end  -  hole_start );
2326+ 		lock_extent (io_tree , hole_start , block_end  -  1 , GFP_NOFS );
2327+ 		ordered  =  btrfs_lookup_ordered_extent (inode , hole_start );
2328+ 		if  (!ordered )
2329+ 			break ;
2330+ 		unlock_extent (io_tree , hole_start , block_end  -  1 , GFP_NOFS );
2331+ 		btrfs_put_ordered_extent (ordered );
2332+ 	}
23192333
2320- 		 if  ( attr -> ia_size  <=  hole_start ) 
2321- 			goto  out ;
2334+ 	trans   =   btrfs_start_transaction ( root ,  1 ); 
2335+ 	btrfs_set_trans_block_group ( trans ,  inode ) ;
23222336
2323- 		err  =  btrfs_check_free_space (root , 1 , 0 );
2324- 		if  (err )
2325- 			goto fail ;
2337+ 	cur_offset  =  hole_start ;
2338+ 	while  (1 ) {
2339+ 		em  =  btrfs_get_extent (inode , NULL , 0 , cur_offset ,
2340+ 				block_end  -  cur_offset , 0 );
2341+ 		BUG_ON (IS_ERR (em ) ||  !em );
2342+ 		last_byte  =  min (extent_map_end (em ), block_end );
2343+ 		last_byte  =  (last_byte  +  mask ) &  ~mask ;
2344+ 		if  (test_bit (EXTENT_FLAG_VACANCY , & em -> flags )) {
2345+ 			hole_size  =  last_byte  -  cur_offset ;
2346+ 			err  =  btrfs_insert_file_extent (trans , root ,
2347+ 					inode -> i_ino , cur_offset , 0 ,
2348+ 					0 , hole_size , 0 , hole_size ,
2349+ 					0 , 0 , 0 );
2350+ 			btrfs_drop_extent_cache (inode , hole_start ,
2351+ 					last_byte  -  1 , 0 );
2352+ 		}
2353+ 		free_extent_map (em );
2354+ 		cur_offset  =  last_byte ;
2355+ 		if  (err  ||  cur_offset  >= block_end )
2356+ 			break ;
2357+ 	}
23262358
2327- 		btrfs_truncate_page (inode -> i_mapping , inode -> i_size );
2359+ 	btrfs_end_transaction (trans , root );
2360+ 	unlock_extent (io_tree , hole_start , block_end  -  1 , GFP_NOFS );
2361+ 	return  err ;
2362+ }
23282363
2329- 		hole_size  =  block_end  -  hole_start ;
2330- 		while (1 ) {
2331- 			struct  btrfs_ordered_extent  * ordered ;
2332- 			btrfs_wait_ordered_range (inode , hole_start , hole_size );
2333- 
2334- 			lock_extent (io_tree , hole_start , block_end  -  1 , GFP_NOFS );
2335- 			ordered  =  btrfs_lookup_ordered_extent (inode , hole_start );
2336- 			if  (ordered ) {
2337- 				unlock_extent (io_tree , hole_start ,
2338- 					      block_end  -  1 , GFP_NOFS );
2339- 				btrfs_put_ordered_extent (ordered );
2340- 			} else  {
2341- 				break ;
2342- 			}
2343- 		}
2364+ static  int  btrfs_setattr (struct  dentry  * dentry , struct  iattr  * attr )
2365+ {
2366+ 	struct  inode  * inode  =  dentry -> d_inode ;
2367+ 	int  err ;
23442368
2345- 		trans  =  btrfs_start_transaction (root , 1 );
2346- 		btrfs_set_trans_block_group (trans , inode );
2347- 		mutex_lock (& BTRFS_I (inode )-> extent_mutex );
2348- 		err  =  btrfs_drop_extents (trans , root , inode ,
2349- 					 hole_start , block_end , hole_start ,
2350- 					 & alloc_hint );
2369+ 	err  =  inode_change_ok (inode , attr );
2370+ 	if  (err )
2371+ 		return  err ;
23512372
2352- 		if  (alloc_hint  !=  EXTENT_MAP_INLINE ) {
2353- 			err  =  btrfs_insert_file_extent (trans , root ,
2354- 						       inode -> i_ino ,
2355- 						       hole_start , 0 , 0 ,
2356- 						       hole_size , 0 , hole_size ,
2357- 						       0 , 0 , 0 );
2358- 			btrfs_drop_extent_cache (inode , hole_start ,
2359- 						(u64 )- 1 , 0 );
2360- 			btrfs_check_file (root , inode );
2361- 		}
2362- 		mutex_unlock (& BTRFS_I (inode )-> extent_mutex );
2363- 		btrfs_end_transaction (trans , root );
2364- 		unlock_extent (io_tree , hole_start , block_end  -  1 , GFP_NOFS );
2373+ 	if  (S_ISREG (inode -> i_mode ) && 
2374+ 	    attr -> ia_valid  &  ATTR_SIZE  &&  attr -> ia_size  >  inode -> i_size ) {
2375+ 		err  =  btrfs_cont_expand (inode , attr -> ia_size );
23652376		if  (err )
23662377			return  err ;
23672378	}
2368- out : 
2379+ 
23692380	err  =  inode_setattr (inode , attr );
23702381
23712382	if  (!err  &&  ((attr -> ia_valid  &  ATTR_MODE )))
23722383		err  =  btrfs_acl_chmod (inode );
2373- fail :
23742384	return  err ;
23752385}
23762386
@@ -3456,27 +3466,44 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
34563466	if  (found_type  ==  BTRFS_FILE_EXTENT_REG ) {
34573467		extent_end  =  extent_start  + 
34583468		       btrfs_file_extent_num_bytes (leaf , item );
3459- 		err  =  0 ;
3460- 		if  (start  <  extent_start  ||  start  >= extent_end ) {
3461- 			em -> start  =  start ;
3462- 			if  (start  <  extent_start ) {
3463- 				if  (start  +  len  <= extent_start )
3464- 					goto not_found ;
3465- 				em -> len  =  extent_end  -  extent_start ;
3466- 			} else  {
3467- 				em -> len  =  len ;
3469+ 	} else  if  (found_type  ==  BTRFS_FILE_EXTENT_INLINE ) {
3470+ 		size_t  size ;
3471+ 		size  =  btrfs_file_extent_inline_len (leaf , item );
3472+ 		extent_end  =  (extent_start  +  size  +  root -> sectorsize  -  1 ) & 
3473+ 			~((u64 )root -> sectorsize  -  1 );
3474+ 	}
3475+ 
3476+ 	if  (start  >= extent_end ) {
3477+ 		path -> slots [0 ]++ ;
3478+ 		if  (path -> slots [0 ] >= btrfs_header_nritems (leaf )) {
3479+ 			ret  =  btrfs_next_leaf (root , path );
3480+ 			if  (ret  <  0 ) {
3481+ 				err  =  ret ;
3482+ 				goto out ;
34683483			}
3469- 			goto not_found_em ;
3484+ 			if  (ret  >  0 )
3485+ 				goto not_found ;
3486+ 			leaf  =  path -> nodes [0 ];
34703487		}
3488+ 		btrfs_item_key_to_cpu (leaf , & found_key , path -> slots [0 ]);
3489+ 		if  (found_key .objectid  !=  objectid  || 
3490+ 		    found_key .type  !=  BTRFS_EXTENT_DATA_KEY )
3491+ 			goto not_found ;
3492+ 		if  (start  +  len  <= found_key .offset )
3493+ 			goto not_found ;
3494+ 		em -> start  =  start ;
3495+ 		em -> len  =  found_key .offset  -  start ;
3496+ 		goto not_found_em ;
3497+ 	}
3498+ 
3499+ 	if  (found_type  ==  BTRFS_FILE_EXTENT_REG ) {
3500+ 		em -> start  =  extent_start ;
3501+ 		em -> len  =  extent_end  -  extent_start ;
34713502		bytenr  =  btrfs_file_extent_disk_bytenr (leaf , item );
34723503		if  (bytenr  ==  0 ) {
3473- 			em -> start  =  extent_start ;
3474- 			em -> len  =  extent_end  -  extent_start ;
34753504			em -> block_start  =  EXTENT_MAP_HOLE ;
34763505			goto insert ;
34773506		}
3478- 		em -> start  =  extent_start ;
3479- 		em -> len  =  extent_end  -  extent_start ;
34803507		if  (compressed ) {
34813508			set_bit (EXTENT_FLAG_COMPRESSED , & em -> flags );
34823509			em -> block_start  =  bytenr ;
@@ -3489,38 +3516,21 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
34893516		}
34903517		goto insert ;
34913518	} else  if  (found_type  ==  BTRFS_FILE_EXTENT_INLINE ) {
3492- 		u64  page_start ;
34933519		unsigned long  ptr ;
34943520		char  * map ;
34953521		size_t  size ;
34963522		size_t  extent_offset ;
34973523		size_t  copy_size ;
34983524
3499- 		size  =  btrfs_file_extent_inline_len (leaf , item );
3500- 		extent_end  =  (extent_start  +  size  +  root -> sectorsize  -  1 ) & 
3501- 			~((u64 )root -> sectorsize  -  1 );
3502- 		if  (start  <  extent_start  ||  start  >= extent_end ) {
3503- 			em -> start  =  start ;
3504- 			if  (start  <  extent_start ) {
3505- 				if  (start  +  len  <= extent_start )
3506- 					goto not_found ;
3507- 				em -> len  =  extent_end  -  extent_start ;
3508- 			} else  {
3509- 				em -> len  =  len ;
3510- 			}
3511- 			goto not_found_em ;
3512- 		}
35133525		em -> block_start  =  EXTENT_MAP_INLINE ;
3514- 
35153526		if  (!page  ||  create ) {
35163527			em -> start  =  extent_start ;
3517- 			em -> len  =  (size  +  root -> sectorsize  -  1 ) & 
3518- 			~((u64 )root -> sectorsize  -  1 );
3528+ 			em -> len  =  extent_end  -  extent_start ;
35193529			goto out ;
35203530		}
35213531
3522- 		page_start  =  page_offset ( page )  +   pg_offset ;
3523- 		extent_offset  =  page_start  -  extent_start ;
3532+ 		size  =  btrfs_file_extent_inline_len ( leaf ,  item ) ;
3533+ 		extent_offset  =  page_offset ( page )  +   pg_offset  -  extent_start ;
35243534		copy_size  =  min_t (u64 , PAGE_CACHE_SIZE  -  pg_offset ,
35253535				size  -  extent_offset );
35263536		em -> start  =  extent_start  +  extent_offset ;
@@ -3570,6 +3580,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
35703580	em -> len  =  len ;
35713581not_found_em :
35723582	em -> block_start  =  EXTENT_MAP_HOLE ;
3583+ 	set_bit (EXTENT_FLAG_VACANCY , & em -> flags );
35733584insert :
35743585	btrfs_release_path (root , path );
35753586	if  (em -> start  >  start  ||  extent_map_end (em ) <= start ) {
0 commit comments