Btrfs: fix missing error return if writeback for extent buffer never started
[linux-2.6-block.git] / fs / btrfs / qgroup.c
index f8a3c1b0a15a81d5cb3a9ea5cdd9c6205fe32d96..8d3bd799ac7dadb06a42dff8799c886b758f048d 100644 (file)
@@ -21,7 +21,7 @@
 #include "backref.h"
 #include "extent_io.h"
 #include "qgroup.h"
-
+#include "block-group.h"
 
 /* TODO XXX FIXME
  *  - subvol delete -> delete when ref goes to 0? delete limits also?
@@ -1312,8 +1312,9 @@ static int __del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src,
        struct btrfs_qgroup *member;
        struct btrfs_qgroup_list *list;
        struct ulist *tmp;
+       bool found = false;
        int ret = 0;
-       int err;
+       int ret2;
 
        tmp = ulist_alloc(GFP_KERNEL);
        if (!tmp)
@@ -1327,28 +1328,39 @@ static int __del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src,
 
        member = find_qgroup_rb(fs_info, src);
        parent = find_qgroup_rb(fs_info, dst);
-       if (!member || !parent) {
-               ret = -EINVAL;
-               goto out;
-       }
+       /*
+        * The parent/member pair doesn't exist, then try to delete the dead
+        * relation items only.
+        */
+       if (!member || !parent)
+               goto delete_item;
 
        /* check if such qgroup relation exist firstly */
        list_for_each_entry(list, &member->groups, next_group) {
-               if (list->group == parent)
-                       goto exist;
+               if (list->group == parent) {
+                       found = true;
+                       break;
+               }
        }
-       ret = -ENOENT;
-       goto out;
-exist:
+
+delete_item:
        ret = del_qgroup_relation_item(trans, src, dst);
-       err = del_qgroup_relation_item(trans, dst, src);
-       if (err && !ret)
-               ret = err;
+       if (ret < 0 && ret != -ENOENT)
+               goto out;
+       ret2 = del_qgroup_relation_item(trans, dst, src);
+       if (ret2 < 0 && ret2 != -ENOENT)
+               goto out;
 
-       spin_lock(&fs_info->qgroup_lock);
-       del_relation_rb(fs_info, src, dst);
-       ret = quick_update_accounting(fs_info, tmp, src, dst, -1);
-       spin_unlock(&fs_info->qgroup_lock);
+       /* At least one deletion succeeded, return 0 */
+       if (!ret || !ret2)
+               ret = 0;
+
+       if (found) {
+               spin_lock(&fs_info->qgroup_lock);
+               del_relation_rb(fs_info, src, dst);
+               ret = quick_update_accounting(fs_info, tmp, src, dst, -1);
+               spin_unlock(&fs_info->qgroup_lock);
+       }
 out:
        ulist_free(tmp);
        return ret;