diff options
Diffstat (limited to 'fs/btrfs/file.c')
| -rw-r--r-- | fs/btrfs/file.c | 91 | 
1 files changed, 54 insertions, 37 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 53bf2d764bb..9aa01ec2138 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -65,6 +65,21 @@ struct inode_defrag {  	int cycled;  }; +static int __compare_inode_defrag(struct inode_defrag *defrag1, +				  struct inode_defrag *defrag2) +{ +	if (defrag1->root > defrag2->root) +		return 1; +	else if (defrag1->root < defrag2->root) +		return -1; +	else if (defrag1->ino > defrag2->ino) +		return 1; +	else if (defrag1->ino < defrag2->ino) +		return -1; +	else +		return 0; +} +  /* pop a record for an inode into the defrag tree.  The lock   * must be held already   * @@ -81,15 +96,17 @@ static void __btrfs_add_inode_defrag(struct inode *inode,  	struct inode_defrag *entry;  	struct rb_node **p;  	struct rb_node *parent = NULL; +	int ret;  	p = &root->fs_info->defrag_inodes.rb_node;  	while (*p) {  		parent = *p;  		entry = rb_entry(parent, struct inode_defrag, rb_node); -		if (defrag->ino < entry->ino) +		ret = __compare_inode_defrag(defrag, entry); +		if (ret < 0)  			p = &parent->rb_left; -		else if (defrag->ino > entry->ino) +		else if (ret > 0)  			p = &parent->rb_right;  		else {  			/* if we're reinserting an entry for @@ -103,7 +120,7 @@ static void __btrfs_add_inode_defrag(struct inode *inode,  			goto exists;  		}  	} -	BTRFS_I(inode)->in_defrag = 1; +	set_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags);  	rb_link_node(&defrag->rb_node, parent, p);  	rb_insert_color(&defrag->rb_node, &root->fs_info->defrag_inodes);  	return; @@ -131,7 +148,7 @@ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,  	if (btrfs_fs_closing(root->fs_info))  		return 0; -	if (BTRFS_I(inode)->in_defrag) +	if (test_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags))  		return 0;  	if (trans) @@ -148,7 +165,7 @@ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,  	defrag->root = root->root_key.objectid;  	spin_lock(&root->fs_info->defrag_inodes_lock); -	if (!BTRFS_I(inode)->in_defrag) +	if (!test_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags))  		__btrfs_add_inode_defrag(inode, defrag);  	else  		kfree(defrag); @@ -159,28 +176,35 @@ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,  /*   * must be called with the defrag_inodes lock held   */ -struct inode_defrag *btrfs_find_defrag_inode(struct btrfs_fs_info *info, u64 ino, +struct inode_defrag *btrfs_find_defrag_inode(struct btrfs_fs_info *info, +					     u64 root, u64 ino,  					     struct rb_node **next)  {  	struct inode_defrag *entry = NULL; +	struct inode_defrag tmp;  	struct rb_node *p;  	struct rb_node *parent = NULL; +	int ret; + +	tmp.ino = ino; +	tmp.root = root;  	p = info->defrag_inodes.rb_node;  	while (p) {  		parent = p;  		entry = rb_entry(parent, struct inode_defrag, rb_node); -		if (ino < entry->ino) +		ret = __compare_inode_defrag(&tmp, entry); +		if (ret < 0)  			p = parent->rb_left; -		else if (ino > entry->ino) +		else if (ret > 0)  			p = parent->rb_right;  		else  			return entry;  	}  	if (next) { -		while (parent && ino > entry->ino) { +		while (parent && __compare_inode_defrag(&tmp, entry) > 0) {  			parent = rb_next(parent);  			entry = rb_entry(parent, struct inode_defrag, rb_node);  		} @@ -202,6 +226,7 @@ int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info)  	struct btrfs_key key;  	struct btrfs_ioctl_defrag_range_args range;  	u64 first_ino = 0; +	u64 root_objectid = 0;  	int num_defrag;  	int defrag_batch = 1024; @@ -214,11 +239,14 @@ int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info)  		n = NULL;  		/* find an inode to defrag */ -		defrag = btrfs_find_defrag_inode(fs_info, first_ino, &n); +		defrag = btrfs_find_defrag_inode(fs_info, root_objectid, +						 first_ino, &n);  		if (!defrag) { -			if (n) -				defrag = rb_entry(n, struct inode_defrag, rb_node); -			else if (first_ino) { +			if (n) { +				defrag = rb_entry(n, struct inode_defrag, +						  rb_node); +			} else if (root_objectid || first_ino) { +				root_objectid = 0;  				first_ino = 0;  				continue;  			} else { @@ -228,6 +256,7 @@ int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info)  		/* remove it from the rbtree */  		first_ino = defrag->ino + 1; +		root_objectid = defrag->root;  		rb_erase(&defrag->rb_node, &fs_info->defrag_inodes);  		if (btrfs_fs_closing(fs_info)) @@ -252,7 +281,7 @@ int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info)  			goto next;  		/* do a chunk of defrag */ -		BTRFS_I(inode)->in_defrag = 0; +		clear_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags);  		range.start = defrag->last_offset;  		num_defrag = btrfs_defrag_file(inode, NULL, &range, defrag->transid,  					       defrag_batch); @@ -1305,7 +1334,6 @@ static ssize_t __btrfs_direct_write(struct kiocb *iocb,  				    loff_t *ppos, size_t count, size_t ocount)  {  	struct file *file = iocb->ki_filp; -	struct inode *inode = fdentry(file)->d_inode;  	struct iov_iter i;  	ssize_t written;  	ssize_t written_buffered; @@ -1315,18 +1343,6 @@ static ssize_t __btrfs_direct_write(struct kiocb *iocb,  	written = generic_file_direct_write(iocb, iov, &nr_segs, pos, ppos,  					    count, ocount); -	/* -	 * the generic O_DIRECT will update in-memory i_size after the -	 * DIOs are done.  But our endio handlers that update the on -	 * disk i_size never update past the in memory i_size.  So we -	 * need one more update here to catch any additions to the -	 * file -	 */ -	if (inode->i_size != BTRFS_I(inode)->disk_i_size) { -		btrfs_ordered_update_i_size(inode, inode->i_size, NULL); -		mark_inode_dirty(inode); -	} -  	if (written < 0 || written == count)  		return written; @@ -1404,12 +1420,11 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,  		goto out;  	} -	err = btrfs_update_time(file); +	err = file_update_time(file);  	if (err) {  		mutex_unlock(&inode->i_mutex);  		goto out;  	} -	BTRFS_I(inode)->sequence++;  	start_pos = round_down(pos, root->sectorsize);  	if (start_pos > i_size_read(inode)) { @@ -1466,8 +1481,8 @@ int btrfs_release_file(struct inode *inode, struct file *filp)  	 * flush down new bytes that may have been written if the  	 * application were using truncate to replace a file in place.  	 */ -	if (BTRFS_I(inode)->ordered_data_close) { -		BTRFS_I(inode)->ordered_data_close = 0; +	if (test_and_clear_bit(BTRFS_INODE_ORDERED_DATA_CLOSE, +			       &BTRFS_I(inode)->runtime_flags)) {  		btrfs_add_ordered_operation(NULL, BTRFS_I(inode)->root, inode);  		if (inode->i_size > BTRFS_ORDERED_OPERATIONS_FLUSH_LIMIT)  			filemap_flush(inode->i_mapping); @@ -1498,14 +1513,15 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)  	trace_btrfs_sync_file(file, datasync); -	ret = filemap_write_and_wait_range(inode->i_mapping, start, end); -	if (ret) -		return ret;  	mutex_lock(&inode->i_mutex); -	/* we wait first, since the writeback may change the inode */ +	/* +	 * we wait first, since the writeback may change the inode, also wait +	 * ordered range does a filemape_write_and_wait_range which is why we +	 * don't do it above like other file systems. +	 */  	root->log_batch++; -	btrfs_wait_ordered_range(inode, 0, (u64)-1); +	btrfs_wait_ordered_range(inode, start, end);  	root->log_batch++;  	/* @@ -1523,7 +1539,8 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)  	 * syncing  	 */  	smp_mb(); -	if (BTRFS_I(inode)->last_trans <= +	if (btrfs_inode_in_log(inode, root->fs_info->generation) || +	    BTRFS_I(inode)->last_trans <=  	    root->fs_info->last_trans_committed) {  		BTRFS_I(inode)->last_trans = 0;  		mutex_unlock(&inode->i_mutex);  |