]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.6-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 2 Dec 2024 11:25:54 +0000 (12:25 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 2 Dec 2024 11:25:54 +0000 (12:25 +0100)
added patches:
alsa-usb-audio-fix-out-of-bounds-reads-when-finding-clock-sources.patch
closures-change-bug_on-to-warn_on.patch
dm-cache-fix-warnings-about-duplicate-slab-caches.patch
usb-ehci-spear-fix-call-balance-of-sehci-clk-handling-routines.patch
xen-fix-the-issue-of-resource-not-being-properly-released-in-xenbus_dev_probe.patch

queue-6.6/alsa-usb-audio-fix-out-of-bounds-reads-when-finding-clock-sources.patch [new file with mode: 0644]
queue-6.6/closures-change-bug_on-to-warn_on.patch [new file with mode: 0644]
queue-6.6/dm-cache-fix-warnings-about-duplicate-slab-caches.patch [new file with mode: 0644]
queue-6.6/series
queue-6.6/usb-ehci-spear-fix-call-balance-of-sehci-clk-handling-routines.patch [new file with mode: 0644]
queue-6.6/xen-fix-the-issue-of-resource-not-being-properly-released-in-xenbus_dev_probe.patch [new file with mode: 0644]

diff --git a/queue-6.6/alsa-usb-audio-fix-out-of-bounds-reads-when-finding-clock-sources.patch b/queue-6.6/alsa-usb-audio-fix-out-of-bounds-reads-when-finding-clock-sources.patch
new file mode 100644 (file)
index 0000000..e4af7f4
--- /dev/null
@@ -0,0 +1,90 @@
+From a3dd4d63eeb452cfb064a13862fb376ab108f6a6 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Mon, 25 Nov 2024 15:46:16 +0100
+Subject: ALSA: usb-audio: Fix out of bounds reads when finding clock sources
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit a3dd4d63eeb452cfb064a13862fb376ab108f6a6 upstream.
+
+The current USB-audio driver code doesn't check bLength of each
+descriptor at traversing for clock descriptors.  That is, when a
+device provides a bogus descriptor with a shorter bLength, the driver
+might hit out-of-bounds reads.
+
+For addressing it, this patch adds sanity checks to the validator
+functions for the clock descriptor traversal.  When the descriptor
+length is shorter than expected, it's skipped in the loop.
+
+For the clock source and clock multiplier descriptors, we can just
+check bLength against the sizeof() of each descriptor type.
+OTOH, the clock selector descriptor of UAC2 and UAC3 has an array
+of bNrInPins elements and two more fields at its tail, hence those
+have to be checked in addition to the sizeof() check.
+
+Reported-by: BenoĆ®t Sevens <bsevens@google.com>
+Cc: <stable@vger.kernel.org>
+Link: https://lore.kernel.org/20241121140613.3651-1-bsevens@google.com
+Link: https://patch.msgid.link/20241125144629.20757-1-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/usb/clock.c |   24 +++++++++++++++++++++++-
+ 1 file changed, 23 insertions(+), 1 deletion(-)
+
+--- a/sound/usb/clock.c
++++ b/sound/usb/clock.c
+@@ -36,6 +36,12 @@ union uac23_clock_multiplier_desc {
+       struct uac_clock_multiplier_descriptor v3;
+ };
++/* check whether the descriptor bLength has the minimal length */
++#define DESC_LENGTH_CHECK(p, proto) \
++      ((proto) == UAC_VERSION_3 ? \
++       ((p)->v3.bLength >= sizeof((p)->v3)) : \
++       ((p)->v2.bLength >= sizeof((p)->v2)))
++
+ #define GET_VAL(p, proto, field) \
+       ((proto) == UAC_VERSION_3 ? (p)->v3.field : (p)->v2.field)
+@@ -58,6 +64,8 @@ static bool validate_clock_source(void *
+ {
+       union uac23_clock_source_desc *cs = p;
++      if (!DESC_LENGTH_CHECK(cs, proto))
++              return false;
+       return GET_VAL(cs, proto, bClockID) == id;
+ }
+@@ -65,13 +73,27 @@ static bool validate_clock_selector(void
+ {
+       union uac23_clock_selector_desc *cs = p;
+-      return GET_VAL(cs, proto, bClockID) == id;
++      if (!DESC_LENGTH_CHECK(cs, proto))
++              return false;
++      if (GET_VAL(cs, proto, bClockID) != id)
++              return false;
++      /* additional length check for baCSourceID array (in bNrInPins size)
++       * and two more fields (which sizes depend on the protocol)
++       */
++      if (proto == UAC_VERSION_3)
++              return cs->v3.bLength >= sizeof(cs->v3) + cs->v3.bNrInPins +
++                      4 /* bmControls */ + 2 /* wCSelectorDescrStr */;
++      else
++              return cs->v2.bLength >= sizeof(cs->v2) + cs->v2.bNrInPins +
++                      1 /* bmControls */ + 1 /* iClockSelector */;
+ }
+ static bool validate_clock_multiplier(void *p, int id, int proto)
+ {
+       union uac23_clock_multiplier_desc *cs = p;
++      if (!DESC_LENGTH_CHECK(cs, proto))
++              return false;
+       return GET_VAL(cs, proto, bClockID) == id;
+ }
diff --git a/queue-6.6/closures-change-bug_on-to-warn_on.patch b/queue-6.6/closures-change-bug_on-to-warn_on.patch
new file mode 100644 (file)
index 0000000..df8b30e
--- /dev/null
@@ -0,0 +1,90 @@
+From 339b84ab6b1d66900c27bd999271cb2ae40ce812 Mon Sep 17 00:00:00 2001
+From: Kent Overstreet <kent.overstreet@linux.dev>
+Date: Thu, 20 Jun 2024 09:45:09 -0400
+Subject: closures: Change BUG_ON() to WARN_ON()
+
+From: Kent Overstreet <kent.overstreet@linux.dev>
+
+commit 339b84ab6b1d66900c27bd999271cb2ae40ce812 upstream.
+
+If a BUG_ON() can be hit in the wild, it shouldn't be a BUG_ON()
+
+For reference, this has popped up once in the CI, and we'll need more
+info to debug it:
+
+03240 ------------[ cut here ]------------
+03240 kernel BUG at lib/closure.c:21!
+03240 kernel BUG at lib/closure.c:21!
+03240 Internal error: Oops - BUG: 00000000f2000800 [#1] SMP
+03240 Modules linked in:
+03240 CPU: 15 PID: 40534 Comm: kworker/u80:1 Not tainted 6.10.0-rc4-ktest-ga56da69799bd #25570
+03240 Hardware name: linux,dummy-virt (DT)
+03240 Workqueue: btree_update btree_interior_update_work
+03240 pstate: 00001005 (nzcv daif -PAN -UAO -TCO -DIT +SSBS BTYPE=--)
+03240 pc : closure_put+0x224/0x2a0
+03240 lr : closure_put+0x24/0x2a0
+03240 sp : ffff0000d12071c0
+03240 x29: ffff0000d12071c0 x28: dfff800000000000 x27: ffff0000d1207360
+03240 x26: 0000000000000040 x25: 0000000000000040 x24: 0000000000000040
+03240 x23: ffff0000c1f20180 x22: 0000000000000000 x21: ffff0000c1f20168
+03240 x20: 0000000040000000 x19: ffff0000c1f20140 x18: 0000000000000001
+03240 x17: 0000000000003aa0 x16: 0000000000003ad0 x15: 1fffe0001c326974
+03240 x14: 0000000000000a1e x13: 0000000000000000 x12: 1fffe000183e402d
+03240 x11: ffff6000183e402d x10: dfff800000000000 x9 : ffff6000183e402e
+03240 x8 : 0000000000000001 x7 : 00009fffe7c1bfd3 x6 : ffff0000c1f2016b
+03240 x5 : ffff0000c1f20168 x4 : ffff6000183e402e x3 : ffff800081391954
+03240 x2 : 0000000000000001 x1 : 0000000000000000 x0 : 00000000a8000000
+03240 Call trace:
+03240  closure_put+0x224/0x2a0
+03240  bch2_check_for_deadlock+0x910/0x1028
+03240  bch2_six_check_for_deadlock+0x1c/0x30
+03240  six_lock_slowpath.isra.0+0x29c/0xed0
+03240  six_lock_ip_waiter+0xa8/0xf8
+03240  __bch2_btree_node_lock_write+0x14c/0x298
+03240  bch2_trans_lock_write+0x6d4/0xb10
+03240  __bch2_trans_commit+0x135c/0x5520
+03240  btree_interior_update_work+0x1248/0x1c10
+03240  process_scheduled_works+0x53c/0xd90
+03240  worker_thread+0x370/0x8c8
+03240  kthread+0x258/0x2e8
+03240  ret_from_fork+0x10/0x20
+03240 Code: aa1303e0 d63f0020 a94363f7 17ffff8c (d4210000)
+03240 ---[ end trace 0000000000000000 ]---
+03240 Kernel panic - not syncing: Oops - BUG: Fatal exception
+03240 SMP: stopping secondary CPUs
+03241 SMP: failed to stop secondary CPUs 13,15
+03241 Kernel Offset: disabled
+03241 CPU features: 0x00,00000003,80000008,4240500b
+03241 Memory Limit: none
+03241 ---[ end Kernel panic - not syncing: Oops - BUG: Fatal exception ]---
+03246 ========= FAILED TIMEOUT copygc_torture_no_checksum in 7200s
+
+Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
+[ Resolve minor conflicts to fix CVE-2024-42252 ]
+Signed-off-by: Bin Lan <bin.lan.cn@windriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/bcache/closure.c |   10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+--- a/drivers/md/bcache/closure.c
++++ b/drivers/md/bcache/closure.c
+@@ -17,10 +17,16 @@ static inline void closure_put_after_sub
+ {
+       int r = flags & CLOSURE_REMAINING_MASK;
+-      BUG_ON(flags & CLOSURE_GUARD_MASK);
+-      BUG_ON(!r && (flags & ~CLOSURE_DESTRUCTOR));
++      if (WARN(flags & CLOSURE_GUARD_MASK,
++               "closure has guard bits set: %x (%u)",
++               flags & CLOSURE_GUARD_MASK, (unsigned) __fls(r)))
++              r &= ~CLOSURE_GUARD_MASK;
+       if (!r) {
++              WARN(flags & ~CLOSURE_DESTRUCTOR,
++                   "closure ref hit 0 with incorrect flags set: %x (%u)",
++                   flags & ~CLOSURE_DESTRUCTOR, (unsigned) __fls(flags));
++
+               if (cl->fn && !(flags & CLOSURE_DESTRUCTOR)) {
+                       atomic_set(&cl->remaining,
+                                  CLOSURE_REMAINING_INITIALIZER);
diff --git a/queue-6.6/dm-cache-fix-warnings-about-duplicate-slab-caches.patch b/queue-6.6/dm-cache-fix-warnings-about-duplicate-slab-caches.patch
new file mode 100644 (file)
index 0000000..686b3be
--- /dev/null
@@ -0,0 +1,182 @@
+From 346dbf1b1345476a6524512892cceb931bee3039 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Mon, 11 Nov 2024 16:51:02 +0100
+Subject: dm-cache: fix warnings about duplicate slab caches
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit 346dbf1b1345476a6524512892cceb931bee3039 upstream.
+
+The commit 4c39529663b9 adds a warning about duplicate cache names if
+CONFIG_DEBUG_VM is selected. These warnings are triggered by the dm-cache
+code.
+
+The dm-cache code allocates a slab cache for each device. This commit
+changes it to allocate just one slab cache in the module init function.
+
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Fixes: 4c39529663b9 ("slab: Warn on duplicate cache names when DEBUG_VM=y")
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm-cache-background-tracker.c |   25 ++++++-------------------
+ drivers/md/dm-cache-background-tracker.h |    8 ++++++++
+ drivers/md/dm-cache-target.c             |   25 ++++++++++++++++++++-----
+ 3 files changed, 34 insertions(+), 24 deletions(-)
+
+--- a/drivers/md/dm-cache-background-tracker.c
++++ b/drivers/md/dm-cache-background-tracker.c
+@@ -11,12 +11,6 @@
+ #define DM_MSG_PREFIX "dm-background-tracker"
+-struct bt_work {
+-      struct list_head list;
+-      struct rb_node node;
+-      struct policy_work work;
+-};
+-
+ struct background_tracker {
+       unsigned int max_work;
+       atomic_t pending_promotes;
+@@ -26,10 +20,10 @@ struct background_tracker {
+       struct list_head issued;
+       struct list_head queued;
+       struct rb_root pending;
+-
+-      struct kmem_cache *work_cache;
+ };
++struct kmem_cache *btracker_work_cache = NULL;
++
+ struct background_tracker *btracker_create(unsigned int max_work)
+ {
+       struct background_tracker *b = kmalloc(sizeof(*b), GFP_KERNEL);
+@@ -48,12 +42,6 @@ struct background_tracker *btracker_crea
+       INIT_LIST_HEAD(&b->queued);
+       b->pending = RB_ROOT;
+-      b->work_cache = KMEM_CACHE(bt_work, 0);
+-      if (!b->work_cache) {
+-              DMERR("couldn't create mempool for background work items");
+-              kfree(b);
+-              b = NULL;
+-      }
+       return b;
+ }
+@@ -66,10 +54,9 @@ void btracker_destroy(struct background_
+       BUG_ON(!list_empty(&b->issued));
+       list_for_each_entry_safe (w, tmp, &b->queued, list) {
+               list_del(&w->list);
+-              kmem_cache_free(b->work_cache, w);
++              kmem_cache_free(btracker_work_cache, w);
+       }
+-      kmem_cache_destroy(b->work_cache);
+       kfree(b);
+ }
+ EXPORT_SYMBOL_GPL(btracker_destroy);
+@@ -180,7 +167,7 @@ static struct bt_work *alloc_work(struct
+       if (max_work_reached(b))
+               return NULL;
+-      return kmem_cache_alloc(b->work_cache, GFP_NOWAIT);
++      return kmem_cache_alloc(btracker_work_cache, GFP_NOWAIT);
+ }
+ int btracker_queue(struct background_tracker *b,
+@@ -203,7 +190,7 @@ int btracker_queue(struct background_tra
+                * There was a race, we'll just ignore this second
+                * bit of work for the same oblock.
+                */
+-              kmem_cache_free(b->work_cache, w);
++              kmem_cache_free(btracker_work_cache, w);
+               return -EINVAL;
+       }
+@@ -244,7 +231,7 @@ void btracker_complete(struct background
+       update_stats(b, &w->work, -1);
+       rb_erase(&w->node, &b->pending);
+       list_del(&w->list);
+-      kmem_cache_free(b->work_cache, w);
++      kmem_cache_free(btracker_work_cache, w);
+ }
+ EXPORT_SYMBOL_GPL(btracker_complete);
+--- a/drivers/md/dm-cache-background-tracker.h
++++ b/drivers/md/dm-cache-background-tracker.h
+@@ -26,6 +26,14 @@
+  * protected with a spinlock.
+  */
++struct bt_work {
++      struct list_head list;
++      struct rb_node node;
++      struct policy_work work;
++};
++
++extern struct kmem_cache *btracker_work_cache;
++
+ struct background_work;
+ struct background_tracker;
+--- a/drivers/md/dm-cache-target.c
++++ b/drivers/md/dm-cache-target.c
+@@ -10,6 +10,7 @@
+ #include "dm-bio-record.h"
+ #include "dm-cache-metadata.h"
+ #include "dm-io-tracker.h"
++#include "dm-cache-background-tracker.h"
+ #include <linux/dm-io.h>
+ #include <linux/dm-kcopyd.h>
+@@ -2267,7 +2268,7 @@ static int parse_cache_args(struct cache
+ /*----------------------------------------------------------------*/
+-static struct kmem_cache *migration_cache;
++static struct kmem_cache *migration_cache = NULL;
+ #define NOT_CORE_OPTION 1
+@@ -3455,22 +3456,36 @@ static int __init dm_cache_init(void)
+       int r;
+       migration_cache = KMEM_CACHE(dm_cache_migration, 0);
+-      if (!migration_cache)
+-              return -ENOMEM;
++      if (!migration_cache) {
++              r = -ENOMEM;
++              goto err;
++      }
++
++      btracker_work_cache = kmem_cache_create("dm_cache_bt_work",
++              sizeof(struct bt_work), __alignof__(struct bt_work), 0, NULL);
++      if (!btracker_work_cache) {
++              r = -ENOMEM;
++              goto err;
++      }
+       r = dm_register_target(&cache_target);
+       if (r) {
+-              kmem_cache_destroy(migration_cache);
+-              return r;
++              goto err;
+       }
+       return 0;
++
++err:
++      kmem_cache_destroy(migration_cache);
++      kmem_cache_destroy(btracker_work_cache);
++      return r;
+ }
+ static void __exit dm_cache_exit(void)
+ {
+       dm_unregister_target(&cache_target);
+       kmem_cache_destroy(migration_cache);
++      kmem_cache_destroy(btracker_work_cache);
+ }
+ module_init(dm_cache_init);
index 97c7f687814b351373a888328e97178a25be1a85..480b88bd699a25f0a7fe88f396ba47725372c7e7 100644 (file)
@@ -455,3 +455,8 @@ mailbox-mtk-cmdq-move-devm_mbox_controller_register-after-devm_pm_runtime_enable
 scsi-lpfc-validate-hdwq-pointers-before-dereferencing-in-reset-errata-paths.patch
 nvme-fix-metadata-handling-in-nvme-passthrough.patch
 xfs-add-bounds-checking-to-xlog_recover_process_data.patch
+xen-fix-the-issue-of-resource-not-being-properly-released-in-xenbus_dev_probe.patch
+alsa-usb-audio-fix-out-of-bounds-reads-when-finding-clock-sources.patch
+usb-ehci-spear-fix-call-balance-of-sehci-clk-handling-routines.patch
+closures-change-bug_on-to-warn_on.patch
+dm-cache-fix-warnings-about-duplicate-slab-caches.patch
diff --git a/queue-6.6/usb-ehci-spear-fix-call-balance-of-sehci-clk-handling-routines.patch b/queue-6.6/usb-ehci-spear-fix-call-balance-of-sehci-clk-handling-routines.patch
new file mode 100644 (file)
index 0000000..b448edc
--- /dev/null
@@ -0,0 +1,50 @@
+From 40c974826734836402abfd44efbf04f63a2cc1c1 Mon Sep 17 00:00:00 2001
+From: Vitalii Mordan <mordan@ispras.ru>
+Date: Fri, 15 Nov 2024 02:03:10 +0300
+Subject: usb: ehci-spear: fix call balance of sehci clk handling routines
+
+From: Vitalii Mordan <mordan@ispras.ru>
+
+commit 40c974826734836402abfd44efbf04f63a2cc1c1 upstream.
+
+If the clock sehci->clk was not enabled in spear_ehci_hcd_drv_probe,
+it should not be disabled in any path.
+
+Conversely, if it was enabled in spear_ehci_hcd_drv_probe, it must be disabled
+in all error paths to ensure proper cleanup.
+
+Found by Linux Verification Center (linuxtesting.org) with Klever.
+
+Fixes: 7675d6ba436f ("USB: EHCI: make ehci-spear a separate driver")
+Cc: stable@vger.kernel.org
+Signed-off-by: Vitalii Mordan <mordan@ispras.ru>
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+Link: https://lore.kernel.org/r/20241114230310.432213-1-mordan@ispras.ru
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/host/ehci-spear.c |    7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/host/ehci-spear.c
++++ b/drivers/usb/host/ehci-spear.c
+@@ -105,7 +105,9 @@ static int spear_ehci_hcd_drv_probe(stru
+       /* registers start at offset 0x0 */
+       hcd_to_ehci(hcd)->caps = hcd->regs;
+-      clk_prepare_enable(sehci->clk);
++      retval = clk_prepare_enable(sehci->clk);
++      if (retval)
++              goto err_put_hcd;
+       retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
+       if (retval)
+               goto err_stop_ehci;
+@@ -130,8 +132,7 @@ static void spear_ehci_hcd_drv_remove(st
+       usb_remove_hcd(hcd);
+-      if (sehci->clk)
+-              clk_disable_unprepare(sehci->clk);
++      clk_disable_unprepare(sehci->clk);
+       usb_put_hcd(hcd);
+ }
diff --git a/queue-6.6/xen-fix-the-issue-of-resource-not-being-properly-released-in-xenbus_dev_probe.patch b/queue-6.6/xen-fix-the-issue-of-resource-not-being-properly-released-in-xenbus_dev_probe.patch
new file mode 100644 (file)
index 0000000..afb3331
--- /dev/null
@@ -0,0 +1,66 @@
+From afc545da381ba0c651b2658966ac737032676f01 Mon Sep 17 00:00:00 2001
+From: Qiu-ji Chen <chenqiuji666@gmail.com>
+Date: Tue, 5 Nov 2024 21:09:19 +0800
+Subject: xen: Fix the issue of resource not being properly released in xenbus_dev_probe()
+
+From: Qiu-ji Chen <chenqiuji666@gmail.com>
+
+commit afc545da381ba0c651b2658966ac737032676f01 upstream.
+
+This patch fixes an issue in the function xenbus_dev_probe(). In the
+xenbus_dev_probe() function, within the if (err) branch at line 313, the
+program incorrectly returns err directly without releasing the resources
+allocated by err = drv->probe(dev, id). As the return value is non-zero,
+the upper layers assume the processing logic has failed. However, the probe
+operation was performed earlier without a corresponding remove operation.
+Since the probe actually allocates resources, failing to perform the remove
+operation could lead to problems.
+
+To fix this issue, we followed the resource release logic of the
+xenbus_dev_remove() function by adding a new block fail_remove before the
+fail_put block. After entering the branch if (err) at line 313, the
+function will use a goto statement to jump to the fail_remove block,
+ensuring that the previously acquired resources are correctly released,
+thus preventing the reference count leak.
+
+This bug was identified by an experimental static analysis tool developed
+by our team. The tool specializes in analyzing reference count operations
+and detecting potential issues where resources are not properly managed.
+In this case, the tool flagged the missing release operation as a
+potential problem, which led to the development of this patch.
+
+Fixes: 4bac07c993d0 ("xen: add the Xenbus sysfs and virtual device hotplug driver")
+Cc: stable@vger.kernel.org
+Signed-off-by: Qiu-ji Chen <chenqiuji666@gmail.com>
+Reviewed-by: Juergen Gross <jgross@suse.com>
+Message-ID: <20241105130919.4621-1-chenqiuji666@gmail.com>
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/xen/xenbus/xenbus_probe.c |    8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/xen/xenbus/xenbus_probe.c
++++ b/drivers/xen/xenbus/xenbus_probe.c
+@@ -313,7 +313,7 @@ int xenbus_dev_probe(struct device *_dev
+       if (err) {
+               dev_warn(&dev->dev, "watch_otherend on %s failed.\n",
+                      dev->nodename);
+-              return err;
++              goto fail_remove;
+       }
+       dev->spurious_threshold = 1;
+@@ -322,6 +322,12 @@ int xenbus_dev_probe(struct device *_dev
+                        dev->nodename);
+       return 0;
++fail_remove:
++      if (drv->remove) {
++              down(&dev->reclaim_sem);
++              drv->remove(dev);
++              up(&dev->reclaim_sem);
++      }
+ fail_put:
+       module_put(drv->driver.owner);
+ fail: