diff options
Diffstat (limited to 'fs/f2fs/dir.c')
| -rw-r--r-- | fs/f2fs/dir.c | 146 | 
1 files changed, 80 insertions, 66 deletions
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 384c6daf9a8..a4addd72ebb 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -21,12 +21,12 @@ static unsigned long dir_blocks(struct inode *inode)  							>> PAGE_CACHE_SHIFT;  } -static unsigned int dir_buckets(unsigned int level) +static unsigned int dir_buckets(unsigned int level, int dir_level)  { -	if (level < MAX_DIR_HASH_DEPTH / 2) -		return 1 << level; +	if (level + dir_level < MAX_DIR_HASH_DEPTH / 2) +		return 1 << (level + dir_level);  	else -		return 1 << ((MAX_DIR_HASH_DEPTH / 2) - 1); +		return MAX_DIR_BUCKETS;  }  static unsigned int bucket_blocks(unsigned int level) @@ -65,13 +65,14 @@ static void set_de_type(struct f2fs_dir_entry *de, struct inode *inode)  	de->file_type = f2fs_type_by_mode[(mode & S_IFMT) >> S_SHIFT];  } -static unsigned long dir_block_index(unsigned int level, unsigned int idx) +static unsigned long dir_block_index(unsigned int level, +				int dir_level, unsigned int idx)  {  	unsigned long i;  	unsigned long bidx = 0;  	for (i = 0; i < level; i++) -		bidx += dir_buckets(i) * bucket_blocks(i); +		bidx += dir_buckets(i, dir_level) * bucket_blocks(i);  	bidx += idx * bucket_blocks(level);  	return bidx;  } @@ -93,16 +94,21 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page,  			f2fs_hash_t namehash, struct page **res_page)  {  	struct f2fs_dir_entry *de; -	unsigned long bit_pos, end_pos, next_pos; +	unsigned long bit_pos = 0;  	struct f2fs_dentry_block *dentry_blk = kmap(dentry_page); -	int slots; +	const void *dentry_bits = &dentry_blk->dentry_bitmap; +	int max_len = 0; -	bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, -					NR_DENTRY_IN_BLOCK, 0);  	while (bit_pos < NR_DENTRY_IN_BLOCK) { +		if (!test_bit_le(bit_pos, dentry_bits)) { +			if (bit_pos == 0) +				max_len = 1; +			else if (!test_bit_le(bit_pos - 1, dentry_bits)) +				max_len++; +			bit_pos++; +			continue; +		}  		de = &dentry_blk->dentry[bit_pos]; -		slots = GET_DENTRY_SLOTS(le16_to_cpu(de->name_len)); -  		if (early_match_name(name, namelen, namehash, de)) {  			if (!memcmp(dentry_blk->filename[bit_pos],  							name, namelen)) { @@ -110,20 +116,18 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page,  				goto found;  			}  		} -		next_pos = bit_pos + slots; -		bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, -				NR_DENTRY_IN_BLOCK, next_pos); -		if (bit_pos >= NR_DENTRY_IN_BLOCK) -			end_pos = NR_DENTRY_IN_BLOCK; -		else -			end_pos = bit_pos; -		if (*max_slots < end_pos - next_pos) -			*max_slots = end_pos - next_pos; +		if (max_len > *max_slots) { +			*max_slots = max_len; +			max_len = 0; +		} +		bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));  	}  	de = NULL;  	kunmap(dentry_page);  found: +	if (max_len > *max_slots) +		*max_slots = max_len;  	return de;  } @@ -139,12 +143,13 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,  	bool room = false;  	int max_slots = 0; -	BUG_ON(level > MAX_DIR_HASH_DEPTH); +	f2fs_bug_on(level > MAX_DIR_HASH_DEPTH); -	nbucket = dir_buckets(level); +	nbucket = dir_buckets(level, F2FS_I(dir)->i_dir_level);  	nblock = bucket_blocks(level); -	bidx = dir_block_index(level, le32_to_cpu(namehash) % nbucket); +	bidx = dir_block_index(level, F2FS_I(dir)->i_dir_level, +					le32_to_cpu(namehash) % nbucket);  	end_block = bidx + nblock;  	for (; bidx < end_block; bidx++) { @@ -190,9 +195,6 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,  	unsigned int max_depth;  	unsigned int level; -	if (namelen > F2FS_NAME_LEN) -		return NULL; -  	if (npages == 0)  		return NULL; @@ -251,7 +253,7 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,  		struct page *page, struct inode *inode)  {  	lock_page(page); -	wait_on_page_writeback(page); +	f2fs_wait_on_page_writeback(page, DATA);  	de->ino = cpu_to_le32(inode->i_ino);  	set_de_type(de, inode);  	kunmap(page); @@ -259,20 +261,19 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,  	dir->i_mtime = dir->i_ctime = CURRENT_TIME;  	mark_inode_dirty(dir); -	/* update parent inode number before releasing dentry page */ -	F2FS_I(inode)->i_pino = dir->i_ino; -  	f2fs_put_page(page, 1);  }  static void init_dent_inode(const struct qstr *name, struct page *ipage)  { -	struct f2fs_node *rn; +	struct f2fs_inode *ri; + +	f2fs_wait_on_page_writeback(ipage, NODE);  	/* copy name info. to this inode page */ -	rn = F2FS_NODE(ipage); -	rn->i.i_namelen = cpu_to_le32(name->len); -	memcpy(rn->i.i_name, name->name, name->len); +	ri = F2FS_INODE(ipage); +	ri->i_namelen = cpu_to_le32(name->len); +	memcpy(ri->i_name, name->name, name->len);  	set_page_dirty(ipage);  } @@ -346,21 +347,18 @@ static struct page *init_inode_metadata(struct inode *inode,  				goto error;  		} -		err = f2fs_init_acl(inode, dir); +		err = f2fs_init_acl(inode, dir, page);  		if (err) -			goto error; +			goto put_error;  		err = f2fs_init_security(inode, dir, name, page);  		if (err) -			goto error; - -		wait_on_page_writeback(page); +			goto put_error;  	} else {  		page = get_node_page(F2FS_SB(dir->i_sb), inode->i_ino);  		if (IS_ERR(page))  			return page; -		wait_on_page_writeback(page);  		set_cold_node(inode, page);  	} @@ -376,8 +374,13 @@ static struct page *init_inode_metadata(struct inode *inode,  	}  	return page; -error: +put_error:  	f2fs_put_page(page, 1); +error: +	/* once the failed inode becomes a bad inode, i_mode is S_IFREG */ +	truncate_inode_pages(&inode->i_data, 0); +	truncate_blocks(inode, 0); +	remove_dirty_dir_inode(inode);  	remove_inode_page(inode);  	return ERR_PTR(err);  } @@ -393,16 +396,13 @@ static void update_parent_metadata(struct inode *dir, struct inode *inode,  		clear_inode_flag(F2FS_I(inode), FI_NEW_INODE);  	}  	dir->i_mtime = dir->i_ctime = CURRENT_TIME; +	mark_inode_dirty(dir); +  	if (F2FS_I(dir)->i_current_depth != current_depth) {  		F2FS_I(dir)->i_current_depth = current_depth;  		set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);  	} -	if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) -		update_inode_page(dir); -	else -		mark_inode_dirty(dir); -  	if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK))  		clear_inode_flag(F2FS_I(inode), FI_INC_LINK);  } @@ -432,10 +432,11 @@ next:  }  /* - * Caller should grab and release a mutex by calling mutex_lock_op() and - * mutex_unlock_op(). + * Caller should grab and release a rwsem by calling f2fs_lock_op() and + * f2fs_unlock_op().   */ -int __f2fs_add_link(struct inode *dir, const struct qstr *name, struct inode *inode) +int __f2fs_add_link(struct inode *dir, const struct qstr *name, +						struct inode *inode)  {  	unsigned int bit_pos;  	unsigned int level; @@ -461,17 +462,18 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, struct inode *in  	}  start: -	if (current_depth == MAX_DIR_HASH_DEPTH) +	if (unlikely(current_depth == MAX_DIR_HASH_DEPTH))  		return -ENOSPC;  	/* Increase the depth, if required */  	if (level == current_depth)  		++current_depth; -	nbucket = dir_buckets(level); +	nbucket = dir_buckets(level, F2FS_I(dir)->i_dir_level);  	nblock = bucket_blocks(level); -	bidx = dir_block_index(level, (le32_to_cpu(dentry_hash) % nbucket)); +	bidx = dir_block_index(level, F2FS_I(dir)->i_dir_level, +				(le32_to_cpu(dentry_hash) % nbucket));  	for (block = bidx; block <= (bidx + nblock - 1); block++) {  		dentry_page = get_new_data_page(dir, NULL, block, true); @@ -491,8 +493,9 @@ start:  	++level;  	goto start;  add_dentry: -	wait_on_page_writeback(dentry_page); +	f2fs_wait_on_page_writeback(dentry_page, DATA); +	down_write(&F2FS_I(inode)->i_sem);  	page = init_inode_metadata(inode, dir, name);  	if (IS_ERR(page)) {  		err = PTR_ERR(page); @@ -515,7 +518,12 @@ add_dentry:  	update_parent_metadata(dir, inode, current_depth);  fail: -	clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); +	up_write(&F2FS_I(inode)->i_sem); + +	if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) { +		update_inode_page(dir); +		clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); +	}  	kunmap(dentry_page);  	f2fs_put_page(dentry_page, 1);  	return err; @@ -532,13 +540,12 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,  	unsigned int bit_pos;  	struct address_space *mapping = page->mapping;  	struct inode *dir = mapping->host; -	struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);  	int slots = GET_DENTRY_SLOTS(le16_to_cpu(dentry->name_len));  	void *kaddr = page_address(page);  	int i;  	lock_page(page); -	wait_on_page_writeback(page); +	f2fs_wait_on_page_writeback(page, DATA);  	dentry_blk = (struct f2fs_dentry_block *)kaddr;  	bit_pos = dentry - (struct f2fs_dir_entry *)dentry_blk->dentry; @@ -554,20 +561,22 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,  	dir->i_ctime = dir->i_mtime = CURRENT_TIME; -	if (inode && S_ISDIR(inode->i_mode)) { -		drop_nlink(dir); -		update_inode_page(dir); -	} else { -		mark_inode_dirty(dir); -	} -  	if (inode) { +		struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); + +		down_write(&F2FS_I(inode)->i_sem); + +		if (S_ISDIR(inode->i_mode)) { +			drop_nlink(dir); +			update_inode_page(dir); +		}  		inode->i_ctime = CURRENT_TIME;  		drop_nlink(inode);  		if (S_ISDIR(inode->i_mode)) {  			drop_nlink(inode);  			i_size_write(inode, 0);  		} +		up_write(&F2FS_I(inode)->i_sem);  		update_inode_page(inode);  		if (inode->i_nlink == 0) @@ -580,7 +589,6 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,  		truncate_hole(dir, page->index, page->index + 1);  		clear_page_dirty_for_io(page);  		ClearPageUptodate(page); -		dec_page_count(sbi, F2FS_DIRTY_DENTS);  		inode_dec_dirty_dents(dir);  	}  	f2fs_put_page(page, 1); @@ -631,12 +639,18 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)  	struct f2fs_dentry_block *dentry_blk = NULL;  	struct f2fs_dir_entry *de = NULL;  	struct page *dentry_page = NULL; +	struct file_ra_state *ra = &file->f_ra;  	unsigned int n = ((unsigned long)ctx->pos / NR_DENTRY_IN_BLOCK);  	unsigned char d_type = DT_UNKNOWN;  	bit_pos = ((unsigned long)ctx->pos % NR_DENTRY_IN_BLOCK); -	for ( ; n < npages; n++) { +	/* readahead for multi pages of dir */ +	if (npages - n > 1 && !ra_has_index(ra, n)) +		page_cache_sync_readahead(inode->i_mapping, ra, file, n, +				min(npages - n, (pgoff_t)MAX_DIR_RA_PAGES)); + +	for (; n < npages; n++) {  		dentry_page = get_lock_data_page(inode, n);  		if (IS_ERR(dentry_page))  			continue;  | 
