diff options
Diffstat (limited to 'fs/exfat/fatent.c')
| -rw-r--r-- | fs/exfat/fatent.c | 41 | 
1 files changed, 31 insertions, 10 deletions
diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c index 7b2e8af17193..e949e563443c 100644 --- a/fs/exfat/fatent.c +++ b/fs/exfat/fatent.c @@ -151,13 +151,14 @@ int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain,  	return 0;  } -int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain) +/* This function must be called with bitmap_lock held */ +static int __exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain)  { -	unsigned int num_clusters = 0; -	unsigned int clu;  	struct super_block *sb = inode->i_sb;  	struct exfat_sb_info *sbi = EXFAT_SB(sb);  	int cur_cmap_i, next_cmap_i; +	unsigned int num_clusters = 0; +	unsigned int clu;  	/* invalid cluster number */  	if (p_chain->dir == EXFAT_FREE_CLUSTER || @@ -230,6 +231,17 @@ dec_used_clus:  	return 0;  } +int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain) +{ +	int ret = 0; + +	mutex_lock(&EXFAT_SB(inode->i_sb)->bitmap_lock); +	ret = __exfat_free_cluster(inode, p_chain); +	mutex_unlock(&EXFAT_SB(inode->i_sb)->bitmap_lock); + +	return ret; +} +  int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain,  		unsigned int *ret_clu)  { @@ -308,7 +320,7 @@ release_bhs:  }  int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc, -		struct exfat_chain *p_chain) +		struct exfat_chain *p_chain, bool sync_bmap)  {  	int ret = -ENOSPC;  	unsigned int num_clusters = 0, total_cnt; @@ -328,6 +340,8 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,  	if (num_alloc > total_cnt - sbi->used_clusters)  		return -ENOSPC; +	mutex_lock(&sbi->bitmap_lock); +  	hint_clu = p_chain->dir;  	/* find new cluster */  	if (hint_clu == EXFAT_EOF_CLUSTER) { @@ -338,8 +352,10 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,  		}  		hint_clu = exfat_find_free_bitmap(sb, sbi->clu_srch_ptr); -		if (hint_clu == EXFAT_EOF_CLUSTER) -			return -ENOSPC; +		if (hint_clu == EXFAT_EOF_CLUSTER) { +			ret = -ENOSPC; +			goto unlock; +		}  	}  	/* check cluster validation */ @@ -349,8 +365,10 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,  		hint_clu = EXFAT_FIRST_CLUSTER;  		if (p_chain->flags == ALLOC_NO_FAT_CHAIN) {  			if (exfat_chain_cont_cluster(sb, p_chain->dir, -					num_clusters)) -				return -EIO; +					num_clusters)) { +				ret = -EIO; +				goto unlock; +			}  			p_chain->flags = ALLOC_FAT_CHAIN;  		}  	} @@ -370,7 +388,7 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,  		}  		/* update allocation bitmap */ -		if (exfat_set_bitmap(inode, new_clu)) { +		if (exfat_set_bitmap(inode, new_clu, sync_bmap)) {  			ret = -EIO;  			goto free_cluster;  		} @@ -400,6 +418,7 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,  			sbi->used_clusters += num_clusters;  			p_chain->size += num_clusters; +			mutex_unlock(&sbi->bitmap_lock);  			return 0;  		} @@ -419,7 +438,9 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,  	}  free_cluster:  	if (num_clusters) -		exfat_free_cluster(inode, p_chain); +		__exfat_free_cluster(inode, p_chain); +unlock: +	mutex_unlock(&sbi->bitmap_lock);  	return ret;  }  | 
