From: Greg Kroah-Hartman Date: Mon, 19 Aug 2024 09:37:03 +0000 (+0200) Subject: 4.19-stable patches X-Git-Tag: v6.1.107~140 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=34060ad99ca3264eeec1698510721b884cab1f68;p=thirdparty%2Fkernel%2Fstable-queue.git 4.19-stable patches added patches: alsa-usb-audio-support-yamaha-p-125-quirk-entry.patch arm64-acpi-numa-initialize-all-values-of-acpi_early_node_map-to-numa_no_node.patch dm-persistent-data-fix-memory-allocation-failure.patch dm-resume-don-t-return-einval-when-signalled.patch fix-bitmap-corruption-on-close_range-with-close_range_unshare.patch xhci-fix-panther-point-null-pointer-deref-at-full-speed-re-enumeration.patch --- diff --git a/queue-4.19/alsa-usb-audio-support-yamaha-p-125-quirk-entry.patch b/queue-4.19/alsa-usb-audio-support-yamaha-p-125-quirk-entry.patch new file mode 100644 index 00000000000..871ecc7d9f4 --- /dev/null +++ b/queue-4.19/alsa-usb-audio-support-yamaha-p-125-quirk-entry.patch @@ -0,0 +1,33 @@ +From c286f204ce6ba7b48e3dcba53eda7df8eaa64dd9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Juan=20Jos=C3=A9=20Arboleda?= +Date: Tue, 13 Aug 2024 11:10:53 -0500 +Subject: ALSA: usb-audio: Support Yamaha P-125 quirk entry +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Juan José Arboleda + +commit c286f204ce6ba7b48e3dcba53eda7df8eaa64dd9 upstream. + +This patch adds a USB quirk for the Yamaha P-125 digital piano. + +Signed-off-by: Juan José Arboleda +Cc: +Link: https://patch.msgid.link/20240813161053.70256-1-soyjuanarbol@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/usb/quirks-table.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/sound/usb/quirks-table.h ++++ b/sound/usb/quirks-table.h +@@ -352,6 +352,7 @@ YAMAHA_DEVICE(0x105a, NULL), + YAMAHA_DEVICE(0x105b, NULL), + YAMAHA_DEVICE(0x105c, NULL), + YAMAHA_DEVICE(0x105d, NULL), ++YAMAHA_DEVICE(0x1718, "P-125"), + { + USB_DEVICE(0x0499, 0x1503), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { diff --git a/queue-4.19/arm64-acpi-numa-initialize-all-values-of-acpi_early_node_map-to-numa_no_node.patch b/queue-4.19/arm64-acpi-numa-initialize-all-values-of-acpi_early_node_map-to-numa_no_node.patch new file mode 100644 index 00000000000..fca8a4428fd --- /dev/null +++ b/queue-4.19/arm64-acpi-numa-initialize-all-values-of-acpi_early_node_map-to-numa_no_node.patch @@ -0,0 +1,42 @@ +From a21dcf0ea8566ebbe011c79d6ed08cdfea771de3 Mon Sep 17 00:00:00 2001 +From: Haibo Xu +Date: Mon, 5 Aug 2024 11:30:24 +0800 +Subject: arm64: ACPI: NUMA: initialize all values of acpi_early_node_map to NUMA_NO_NODE + +From: Haibo Xu + +commit a21dcf0ea8566ebbe011c79d6ed08cdfea771de3 upstream. + +Currently, only acpi_early_node_map[0] was initialized to NUMA_NO_NODE. +To ensure all the values were properly initialized, switch to initialize +all of them to NUMA_NO_NODE. + +Fixes: e18962491696 ("arm64: numa: rework ACPI NUMA initialization") +Cc: # 4.19.x +Reported-by: Andrew Jones +Suggested-by: Andrew Jones +Signed-off-by: Haibo Xu +Reviewed-by: Anshuman Khandual +Reviewed-by: Sunil V L +Reviewed-by: Andrew Jones +Acked-by: Catalin Marinas +Acked-by: Lorenzo Pieralisi +Reviewed-by: Hanjun Guo +Link: https://lore.kernel.org/r/853d7f74aa243f6f5999e203246f0d1ae92d2b61.1722828421.git.haibo1.xu@intel.com +Signed-off-by: Catalin Marinas +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm64/kernel/acpi_numa.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm64/kernel/acpi_numa.c ++++ b/arch/arm64/kernel/acpi_numa.c +@@ -28,7 +28,7 @@ + + #include + +-static int acpi_early_node_map[NR_CPUS] __initdata = { NUMA_NO_NODE }; ++static int acpi_early_node_map[NR_CPUS] __initdata = { [0 ... NR_CPUS - 1] = NUMA_NO_NODE }; + + int __init acpi_numa_get_nid(unsigned int cpu) + { diff --git a/queue-4.19/dm-persistent-data-fix-memory-allocation-failure.patch b/queue-4.19/dm-persistent-data-fix-memory-allocation-failure.patch new file mode 100644 index 00000000000..da31b4046a3 --- /dev/null +++ b/queue-4.19/dm-persistent-data-fix-memory-allocation-failure.patch @@ -0,0 +1,45 @@ +From faada2174c08662ae98b439c69efe3e79382c538 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Tue, 13 Aug 2024 16:35:14 +0200 +Subject: dm persistent data: fix memory allocation failure + +From: Mikulas Patocka + +commit faada2174c08662ae98b439c69efe3e79382c538 upstream. + +kmalloc is unreliable when allocating more than 8 pages of memory. It may +fail when there is plenty of free memory but the memory is fragmented. +Zdenek Kabelac observed such failure in his tests. + +This commit changes kmalloc to kvmalloc - kvmalloc will fall back to +vmalloc if the large allocation fails. + +Signed-off-by: Mikulas Patocka +Reported-by: Zdenek Kabelac +Reviewed-by: Mike Snitzer +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/persistent-data/dm-space-map-metadata.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/md/persistent-data/dm-space-map-metadata.c ++++ b/drivers/md/persistent-data/dm-space-map-metadata.c +@@ -275,7 +275,7 @@ static void sm_metadata_destroy(struct d + { + struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); + +- kfree(smm); ++ kvfree(smm); + } + + static int sm_metadata_get_nr_blocks(struct dm_space_map *sm, dm_block_t *count) +@@ -759,7 +759,7 @@ struct dm_space_map *dm_sm_metadata_init + { + struct sm_metadata *smm; + +- smm = kmalloc(sizeof(*smm), GFP_KERNEL); ++ smm = kvmalloc(sizeof(*smm), GFP_KERNEL); + if (!smm) + return ERR_PTR(-ENOMEM); + diff --git a/queue-4.19/dm-resume-don-t-return-einval-when-signalled.patch b/queue-4.19/dm-resume-don-t-return-einval-when-signalled.patch new file mode 100644 index 00000000000..5cc65312622 --- /dev/null +++ b/queue-4.19/dm-resume-don-t-return-einval-when-signalled.patch @@ -0,0 +1,60 @@ +From 7a636b4f03af9d541205f69e373672e7b2b60a8a Mon Sep 17 00:00:00 2001 +From: Khazhismel Kumykov +Date: Tue, 13 Aug 2024 12:39:52 +0200 +Subject: dm resume: don't return EINVAL when signalled + +From: Khazhismel Kumykov + +commit 7a636b4f03af9d541205f69e373672e7b2b60a8a upstream. + +If the dm_resume method is called on a device that is not suspended, the +method will suspend the device briefly, before resuming it (so that the +table will be swapped). + +However, there was a bug that the return value of dm_suspended_md was not +checked. dm_suspended_md may return an error when it is interrupted by a +signal. In this case, do_resume would call dm_swap_table, which would +return -EINVAL. + +This commit fixes the logic, so that error returned by dm_suspend is +checked and the resume operation is undone. + +Signed-off-by: Mikulas Patocka +Signed-off-by: Khazhismel Kumykov +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/dm-ioctl.c | 22 ++++++++++++++++++++-- + 1 file changed, 20 insertions(+), 2 deletions(-) + +--- a/drivers/md/dm-ioctl.c ++++ b/drivers/md/dm-ioctl.c +@@ -1039,8 +1039,26 @@ static int do_resume(struct dm_ioctl *pa + suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG; + if (param->flags & DM_NOFLUSH_FLAG) + suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG; +- if (!dm_suspended_md(md)) +- dm_suspend(md, suspend_flags); ++ if (!dm_suspended_md(md)) { ++ r = dm_suspend(md, suspend_flags); ++ if (r) { ++ down_write(&_hash_lock); ++ hc = dm_get_mdptr(md); ++ if (hc && !hc->new_map) { ++ hc->new_map = new_map; ++ new_map = NULL; ++ } else { ++ r = -ENXIO; ++ } ++ up_write(&_hash_lock); ++ if (new_map) { ++ dm_sync_table(md); ++ dm_table_destroy(new_map); ++ } ++ dm_put(md); ++ return r; ++ } ++ } + + old_map = dm_swap_table(md, new_map); + if (IS_ERR(old_map)) { diff --git a/queue-4.19/fix-bitmap-corruption-on-close_range-with-close_range_unshare.patch b/queue-4.19/fix-bitmap-corruption-on-close_range-with-close_range_unshare.patch new file mode 100644 index 00000000000..61aa616820e --- /dev/null +++ b/queue-4.19/fix-bitmap-corruption-on-close_range-with-close_range_unshare.patch @@ -0,0 +1,193 @@ +From 9a2fa1472083580b6c66bdaf291f591e1170123a Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Sat, 3 Aug 2024 18:02:00 -0400 +Subject: fix bitmap corruption on close_range() with CLOSE_RANGE_UNSHARE + +From: Al Viro + +commit 9a2fa1472083580b6c66bdaf291f591e1170123a upstream. + +copy_fd_bitmaps(new, old, count) is expected to copy the first +count/BITS_PER_LONG bits from old->full_fds_bits[] and fill +the rest with zeroes. What it does is copying enough words +(BITS_TO_LONGS(count/BITS_PER_LONG)), then memsets the rest. +That works fine, *if* all bits past the cutoff point are +clear. Otherwise we are risking garbage from the last word +we'd copied. + +For most of the callers that is true - expand_fdtable() has +count equal to old->max_fds, so there's no open descriptors +past count, let alone fully occupied words in ->open_fds[], +which is what bits in ->full_fds_bits[] correspond to. + +The other caller (dup_fd()) passes sane_fdtable_size(old_fdt, max_fds), +which is the smallest multiple of BITS_PER_LONG that covers all +opened descriptors below max_fds. In the common case (copying on +fork()) max_fds is ~0U, so all opened descriptors will be below +it and we are fine, by the same reasons why the call in expand_fdtable() +is safe. + +Unfortunately, there is a case where max_fds is less than that +and where we might, indeed, end up with junk in ->full_fds_bits[] - +close_range(from, to, CLOSE_RANGE_UNSHARE) with + * descriptor table being currently shared + * 'to' being above the current capacity of descriptor table + * 'from' being just under some chunk of opened descriptors. +In that case we end up with observably wrong behaviour - e.g. spawn +a child with CLONE_FILES, get all descriptors in range 0..127 open, +then close_range(64, ~0U, CLOSE_RANGE_UNSHARE) and watch dup(0) ending +up with descriptor #128, despite #64 being observably not open. + +The minimally invasive fix would be to deal with that in dup_fd(). +If this proves to add measurable overhead, we can go that way, but +let's try to fix copy_fd_bitmaps() first. + +* new helper: bitmap_copy_and_expand(to, from, bits_to_copy, size). +* make copy_fd_bitmaps() take the bitmap size in words, rather than +bits; it's 'count' argument is always a multiple of BITS_PER_LONG, +so we are not losing any information, and that way we can use the +same helper for all three bitmaps - compiler will see that count +is a multiple of BITS_PER_LONG for the large ones, so it'll generate +plain memcpy()+memset(). + +Reproducer added to tools/testing/selftests/core/close_range_test.c + +Cc: stable@vger.kernel.org +Signed-off-by: Al Viro +Signed-off-by: Greg Kroah-Hartman +--- + fs/file.c | 28 +++++++-------- + include/linux/bitmap.h | 12 +++++++ + .../testing/selftests/core/close_range_test.c | 35 +++++++++++++++++++ + 3 files changed, 59 insertions(+), 16 deletions(-) + +diff --git a/fs/file.c b/fs/file.c +index a11e59b5d602..655338effe9c 100644 +--- a/fs/file.c ++++ b/fs/file.c +@@ -46,27 +46,23 @@ static void free_fdtable_rcu(struct rcu_head *rcu) + #define BITBIT_NR(nr) BITS_TO_LONGS(BITS_TO_LONGS(nr)) + #define BITBIT_SIZE(nr) (BITBIT_NR(nr) * sizeof(long)) + ++#define fdt_words(fdt) ((fdt)->max_fds / BITS_PER_LONG) // words in ->open_fds + /* + * Copy 'count' fd bits from the old table to the new table and clear the extra + * space if any. This does not copy the file pointers. Called with the files + * spinlock held for write. + */ +-static void copy_fd_bitmaps(struct fdtable *nfdt, struct fdtable *ofdt, +- unsigned int count) ++static inline void copy_fd_bitmaps(struct fdtable *nfdt, struct fdtable *ofdt, ++ unsigned int copy_words) + { +- unsigned int cpy, set; ++ unsigned int nwords = fdt_words(nfdt); + +- cpy = count / BITS_PER_BYTE; +- set = (nfdt->max_fds - count) / BITS_PER_BYTE; +- memcpy(nfdt->open_fds, ofdt->open_fds, cpy); +- memset((char *)nfdt->open_fds + cpy, 0, set); +- memcpy(nfdt->close_on_exec, ofdt->close_on_exec, cpy); +- memset((char *)nfdt->close_on_exec + cpy, 0, set); +- +- cpy = BITBIT_SIZE(count); +- set = BITBIT_SIZE(nfdt->max_fds) - cpy; +- memcpy(nfdt->full_fds_bits, ofdt->full_fds_bits, cpy); +- memset((char *)nfdt->full_fds_bits + cpy, 0, set); ++ bitmap_copy_and_extend(nfdt->open_fds, ofdt->open_fds, ++ copy_words * BITS_PER_LONG, nwords * BITS_PER_LONG); ++ bitmap_copy_and_extend(nfdt->close_on_exec, ofdt->close_on_exec, ++ copy_words * BITS_PER_LONG, nwords * BITS_PER_LONG); ++ bitmap_copy_and_extend(nfdt->full_fds_bits, ofdt->full_fds_bits, ++ copy_words, nwords); + } + + /* +@@ -84,7 +80,7 @@ static void copy_fdtable(struct fdtable *nfdt, struct fdtable *ofdt) + memcpy(nfdt->fd, ofdt->fd, cpy); + memset((char *)nfdt->fd + cpy, 0, set); + +- copy_fd_bitmaps(nfdt, ofdt, ofdt->max_fds); ++ copy_fd_bitmaps(nfdt, ofdt, fdt_words(ofdt)); + } + + /* +@@ -379,7 +375,7 @@ struct files_struct *dup_fd(struct files_struct *oldf, unsigned int max_fds, int + open_files = sane_fdtable_size(old_fdt, max_fds); + } + +- copy_fd_bitmaps(new_fdt, old_fdt, open_files); ++ copy_fd_bitmaps(new_fdt, old_fdt, open_files / BITS_PER_LONG); + + old_fds = old_fdt->fd; + new_fds = new_fdt->fd; +diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h +index 8c4768c44a01..d3b66d77df7a 100644 +--- a/include/linux/bitmap.h ++++ b/include/linux/bitmap.h +@@ -270,6 +270,18 @@ static inline void bitmap_copy_clear_tail(unsigned long *dst, + dst[nbits / BITS_PER_LONG] &= BITMAP_LAST_WORD_MASK(nbits); + } + ++static inline void bitmap_copy_and_extend(unsigned long *to, ++ const unsigned long *from, ++ unsigned int count, unsigned int size) ++{ ++ unsigned int copy = BITS_TO_LONGS(count); ++ ++ memcpy(to, from, copy * sizeof(long)); ++ if (count % BITS_PER_LONG) ++ to[copy - 1] &= BITMAP_LAST_WORD_MASK(count); ++ memset(to + copy, 0, bitmap_size(size) - copy * sizeof(long)); ++} ++ + /* + * On 32-bit systems bitmaps are represented as u32 arrays internally. On LE64 + * machines the order of hi and lo parts of numbers match the bitmap structure. +diff --git a/tools/testing/selftests/core/close_range_test.c b/tools/testing/selftests/core/close_range_test.c +index 991c473e3859..12b4eb9d0434 100644 +--- a/tools/testing/selftests/core/close_range_test.c ++++ b/tools/testing/selftests/core/close_range_test.c +@@ -589,4 +589,39 @@ TEST(close_range_cloexec_unshare_syzbot) + EXPECT_EQ(close(fd3), 0); + } + ++TEST(close_range_bitmap_corruption) ++{ ++ pid_t pid; ++ int status; ++ struct __clone_args args = { ++ .flags = CLONE_FILES, ++ .exit_signal = SIGCHLD, ++ }; ++ ++ /* get the first 128 descriptors open */ ++ for (int i = 2; i < 128; i++) ++ EXPECT_GE(dup2(0, i), 0); ++ ++ /* get descriptor table shared */ ++ pid = sys_clone3(&args, sizeof(args)); ++ ASSERT_GE(pid, 0); ++ ++ if (pid == 0) { ++ /* unshare and truncate descriptor table down to 64 */ ++ if (sys_close_range(64, ~0U, CLOSE_RANGE_UNSHARE)) ++ exit(EXIT_FAILURE); ++ ++ ASSERT_EQ(fcntl(64, F_GETFD), -1); ++ /* ... and verify that the range 64..127 is not ++ stuck "fully used" according to secondary bitmap */ ++ EXPECT_EQ(dup(0), 64) ++ exit(EXIT_FAILURE); ++ exit(EXIT_SUCCESS); ++ } ++ ++ EXPECT_EQ(waitpid(pid, &status, 0), pid); ++ EXPECT_EQ(true, WIFEXITED(status)); ++ EXPECT_EQ(0, WEXITSTATUS(status)); ++} ++ + TEST_HARNESS_MAIN +-- +2.46.0 + diff --git a/queue-4.19/series b/queue-4.19/series index e834c81ba8e..6803eea792c 100644 --- a/queue-4.19/series +++ b/queue-4.19/series @@ -1 +1,7 @@ fuse-initialize-beyond-eof-page-contents-before-setting-uptodate.patch +alsa-usb-audio-support-yamaha-p-125-quirk-entry.patch +xhci-fix-panther-point-null-pointer-deref-at-full-speed-re-enumeration.patch +arm64-acpi-numa-initialize-all-values-of-acpi_early_node_map-to-numa_no_node.patch +dm-resume-don-t-return-einval-when-signalled.patch +dm-persistent-data-fix-memory-allocation-failure.patch +fix-bitmap-corruption-on-close_range-with-close_range_unshare.patch diff --git a/queue-4.19/xhci-fix-panther-point-null-pointer-deref-at-full-speed-re-enumeration.patch b/queue-4.19/xhci-fix-panther-point-null-pointer-deref-at-full-speed-re-enumeration.patch new file mode 100644 index 00000000000..64e13f0e1a6 --- /dev/null +++ b/queue-4.19/xhci-fix-panther-point-null-pointer-deref-at-full-speed-re-enumeration.patch @@ -0,0 +1,82 @@ +From af8e119f52e9c13e556be9e03f27957554a84656 Mon Sep 17 00:00:00 2001 +From: Mathias Nyman +Date: Thu, 15 Aug 2024 17:11:17 +0300 +Subject: xhci: Fix Panther point NULL pointer deref at full-speed re-enumeration + +From: Mathias Nyman + +commit af8e119f52e9c13e556be9e03f27957554a84656 upstream. + +re-enumerating full-speed devices after a failed address device command +can trigger a NULL pointer dereference. + +Full-speed devices may need to reconfigure the endpoint 0 Max Packet Size +value during enumeration. Usb core calls usb_ep0_reinit() in this case, +which ends up calling xhci_configure_endpoint(). + +On Panther point xHC the xhci_configure_endpoint() function will +additionally check and reserve bandwidth in software. Other hosts do +this in hardware + +If xHC address device command fails then a new xhci_virt_device structure +is allocated as part of re-enabling the slot, but the bandwidth table +pointers are not set up properly here. +This triggers the NULL pointer dereference the next time usb_ep0_reinit() +is called and xhci_configure_endpoint() tries to check and reserve +bandwidth + +[46710.713538] usb 3-1: new full-speed USB device number 5 using xhci_hcd +[46710.713699] usb 3-1: Device not responding to setup address. +[46710.917684] usb 3-1: Device not responding to setup address. +[46711.125536] usb 3-1: device not accepting address 5, error -71 +[46711.125594] BUG: kernel NULL pointer dereference, address: 0000000000000008 +[46711.125600] #PF: supervisor read access in kernel mode +[46711.125603] #PF: error_code(0x0000) - not-present page +[46711.125606] PGD 0 P4D 0 +[46711.125610] Oops: Oops: 0000 [#1] PREEMPT SMP PTI +[46711.125615] CPU: 1 PID: 25760 Comm: kworker/1:2 Not tainted 6.10.3_2 #1 +[46711.125620] Hardware name: Gigabyte Technology Co., Ltd. +[46711.125623] Workqueue: usb_hub_wq hub_event [usbcore] +[46711.125668] RIP: 0010:xhci_reserve_bandwidth (drivers/usb/host/xhci.c + +Fix this by making sure bandwidth table pointers are set up correctly +after a failed address device command, and additionally by avoiding +checking for bandwidth in cases like this where no actual endpoints are +added or removed, i.e. only context for default control endpoint 0 is +evaluated. + +Reported-by: Karel Balej +Closes: https://lore.kernel.org/linux-usb/D3CKQQAETH47.1MUO22RTCH2O3@matfyz.cz/ +Cc: stable@vger.kernel.org +Fixes: 651aaf36a7d7 ("usb: xhci: Handle USB transaction error on address command") +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20240815141117.2702314-2-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/host/xhci.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -2790,7 +2790,7 @@ static int xhci_configure_endpoint(struc + xhci->num_active_eps); + return -ENOMEM; + } +- if ((xhci->quirks & XHCI_SW_BW_CHECKING) && ++ if ((xhci->quirks & XHCI_SW_BW_CHECKING) && !ctx_change && + xhci_reserve_bandwidth(xhci, virt_dev, command->in_ctx)) { + if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK)) + xhci_free_host_resources(xhci, ctrl_ctx); +@@ -4145,8 +4145,10 @@ static int xhci_setup_device(struct usb_ + mutex_unlock(&xhci->mutex); + ret = xhci_disable_slot(xhci, udev->slot_id); + xhci_free_virt_device(xhci, udev->slot_id); +- if (!ret) +- xhci_alloc_dev(hcd, udev); ++ if (!ret) { ++ if (xhci_alloc_dev(hcd, udev) == 1) ++ xhci_setup_addressable_virt_dev(xhci, udev); ++ } + kfree(command->completion); + kfree(command); + return -EPROTO;