return has_metadata_uuid ? sb->metadata_uuid : sb->fsid;
 }
 
+/*
+ * We can have very weird soft links passed in.
+ * One example is "/proc/self/fd/<fd>", which can be a soft link to
+ * a block device.
+ *
+ * But it's never a good idea to use those weird names.
+ * Here we check if the path (not following symlinks) is a good one inside
+ * "/dev/".
+ */
+static bool is_good_dev_path(const char *dev_path)
+{
+       struct path path = { .mnt = NULL, .dentry = NULL };
+       char *path_buf = NULL;
+       char *resolved_path;
+       bool is_good = false;
+       int ret;
+
+       if (!dev_path)
+               goto out;
+
+       path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
+       if (!path_buf)
+               goto out;
+
+       /*
+        * Do not follow soft link, just check if the original path is inside
+        * "/dev/".
+        */
+       ret = kern_path(dev_path, 0, &path);
+       if (ret)
+               goto out;
+       resolved_path = d_path(&path, path_buf, PATH_MAX);
+       if (IS_ERR(resolved_path))
+               goto out;
+       if (strncmp(resolved_path, "/dev/", strlen("/dev/")))
+               goto out;
+       is_good = true;
+out:
+       kfree(path_buf);
+       path_put(&path);
+       return is_good;
+}
+
+static int get_canonical_dev_path(const char *dev_path, char *canonical)
+{
+       struct path path = { .mnt = NULL, .dentry = NULL };
+       char *path_buf = NULL;
+       char *resolved_path;
+       int ret;
+
+       if (!dev_path) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
+       if (!path_buf) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = kern_path(dev_path, LOOKUP_FOLLOW, &path);
+       if (ret)
+               goto out;
+       resolved_path = d_path(&path, path_buf, PATH_MAX);
+       ret = strscpy(canonical, resolved_path, PATH_MAX);
+out:
+       kfree(path_buf);
+       path_put(&path);
+       return ret;
+}
+
 static bool is_same_device(struct btrfs_device *device, const char *new_path)
 {
        struct path old = { .mnt = NULL, .dentry = NULL };
        bool new_device_added = false;
        struct btrfs_device *device = NULL;
        struct file *bdev_file;
+       char *canonical_path = NULL;
        u64 bytenr;
        dev_t devt;
        int ret;
 
        lockdep_assert_held(&uuid_mutex);
 
+       if (!is_good_dev_path(path)) {
+               canonical_path = kmalloc(PATH_MAX, GFP_KERNEL);
+               if (canonical_path) {
+                       ret = get_canonical_dev_path(path, canonical_path);
+                       if (ret < 0) {
+                               kfree(canonical_path);
+                               canonical_path = NULL;
+                       }
+               }
+       }
        /*
         * Avoid an exclusive open here, as the systemd-udev may initiate the
         * device scan which may race with the user's mount or mkfs command,
                goto free_disk_super;
        }
 
-       device = device_list_add(path, disk_super, &new_device_added);
+       device = device_list_add(canonical_path ? : path, disk_super,
+                                &new_device_added);
        if (!IS_ERR(device) && new_device_added)
                btrfs_free_stale_devices(device->devt, device);
 
 
 error_bdev_put:
        fput(bdev_file);
+       kfree(canonical_path);
 
        return device;
 }