]> git.ipfire.org Git - thirdparty/linux.git/blobdiff - fs/btrfs/disk-io.c
btrfs: fix double free of anonymous device after snapshot creation failure
[thirdparty/linux.git] / fs / btrfs / disk-io.c
index e71ef97d0a7cabb236e8cbd073667b2e3d143dca..c843563914cad08e2dd84ef1741e19d933f092ee 100644 (file)
@@ -1307,12 +1307,12 @@ void btrfs_free_fs_info(struct btrfs_fs_info *fs_info)
  *
  * @objectid:  root id
  * @anon_dev:  preallocated anonymous block device number for new roots,
- *             pass 0 for new allocation.
+ *             pass NULL for a new allocation.
  * @check_ref: whether to check root item references, If true, return -ENOENT
  *             for orphan roots
  */
 static struct btrfs_root *btrfs_get_root_ref(struct btrfs_fs_info *fs_info,
-                                            u64 objectid, dev_t anon_dev,
+                                            u64 objectid, dev_t *anon_dev,
                                             bool check_ref)
 {
        struct btrfs_root *root;
@@ -1342,9 +1342,9 @@ again:
                 * that common but still possible.  In that case, we just need
                 * to free the anon_dev.
                 */
-               if (unlikely(anon_dev)) {
-                       free_anon_bdev(anon_dev);
-                       anon_dev = 0;
+               if (unlikely(anon_dev && *anon_dev)) {
+                       free_anon_bdev(*anon_dev);
+                       *anon_dev = 0;
                }
 
                if (check_ref && btrfs_root_refs(&root->root_item) == 0) {
@@ -1366,7 +1366,7 @@ again:
                goto fail;
        }
 
-       ret = btrfs_init_fs_root(root, anon_dev);
+       ret = btrfs_init_fs_root(root, anon_dev ? *anon_dev : 0);
        if (ret)
                goto fail;
 
@@ -1402,7 +1402,7 @@ fail:
         * root's anon_dev to 0 to avoid a double free, once by btrfs_put_root()
         * and once again by our caller.
         */
-       if (anon_dev)
+       if (anon_dev && *anon_dev)
                root->anon_dev = 0;
        btrfs_put_root(root);
        return ERR_PTR(ret);
@@ -1418,7 +1418,7 @@ fail:
 struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info,
                                     u64 objectid, bool check_ref)
 {
-       return btrfs_get_root_ref(fs_info, objectid, 0, check_ref);
+       return btrfs_get_root_ref(fs_info, objectid, NULL, check_ref);
 }
 
 /*
@@ -1426,11 +1426,11 @@ struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info,
  * the anonymous block device id
  *
  * @objectid:  tree objectid
- * @anon_dev:  if zero, allocate a new anonymous block device or use the
- *             parameter value
+ * @anon_dev:  if NULL, allocate a new anonymous block device or use the
+ *             parameter value if not NULL
  */
 struct btrfs_root *btrfs_get_new_fs_root(struct btrfs_fs_info *fs_info,
-                                        u64 objectid, dev_t anon_dev)
+                                        u64 objectid, dev_t *anon_dev)
 {
        return btrfs_get_root_ref(fs_info, objectid, anon_dev, true);
 }