浏览代码

Merge branch 'for-chris-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/fdmanana/linux into for-linus-4.5

Signed-off-by: Chris Mason <clm@fb.com>
Chris Mason 9 年之前
父节点
当前提交
988f1f576d
共有 4 个文件被更改,包括 58 次插入18 次删除
  1. 19 0
      fs/btrfs/extent-tree.c
  2. 14 7
      fs/btrfs/inode.c
  3. 15 1
      fs/btrfs/send.c
  4. 10 10
      fs/btrfs/volumes.c

+ 19 - 0
fs/btrfs/extent-tree.c

@@ -3768,6 +3768,25 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
 		}
 		}
 		if (!ret) {
 		if (!ret) {
 			ret = write_one_cache_group(trans, root, path, cache);
 			ret = write_one_cache_group(trans, root, path, cache);
+			/*
+			 * One of the free space endio workers might have
+			 * created a new block group while updating a free space
+			 * cache's inode (at inode.c:btrfs_finish_ordered_io())
+			 * and hasn't released its transaction handle yet, in
+			 * which case the new block group is still attached to
+			 * its transaction handle and its creation has not
+			 * finished yet (no block group item in the extent tree
+			 * yet, etc). If this is the case, wait for all free
+			 * space endio workers to finish and retry. This is a
+			 * a very rare case so no need for a more efficient and
+			 * complex approach.
+			 */
+			if (ret == -ENOENT) {
+				wait_event(cur_trans->writer_wait,
+				   atomic_read(&cur_trans->num_writers) == 1);
+				ret = write_one_cache_group(trans, root, path,
+							    cache);
+			}
 			if (ret)
 			if (ret)
 				btrfs_abort_transaction(trans, root, ret);
 				btrfs_abort_transaction(trans, root, ret);
 		}
 		}

+ 14 - 7
fs/btrfs/inode.c

@@ -6478,7 +6478,7 @@ out_unlock_inode:
 static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
 static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
 		      struct dentry *dentry)
 		      struct dentry *dentry)
 {
 {
-	struct btrfs_trans_handle *trans;
+	struct btrfs_trans_handle *trans = NULL;
 	struct btrfs_root *root = BTRFS_I(dir)->root;
 	struct btrfs_root *root = BTRFS_I(dir)->root;
 	struct inode *inode = d_inode(old_dentry);
 	struct inode *inode = d_inode(old_dentry);
 	u64 index;
 	u64 index;
@@ -6504,6 +6504,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
 	trans = btrfs_start_transaction(root, 5);
 	trans = btrfs_start_transaction(root, 5);
 	if (IS_ERR(trans)) {
 	if (IS_ERR(trans)) {
 		err = PTR_ERR(trans);
 		err = PTR_ERR(trans);
+		trans = NULL;
 		goto fail;
 		goto fail;
 	}
 	}
 
 
@@ -6537,9 +6538,10 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
 		btrfs_log_new_name(trans, inode, NULL, parent);
 		btrfs_log_new_name(trans, inode, NULL, parent);
 	}
 	}
 
 
-	btrfs_end_transaction(trans, root);
 	btrfs_balance_delayed_items(root);
 	btrfs_balance_delayed_items(root);
 fail:
 fail:
+	if (trans)
+		btrfs_end_transaction(trans, root);
 	if (drop_inode) {
 	if (drop_inode) {
 		inode_dec_link_count(inode);
 		inode_dec_link_count(inode);
 		iput(inode);
 		iput(inode);
@@ -9655,9 +9657,11 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
 	/*
 	/*
 	 * 2 items for inode item and ref
 	 * 2 items for inode item and ref
 	 * 2 items for dir items
 	 * 2 items for dir items
+	 * 1 item for updating parent inode item
+	 * 1 item for the inline extent item
 	 * 1 item for xattr if selinux is on
 	 * 1 item for xattr if selinux is on
 	 */
 	 */
-	trans = btrfs_start_transaction(root, 5);
+	trans = btrfs_start_transaction(root, 7);
 	if (IS_ERR(trans))
 	if (IS_ERR(trans))
 		return PTR_ERR(trans);
 		return PTR_ERR(trans);
 
 
@@ -9688,10 +9692,6 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
 	if (err)
 	if (err)
 		goto out_unlock_inode;
 		goto out_unlock_inode;
 
 
-	err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
-	if (err)
-		goto out_unlock_inode;
-
 	path = btrfs_alloc_path();
 	path = btrfs_alloc_path();
 	if (!path) {
 	if (!path) {
 		err = -ENOMEM;
 		err = -ENOMEM;
@@ -9728,6 +9728,13 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
 	inode_set_bytes(inode, name_len);
 	inode_set_bytes(inode, name_len);
 	btrfs_i_size_write(inode, name_len);
 	btrfs_i_size_write(inode, name_len);
 	err = btrfs_update_inode(trans, root, inode);
 	err = btrfs_update_inode(trans, root, inode);
+	/*
+	 * Last step, add directory indexes for our symlink inode. This is the
+	 * last step to avoid extra cleanup of these indexes if an error happens
+	 * elsewhere above.
+	 */
+	if (!err)
+		err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
 	if (err) {
 	if (err) {
 		drop_inode = 1;
 		drop_inode = 1;
 		goto out_unlock_inode;
 		goto out_unlock_inode;

+ 15 - 1
fs/btrfs/send.c

@@ -1469,7 +1469,21 @@ static int read_symlink(struct btrfs_root *root,
 	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
 	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
 	if (ret < 0)
 	if (ret < 0)
 		goto out;
 		goto out;
-	BUG_ON(ret);
+	if (ret) {
+		/*
+		 * An empty symlink inode. Can happen in rare error paths when
+		 * creating a symlink (transaction committed before the inode
+		 * eviction handler removed the symlink inode items and a crash
+		 * happened in between or the subvol was snapshoted in between).
+		 * Print an informative message to dmesg/syslog so that the user
+		 * can delete the symlink.
+		 */
+		btrfs_err(root->fs_info,
+			  "Found empty symlink inode %llu at root %llu",
+			  ino, root->root_key.objectid);
+		ret = -EIO;
+		goto out;
+	}
 
 
 	ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
 	ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
 			struct btrfs_file_extent_item);
 			struct btrfs_file_extent_item);

+ 10 - 10
fs/btrfs/volumes.c

@@ -1258,6 +1258,15 @@ int find_free_dev_extent_start(struct btrfs_transaction *transaction,
 	int ret;
 	int ret;
 	int slot;
 	int slot;
 	struct extent_buffer *l;
 	struct extent_buffer *l;
+	u64 min_search_start;
+
+	/*
+	 * We don't want to overwrite the superblock on the drive nor any area
+	 * used by the boot loader (grub for example), so we make sure to start
+	 * at an offset of at least 1MB.
+	 */
+	min_search_start = max(root->fs_info->alloc_start, 1024ull * 1024);
+	search_start = max(search_start, min_search_start);
 
 
 	path = btrfs_alloc_path();
 	path = btrfs_alloc_path();
 	if (!path)
 	if (!path)
@@ -1398,18 +1407,9 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans,
 			 struct btrfs_device *device, u64 num_bytes,
 			 struct btrfs_device *device, u64 num_bytes,
 			 u64 *start, u64 *len)
 			 u64 *start, u64 *len)
 {
 {
-	struct btrfs_root *root = device->dev_root;
-	u64 search_start;
-
 	/* FIXME use last free of some kind */
 	/* FIXME use last free of some kind */
-
-	/*
-	 * we don't want to overwrite the superblock on the drive,
-	 * so we make sure to start at an offset of at least 1MB
-	 */
-	search_start = max_t(u64, root->fs_info->alloc_start, SZ_1M);
 	return find_free_dev_extent_start(trans->transaction, device,
 	return find_free_dev_extent_start(trans->transaction, device,
-					  num_bytes, search_start, start, len);
+					  num_bytes, 0, start, len);
 }
 }
 
 
 static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans,
 static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans,