From: Greg Kroah-Hartman Date: Thu, 19 Oct 2017 13:26:48 +0000 (+0200) Subject: 3.18-stable patches X-Git-Tag: v3.18.77~5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=955ecace348c3000f5a06b94a34cf11e39474479;p=thirdparty%2Fkernel%2Fstable-queue.git 3.18-stable patches added patches: btrfs-send-fix-failure-to-rename-top-level-inode-due-to-name-collision.patch crypto-xts-add-ecb-dependency.patch iio-adc-xilinx-fix-error-handling.patch irqchip-crossbar-fix-incorrect-type-of-local-variables.patch locking-lockdep-add-nest_lock-integrity-test.patch net-mlx4_core-fix-vf-overwrite-of-module-param-which-disables-dmfs-on-new-probed-pfs.patch netfilter-nf_ct_expect-change-__nf_ct_expect_check-return-value.patch ocfs2-dlmglue-prepare-tracking-logic-to-avoid-recursive-cluster-lock.patch scsi-scsi_dh_emc-return-success-in-clariion_std_inquiry.patch target-iscsi-fix-unsolicited-data-seq_end_offset-calculation.patch uapi-fix-linux-mroute6.h-userspace-compilation-errors.patch uapi-fix-linux-rds.h-userspace-compilation-errors.patch watchdog-kempld-fix-gcc-4.3-build.patch --- diff --git a/queue-3.18/btrfs-send-fix-failure-to-rename-top-level-inode-due-to-name-collision.patch b/queue-3.18/btrfs-send-fix-failure-to-rename-top-level-inode-due-to-name-collision.patch new file mode 100644 index 00000000000..88b41fe6caa --- /dev/null +++ b/queue-3.18/btrfs-send-fix-failure-to-rename-top-level-inode-due-to-name-collision.patch @@ -0,0 +1,130 @@ +From foo@baz Thu Oct 19 15:22:10 CEST 2017 +From: Robbie Ko +Date: Thu, 5 Jan 2017 16:24:55 +0800 +Subject: Btrfs: send, fix failure to rename top level inode due to name collision + +From: Robbie Ko + + +[ Upstream commit 4dd9920d991745c4a16f53a8f615f706fbe4b3f7 ] + +Under certain situations, an incremental send operation can fail due to a +premature attempt to create a new top level inode (a direct child of the +subvolume/snapshot root) whose name collides with another inode that was +removed from the send snapshot. + +Consider the following example scenario. + +Parent snapshot: + + . (ino 256, gen 8) + |---- a1/ (ino 257, gen 9) + |---- a2/ (ino 258, gen 9) + +Send snapshot: + + . (ino 256, gen 3) + |---- a2/ (ino 257, gen 7) + +In this scenario, when receiving the incremental send stream, the btrfs +receive command fails like this (ran in verbose mode, -vv argument): + + rmdir a1 + mkfile o257-7-0 + rename o257-7-0 -> a2 + ERROR: rename o257-7-0 -> a2 failed: Is a directory + +What happens when computing the incremental send stream is: + +1) An operation to remove the directory with inode number 257 and + generation 9 is issued. + +2) An operation to create the inode with number 257 and generation 7 is + issued. This creates the inode with an orphanized name of "o257-7-0". + +3) An operation rename the new inode 257 to its final name, "a2", is + issued. This is incorrect because inode 258, which has the same name + and it's a child of the same parent (root inode 256), was not yet + processed and therefore no rmdir operation for it was yet issued. + The rename operation is issued because we fail to detect that the + name of the new inode 257 collides with inode 258, because their + parent, a subvolume/snapshot root (inode 256) has a different + generation in both snapshots. + +So fix this by ignoring the generation value of a parent directory that +matches a root inode (number 256) when we are checking if the name of the +inode currently being processed collides with the name of some other +inode that was not yet processed. + +We can achieve this scenario of different inodes with the same number but +different generation values either by mounting a filesystem with the inode +cache option (-o inode_cache) or by creating and sending snapshots across +different filesystems, like in the following example: + + $ mkfs.btrfs -f /dev/sdb + $ mount /dev/sdb /mnt + $ mkdir /mnt/a1 + $ mkdir /mnt/a2 + $ btrfs subvolume snapshot -r /mnt /mnt/snap1 + $ btrfs send /mnt/snap1 -f /tmp/1.snap + $ umount /mnt + + $ mkfs.btrfs -f /dev/sdc + $ mount /dev/sdc /mnt + $ touch /mnt/a2 + $ btrfs subvolume snapshot -r /mnt /mnt/snap2 + $ btrfs receive /mnt -f /tmp/1.snap + # Take note that once the filesystem is created, its current + # generation has value 7 so the inode from the second snapshot has + # a generation value of 7. And after receiving the first snapshot + # the filesystem is at a generation value of 10, because the call to + # create the second snapshot bumps the generation to 8 (the snapshot + # creation ioctl does a transaction commit), the receive command calls + # the snapshot creation ioctl to create the first snapshot, which bumps + # the filesystem's generation to 9, and finally when the receive + # operation finishes it calls an ioctl to transition the first snapshot + # (snap1) from RW mode to RO mode, which does another transaction commit + # and bumps the filesystem's generation to 10. + $ rm -f /tmp/1.snap + $ btrfs send /mnt/snap1 -f /tmp/1.snap + $ btrfs send -p /mnt/snap1 /mnt/snap2 -f /tmp/2.snap + $ umount /mnt + + $ mkfs.btrfs -f /dev/sdd + $ mount /dev/sdd /mnt + $ btrfs receive /mnt /tmp/1.snap + # Receive of snapshot snap2 used to fail. + $ btrfs receive /mnt /tmp/2.snap + +Signed-off-by: Robbie Ko +Reviewed-by: Filipe Manana +[Rewrote changelog to be more precise and clear] +Signed-off-by: Filipe Manana + +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/send.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/fs/btrfs/send.c ++++ b/fs/btrfs/send.c +@@ -1640,6 +1640,9 @@ static int is_inode_existent(struct send + { + int ret; + ++ if (ino == BTRFS_FIRST_FREE_OBJECTID) ++ return 1; ++ + ret = get_cur_inode_state(sctx, ino, gen); + if (ret < 0) + goto out; +@@ -1825,7 +1828,7 @@ static int will_overwrite_ref(struct sen + * not delted and then re-created, if it was then we have no overwrite + * and we can just unlink this entry. + */ +- if (sctx->parent_root) { ++ if (sctx->parent_root && dir != BTRFS_FIRST_FREE_OBJECTID) { + ret = get_inode_info(sctx->parent_root, dir, NULL, &gen, NULL, + NULL, NULL, NULL); + if (ret < 0 && ret != -ENOENT) diff --git a/queue-3.18/crypto-xts-add-ecb-dependency.patch b/queue-3.18/crypto-xts-add-ecb-dependency.patch new file mode 100644 index 00000000000..176607b8a35 --- /dev/null +++ b/queue-3.18/crypto-xts-add-ecb-dependency.patch @@ -0,0 +1,34 @@ +From foo@baz Thu Oct 19 15:22:10 CEST 2017 +From: Milan Broz +Date: Thu, 23 Feb 2017 08:38:26 +0100 +Subject: crypto: xts - Add ECB dependency + +From: Milan Broz + + +[ Upstream commit 12cb3a1c4184f891d965d1f39f8cfcc9ef617647 ] + +Since the + commit f1c131b45410a202eb45cc55980a7a9e4e4b4f40 + crypto: xts - Convert to skcipher +the XTS mode is based on ECB, so the mode must select +ECB otherwise it can fail to initialize. + +Signed-off-by: Milan Broz +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + crypto/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -290,6 +290,7 @@ config CRYPTO_XTS + select CRYPTO_BLKCIPHER + select CRYPTO_MANAGER + select CRYPTO_GF128MUL ++ select CRYPTO_ECB + help + XTS: IEEE1619/D16 narrow block cipher use with aes-xts-plain, + key size 256, 384 or 512 bits. This implementation currently diff --git a/queue-3.18/iio-adc-xilinx-fix-error-handling.patch b/queue-3.18/iio-adc-xilinx-fix-error-handling.patch new file mode 100644 index 00000000000..da46c9512d6 --- /dev/null +++ b/queue-3.18/iio-adc-xilinx-fix-error-handling.patch @@ -0,0 +1,51 @@ +From foo@baz Thu Oct 19 15:22:10 CEST 2017 +From: Christophe JAILLET +Date: Tue, 21 Feb 2017 07:34:00 +0100 +Subject: iio: adc: xilinx: Fix error handling + +From: Christophe JAILLET + + +[ Upstream commit ca1c39ef76376b67303d01f94fe98bb68bb3861a ] + +Reorder error handling labels in order to match the way resources have +been allocated. + +Signed-off-by: Christophe JAILLET +Acked-by: Lars-Peter Clausen +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/iio/adc/xilinx-xadc-core.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/iio/adc/xilinx-xadc-core.c ++++ b/drivers/iio/adc/xilinx-xadc-core.c +@@ -1223,7 +1223,7 @@ static int xadc_probe(struct platform_de + + ret = xadc->ops->setup(pdev, indio_dev, irq); + if (ret) +- goto err_free_samplerate_trigger; ++ goto err_clk_disable_unprepare; + + ret = request_threaded_irq(irq, xadc->ops->interrupt_handler, + xadc->ops->threaded_interrupt_handler, +@@ -1284,6 +1284,8 @@ static int xadc_probe(struct platform_de + + err_free_irq: + free_irq(irq, indio_dev); ++err_clk_disable_unprepare: ++ clk_disable_unprepare(xadc->clk); + err_free_samplerate_trigger: + if (xadc->ops->flags & XADC_FLAGS_BUFFERED) + iio_trigger_free(xadc->samplerate_trigger); +@@ -1293,8 +1295,6 @@ err_free_convst_trigger: + err_triggered_buffer_cleanup: + if (xadc->ops->flags & XADC_FLAGS_BUFFERED) + iio_triggered_buffer_cleanup(indio_dev); +-err_clk_disable_unprepare: +- clk_disable_unprepare(xadc->clk); + err_device_free: + kfree(indio_dev->channels); + diff --git a/queue-3.18/irqchip-crossbar-fix-incorrect-type-of-local-variables.patch b/queue-3.18/irqchip-crossbar-fix-incorrect-type-of-local-variables.patch new file mode 100644 index 00000000000..9a0b833ffe5 --- /dev/null +++ b/queue-3.18/irqchip-crossbar-fix-incorrect-type-of-local-variables.patch @@ -0,0 +1,48 @@ +From foo@baz Thu Oct 19 15:22:10 CEST 2017 +From: Franck Demathieu +Date: Thu, 23 Feb 2017 10:48:55 +0100 +Subject: irqchip/crossbar: Fix incorrect type of local variables + +From: Franck Demathieu + + +[ Upstream commit b28ace12661fbcfd90959c1e84ff5a85113a82a1 ] + +The max and entry variables are unsigned according to the dt-bindings. +Fix following 3 sparse issues (-Wtypesign): + + drivers/irqchip/irq-crossbar.c:222:52: warning: incorrect type in argument 3 (different signedness) + drivers/irqchip/irq-crossbar.c:222:52: expected unsigned int [usertype] *out_value + drivers/irqchip/irq-crossbar.c:222:52: got int * + + drivers/irqchip/irq-crossbar.c:245:56: warning: incorrect type in argument 4 (different signedness) + drivers/irqchip/irq-crossbar.c:245:56: expected unsigned int [usertype] *out_value + drivers/irqchip/irq-crossbar.c:245:56: got int * + + drivers/irqchip/irq-crossbar.c:263:56: warning: incorrect type in argument 4 (different signedness) + drivers/irqchip/irq-crossbar.c:263:56: expected unsigned int [usertype] *out_value + drivers/irqchip/irq-crossbar.c:263:56: got int * + +Signed-off-by: Franck Demathieu +Cc: marc.zyngier@arm.com +Cc: jason@lakedaemon.net +Link: http://lkml.kernel.org/r/20170223094855.6546-1-fdemathieu@gmail.com +Signed-off-by: Thomas Gleixner +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/irqchip/irq-crossbar.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/irqchip/irq-crossbar.c ++++ b/drivers/irqchip/irq-crossbar.c +@@ -175,7 +175,8 @@ static const struct irq_domain_ops routa + + static int __init crossbar_of_init(struct device_node *node) + { +- int i, size, max = 0, reserved = 0, entry; ++ int i, size, reserved = 0; ++ u32 max = 0, entry; + const __be32 *irqsr; + int ret = -ENOMEM; + diff --git a/queue-3.18/locking-lockdep-add-nest_lock-integrity-test.patch b/queue-3.18/locking-lockdep-add-nest_lock-integrity-test.patch new file mode 100644 index 00000000000..d282338f86f --- /dev/null +++ b/queue-3.18/locking-lockdep-add-nest_lock-integrity-test.patch @@ -0,0 +1,55 @@ +From foo@baz Thu Oct 19 15:22:10 CEST 2017 +From: Peter Zijlstra +Date: Wed, 1 Mar 2017 16:23:30 +0100 +Subject: locking/lockdep: Add nest_lock integrity test + +From: Peter Zijlstra + + +[ Upstream commit 7fb4a2cea6b18dab56d609530d077f168169ed6b ] + +Boqun reported that hlock->references can overflow. Add a debug test +for that to generate a clear error when this happens. + +Without this, lockdep is likely to report a mysterious failure on +unlock. + +Reported-by: Boqun Feng +Signed-off-by: Peter Zijlstra (Intel) +Cc: Andrew Morton +Cc: Chris Wilson +Cc: Linus Torvalds +Cc: Nicolai Hähnle +Cc: Paul E. McKenney +Cc: Peter Zijlstra +Cc: Thomas Gleixner +Cc: linux-kernel@vger.kernel.org +Signed-off-by: Ingo Molnar +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + kernel/locking/lockdep.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/kernel/locking/lockdep.c ++++ b/kernel/locking/lockdep.c +@@ -3107,10 +3107,17 @@ static int __lock_acquire(struct lockdep + if (depth) { + hlock = curr->held_locks + depth - 1; + if (hlock->class_idx == class_idx && nest_lock) { +- if (hlock->references) ++ if (hlock->references) { ++ /* ++ * Check: unsigned int references:12, overflow. ++ */ ++ if (DEBUG_LOCKS_WARN_ON(hlock->references == (1 << 12)-1)) ++ return 0; ++ + hlock->references++; +- else ++ } else { + hlock->references = 2; ++ } + + return 1; + } diff --git a/queue-3.18/net-mlx4_core-fix-vf-overwrite-of-module-param-which-disables-dmfs-on-new-probed-pfs.patch b/queue-3.18/net-mlx4_core-fix-vf-overwrite-of-module-param-which-disables-dmfs-on-new-probed-pfs.patch new file mode 100644 index 00000000000..7ba13b5e616 --- /dev/null +++ b/queue-3.18/net-mlx4_core-fix-vf-overwrite-of-module-param-which-disables-dmfs-on-new-probed-pfs.patch @@ -0,0 +1,42 @@ +From foo@baz Thu Oct 19 15:22:10 CEST 2017 +From: Majd Dibbiny +Date: Thu, 23 Feb 2017 12:02:43 +0200 +Subject: net/mlx4_core: Fix VF overwrite of module param which disables DMFS on new probed PFs + +From: Majd Dibbiny + + +[ Upstream commit 95f1ba9a24af9769f6e20dfe9a77c863f253f311 ] + +In the VF driver, module parameter mlx4_log_num_mgm_entry_size was +mistakenly overwritten -- and in a manner which overrode the +device-managed flow steering option encoded in the parameter. + +log_num_mgm_entry_size is a global module parameter which +affects all ConnectX-3 PFs installed on that host. +If a VF changes log_num_mgm_entry_size, this will affect all PFs +which are probed subsequent to the change (by disabling DMFS for +those PFs). + +Fixes: 3c439b5586e9 ("mlx4_core: Allow choosing flow steering mode") +Signed-off-by: Majd Dibbiny +Reviewed-by: Jack Morgenstein +Signed-off-by: Tariq Toukan +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/mellanox/mlx4/main.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/drivers/net/ethernet/mellanox/mlx4/main.c ++++ b/drivers/net/ethernet/mellanox/mlx4/main.c +@@ -648,8 +648,6 @@ static int mlx4_slave_cap(struct mlx4_de + return -ENOSYS; + } + +- mlx4_log_num_mgm_entry_size = hca_param.log_mc_entry_sz; +- + dev->caps.hca_core_clock = hca_param.hca_core_clock; + + memset(&dev_cap, 0, sizeof(dev_cap)); diff --git a/queue-3.18/netfilter-nf_ct_expect-change-__nf_ct_expect_check-return-value.patch b/queue-3.18/netfilter-nf_ct_expect-change-__nf_ct_expect_check-return-value.patch new file mode 100644 index 00000000000..44881309c8f --- /dev/null +++ b/queue-3.18/netfilter-nf_ct_expect-change-__nf_ct_expect_check-return-value.patch @@ -0,0 +1,46 @@ +From foo@baz Thu Oct 19 15:22:10 CEST 2017 +From: Jarno Rajahalme +Date: Thu, 23 Feb 2017 17:08:54 -0800 +Subject: netfilter: nf_ct_expect: Change __nf_ct_expect_check() return value. + +From: Jarno Rajahalme + + +[ Upstream commit 4b86c459c7bee3acaf92f0e2b4c6ac803eaa1a58 ] + +Commit 4dee62b1b9b4 ("netfilter: nf_ct_expect: nf_ct_expect_insert() +returns void") inadvertently changed the successful return value of +nf_ct_expect_related_report() from 0 to 1 due to +__nf_ct_expect_check() returning 1 on success. Prevent this +regression in the future by changing the return value of +__nf_ct_expect_check() to 0 on success. + +Signed-off-by: Jarno Rajahalme +Acked-by: Joe Stringer +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/netfilter/nf_conntrack_expect.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/netfilter/nf_conntrack_expect.c ++++ b/net/netfilter/nf_conntrack_expect.c +@@ -392,7 +392,7 @@ static inline int __nf_ct_expect_check(s + struct net *net = nf_ct_exp_net(expect); + struct hlist_node *next; + unsigned int h; +- int ret = 1; ++ int ret = 0; + + if (!master_help) { + ret = -ESHUTDOWN; +@@ -442,7 +442,7 @@ int nf_ct_expect_related_report(struct n + + spin_lock_bh(&nf_conntrack_expect_lock); + ret = __nf_ct_expect_check(expect); +- if (ret <= 0) ++ if (ret < 0) + goto out; + + ret = nf_ct_expect_insert(expect); diff --git a/queue-3.18/ocfs2-dlmglue-prepare-tracking-logic-to-avoid-recursive-cluster-lock.patch b/queue-3.18/ocfs2-dlmglue-prepare-tracking-logic-to-avoid-recursive-cluster-lock.patch new file mode 100644 index 00000000000..abe5c7b1444 --- /dev/null +++ b/queue-3.18/ocfs2-dlmglue-prepare-tracking-logic-to-avoid-recursive-cluster-lock.patch @@ -0,0 +1,282 @@ +From foo@baz Thu Oct 19 15:22:10 CEST 2017 +From: Eric Ren +Date: Wed, 22 Feb 2017 15:40:41 -0800 +Subject: ocfs2/dlmglue: prepare tracking logic to avoid recursive cluster lock + +From: Eric Ren + + +[ Upstream commit 439a36b8ef38657f765b80b775e2885338d72451 ] + +We are in the situation that we have to avoid recursive cluster locking, +but there is no way to check if a cluster lock has been taken by a precess +already. + +Mostly, we can avoid recursive locking by writing code carefully. +However, we found that it's very hard to handle the routines that are +invoked directly by vfs code. For instance: + + const struct inode_operations ocfs2_file_iops = { + .permission = ocfs2_permission, + .get_acl = ocfs2_iop_get_acl, + .set_acl = ocfs2_iop_set_acl, + }; + +Both ocfs2_permission() and ocfs2_iop_get_acl() call ocfs2_inode_lock(PR): + + do_sys_open + may_open + inode_permission + ocfs2_permission + ocfs2_inode_lock() <=== first time + generic_permission + get_acl + ocfs2_iop_get_acl + ocfs2_inode_lock() <=== recursive one + +A deadlock will occur if a remote EX request comes in between two of +ocfs2_inode_lock(). Briefly describe how the deadlock is formed: + +On one hand, OCFS2_LOCK_BLOCKED flag of this lockres is set in +BAST(ocfs2_generic_handle_bast) when downconvert is started on behalf of +the remote EX lock request. Another hand, the recursive cluster lock +(the second one) will be blocked in in __ocfs2_cluster_lock() because of +OCFS2_LOCK_BLOCKED. But, the downconvert never complete, why? because +there is no chance for the first cluster lock on this node to be +unlocked - we block ourselves in the code path. + +The idea to fix this issue is mostly taken from gfs2 code. + +1. introduce a new field: struct ocfs2_lock_res.l_holders, to keep track + of the processes' pid who has taken the cluster lock of this lock + resource; + +2. introduce a new flag for ocfs2_inode_lock_full: + OCFS2_META_LOCK_GETBH; it means just getting back disk inode bh for + us if we've got cluster lock. + +3. export a helper: ocfs2_is_locked_by_me() is used to check if we have + got the cluster lock in the upper code path. + +The tracking logic should be used by some of the ocfs2 vfs's callbacks, +to solve the recursive locking issue cuased by the fact that vfs +routines can call into each other. + +The performance penalty of processing the holder list should only be +seen at a few cases where the tracking logic is used, such as get/set +acl. + +You may ask what if the first time we got a PR lock, and the second time +we want a EX lock? fortunately, this case never happens in the real +world, as far as I can see, including permission check, +(get|set)_(acl|attr), and the gfs2 code also do so. + +[sfr@canb.auug.org.au remove some inlines] +Link: http://lkml.kernel.org/r/20170117100948.11657-2-zren@suse.com +Signed-off-by: Eric Ren +Reviewed-by: Junxiao Bi +Reviewed-by: Joseph Qi +Cc: Stephen Rothwell +Cc: Mark Fasheh +Cc: Joel Becker +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/ocfs2/dlmglue.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++-- + fs/ocfs2/dlmglue.h | 18 +++++++++ + fs/ocfs2/ocfs2.h | 1 + 3 files changed, 121 insertions(+), 3 deletions(-) + +--- a/fs/ocfs2/dlmglue.c ++++ b/fs/ocfs2/dlmglue.c +@@ -531,6 +531,7 @@ void ocfs2_lock_res_init_once(struct ocf + init_waitqueue_head(&res->l_event); + INIT_LIST_HEAD(&res->l_blocked_list); + INIT_LIST_HEAD(&res->l_mask_waiters); ++ INIT_LIST_HEAD(&res->l_holders); + } + + void ocfs2_inode_lock_res_init(struct ocfs2_lock_res *res, +@@ -748,6 +749,50 @@ void ocfs2_lock_res_free(struct ocfs2_lo + res->l_flags = 0UL; + } + ++/* ++ * Keep a list of processes who have interest in a lockres. ++ * Note: this is now only uesed for check recursive cluster locking. ++ */ ++static inline void ocfs2_add_holder(struct ocfs2_lock_res *lockres, ++ struct ocfs2_lock_holder *oh) ++{ ++ INIT_LIST_HEAD(&oh->oh_list); ++ oh->oh_owner_pid = get_pid(task_pid(current)); ++ ++ spin_lock(&lockres->l_lock); ++ list_add_tail(&oh->oh_list, &lockres->l_holders); ++ spin_unlock(&lockres->l_lock); ++} ++ ++static inline void ocfs2_remove_holder(struct ocfs2_lock_res *lockres, ++ struct ocfs2_lock_holder *oh) ++{ ++ spin_lock(&lockres->l_lock); ++ list_del(&oh->oh_list); ++ spin_unlock(&lockres->l_lock); ++ ++ put_pid(oh->oh_owner_pid); ++} ++ ++static inline int ocfs2_is_locked_by_me(struct ocfs2_lock_res *lockres) ++{ ++ struct ocfs2_lock_holder *oh; ++ struct pid *pid; ++ ++ /* look in the list of holders for one with the current task as owner */ ++ spin_lock(&lockres->l_lock); ++ pid = task_pid(current); ++ list_for_each_entry(oh, &lockres->l_holders, oh_list) { ++ if (oh->oh_owner_pid == pid) { ++ spin_unlock(&lockres->l_lock); ++ return 1; ++ } ++ } ++ spin_unlock(&lockres->l_lock); ++ ++ return 0; ++} ++ + static inline void ocfs2_inc_holders(struct ocfs2_lock_res *lockres, + int level) + { +@@ -2313,8 +2358,9 @@ int ocfs2_inode_lock_full_nested(struct + goto getbh; + } + +- if (ocfs2_mount_local(osb)) +- goto local; ++ if ((arg_flags & OCFS2_META_LOCK_GETBH) || ++ ocfs2_mount_local(osb)) ++ goto update; + + if (!(arg_flags & OCFS2_META_LOCK_RECOVERY)) + ocfs2_wait_for_recovery(osb); +@@ -2343,7 +2389,7 @@ int ocfs2_inode_lock_full_nested(struct + if (!(arg_flags & OCFS2_META_LOCK_RECOVERY)) + ocfs2_wait_for_recovery(osb); + +-local: ++update: + /* + * We only see this flag if we're being called from + * ocfs2_read_locked_inode(). It means we're locking an inode +@@ -2485,6 +2531,59 @@ void ocfs2_inode_unlock(struct inode *in + ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level); + } + ++/* ++ * This _tracker variantes are introduced to deal with the recursive cluster ++ * locking issue. The idea is to keep track of a lock holder on the stack of ++ * the current process. If there's a lock holder on the stack, we know the ++ * task context is already protected by cluster locking. Currently, they're ++ * used in some VFS entry routines. ++ * ++ * return < 0 on error, return == 0 if there's no lock holder on the stack ++ * before this call, return == 1 if this call would be a recursive locking. ++ */ ++int ocfs2_inode_lock_tracker(struct inode *inode, ++ struct buffer_head **ret_bh, ++ int ex, ++ struct ocfs2_lock_holder *oh) ++{ ++ int status; ++ int arg_flags = 0, has_locked; ++ struct ocfs2_lock_res *lockres; ++ ++ lockres = &OCFS2_I(inode)->ip_inode_lockres; ++ has_locked = ocfs2_is_locked_by_me(lockres); ++ /* Just get buffer head if the cluster lock has been taken */ ++ if (has_locked) ++ arg_flags = OCFS2_META_LOCK_GETBH; ++ ++ if (likely(!has_locked || ret_bh)) { ++ status = ocfs2_inode_lock_full(inode, ret_bh, ex, arg_flags); ++ if (status < 0) { ++ if (status != -ENOENT) ++ mlog_errno(status); ++ return status; ++ } ++ } ++ if (!has_locked) ++ ocfs2_add_holder(lockres, oh); ++ ++ return has_locked; ++} ++ ++void ocfs2_inode_unlock_tracker(struct inode *inode, ++ int ex, ++ struct ocfs2_lock_holder *oh, ++ int had_lock) ++{ ++ struct ocfs2_lock_res *lockres; ++ ++ lockres = &OCFS2_I(inode)->ip_inode_lockres; ++ if (!had_lock) { ++ ocfs2_remove_holder(lockres, oh); ++ ocfs2_inode_unlock(inode, ex); ++ } ++} ++ + int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno) + { + struct ocfs2_lock_res *lockres; +--- a/fs/ocfs2/dlmglue.h ++++ b/fs/ocfs2/dlmglue.h +@@ -70,6 +70,11 @@ struct ocfs2_orphan_scan_lvb { + __be32 lvb_os_seqno; + }; + ++struct ocfs2_lock_holder { ++ struct list_head oh_list; ++ struct pid *oh_owner_pid; ++}; ++ + /* ocfs2_inode_lock_full() 'arg_flags' flags */ + /* don't wait on recovery. */ + #define OCFS2_META_LOCK_RECOVERY (0x01) +@@ -77,6 +82,8 @@ struct ocfs2_orphan_scan_lvb { + #define OCFS2_META_LOCK_NOQUEUE (0x02) + /* don't block waiting for the downconvert thread, instead return -EAGAIN */ + #define OCFS2_LOCK_NONBLOCK (0x04) ++/* just get back disk inode bh if we've got cluster lock. */ ++#define OCFS2_META_LOCK_GETBH (0x08) + + /* Locking subclasses of inode cluster lock */ + enum { +@@ -170,4 +177,15 @@ void ocfs2_put_dlm_debug(struct ocfs2_dl + + /* To set the locking protocol on module initialization */ + void ocfs2_set_locking_protocol(void); ++ ++/* The _tracker pair is used to avoid cluster recursive locking */ ++int ocfs2_inode_lock_tracker(struct inode *inode, ++ struct buffer_head **ret_bh, ++ int ex, ++ struct ocfs2_lock_holder *oh); ++void ocfs2_inode_unlock_tracker(struct inode *inode, ++ int ex, ++ struct ocfs2_lock_holder *oh, ++ int had_lock); ++ + #endif /* DLMGLUE_H */ +--- a/fs/ocfs2/ocfs2.h ++++ b/fs/ocfs2/ocfs2.h +@@ -166,6 +166,7 @@ struct ocfs2_lock_res { + + struct list_head l_blocked_list; + struct list_head l_mask_waiters; ++ struct list_head l_holders; + + unsigned long l_flags; + char l_name[OCFS2_LOCK_ID_MAX_LEN]; diff --git a/queue-3.18/scsi-scsi_dh_emc-return-success-in-clariion_std_inquiry.patch b/queue-3.18/scsi-scsi_dh_emc-return-success-in-clariion_std_inquiry.patch new file mode 100644 index 00000000000..81e7b181374 --- /dev/null +++ b/queue-3.18/scsi-scsi_dh_emc-return-success-in-clariion_std_inquiry.patch @@ -0,0 +1,33 @@ +From foo@baz Thu Oct 19 15:22:10 CEST 2017 +From: Dan Carpenter +Date: Tue, 21 Feb 2017 21:46:37 +0300 +Subject: scsi: scsi_dh_emc: return success in clariion_std_inquiry() + +From: Dan Carpenter + + +[ Upstream commit 4d7d39a18b8b81511f0b893b7d2203790bf8a58b ] + +We accidentally return an uninitialized variable on success. + +Fixes: b6ff1b14cdf4 ("[SCSI] scsi_dh: Update EMC handler") +Signed-off-by: Dan Carpenter +Reviewed-by: Hannes Reinecke +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/scsi/device_handler/scsi_dh_emc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/scsi/device_handler/scsi_dh_emc.c ++++ b/drivers/scsi/device_handler/scsi_dh_emc.c +@@ -464,7 +464,7 @@ static int clariion_prep_fn(struct scsi_ + static int clariion_std_inquiry(struct scsi_device *sdev, + struct clariion_dh_data *csdev) + { +- int err; ++ int err = SCSI_DH_OK; + char *sp_model; + + err = send_inquiry_cmd(sdev, 0, csdev); diff --git a/queue-3.18/series b/queue-3.18/series index 83e8df97247..5a03c0f2d49 100644 --- a/queue-3.18/series +++ b/queue-3.18/series @@ -11,3 +11,16 @@ l2tp-fix-race-condition-in-l2tp_tunnel_delete.patch packet-in-packet_do_bind-test-fanout-with-bind_lock-held.patch net-set-sk_prot_creator-when-cloning-sockets-to-the-right-proto.patch revert-bsg-lib-don-t-free-job-in-bsg_prepare_job.patch +locking-lockdep-add-nest_lock-integrity-test.patch +watchdog-kempld-fix-gcc-4.3-build.patch +irqchip-crossbar-fix-incorrect-type-of-local-variables.patch +netfilter-nf_ct_expect-change-__nf_ct_expect_check-return-value.patch +iio-adc-xilinx-fix-error-handling.patch +btrfs-send-fix-failure-to-rename-top-level-inode-due-to-name-collision.patch +net-mlx4_core-fix-vf-overwrite-of-module-param-which-disables-dmfs-on-new-probed-pfs.patch +crypto-xts-add-ecb-dependency.patch +ocfs2-dlmglue-prepare-tracking-logic-to-avoid-recursive-cluster-lock.patch +scsi-scsi_dh_emc-return-success-in-clariion_std_inquiry.patch +uapi-fix-linux-rds.h-userspace-compilation-errors.patch +uapi-fix-linux-mroute6.h-userspace-compilation-errors.patch +target-iscsi-fix-unsolicited-data-seq_end_offset-calculation.patch diff --git a/queue-3.18/target-iscsi-fix-unsolicited-data-seq_end_offset-calculation.patch b/queue-3.18/target-iscsi-fix-unsolicited-data-seq_end_offset-calculation.patch new file mode 100644 index 00000000000..8c631c08f42 --- /dev/null +++ b/queue-3.18/target-iscsi-fix-unsolicited-data-seq_end_offset-calculation.patch @@ -0,0 +1,62 @@ +From foo@baz Thu Oct 19 15:22:10 CEST 2017 +From: Varun Prakash +Date: Fri, 20 Jan 2017 16:44:33 +0530 +Subject: target/iscsi: Fix unsolicited data seq_end_offset calculation + +From: Varun Prakash + + +[ Upstream commit 4d65491c269729a1e3b375c45e73213f49103d33 ] + +In case of unsolicited data for the first sequence +seq_end_offset must be set to minimum of total data length +and FirstBurstLength, so do not add cmd->write_data_done +to the min of total data length and FirstBurstLength. + +This patch avoids that with ImmediateData=Yes, InitialR2T=No, +MaxXmitDataSegmentLength < FirstBurstLength that a WRITE command +with IO size above FirstBurstLength triggers sequence error +messages, for example + +Set following parameters on target (linux-4.8.12) +ImmediateData = Yes +InitialR2T = No +MaxXmitDataSegmentLength = 8k +FirstBurstLength = 64k + +Log in from Open iSCSI initiator and execute +dd if=/dev/zero of=/dev/sdb bs=128k count=1 oflag=direct + +Error messages on target +Command ITT: 0x00000035 with Offset: 65536, Length: 8192 outside +of Sequence 73728:131072 while DataSequenceInOrder=Yes. +Command ITT: 0x00000035, received DataSN: 0x00000001 higher than +expected 0x00000000. +Unable to perform within-command recovery while ERL=0. + +Signed-off-by: Varun Prakash +[ bvanassche: Use min() instead of open-coding it / edited patch description ] +Signed-off-by: Bart Van Assche +Signed-off-by: Nicholas Bellinger + +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/target/iscsi/iscsi_target_erl0.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +--- a/drivers/target/iscsi/iscsi_target_erl0.c ++++ b/drivers/target/iscsi/iscsi_target_erl0.c +@@ -45,10 +45,8 @@ void iscsit_set_dataout_sequence_values( + */ + if (cmd->unsolicited_data) { + cmd->seq_start_offset = cmd->write_data_done; +- cmd->seq_end_offset = (cmd->write_data_done + +- ((cmd->se_cmd.data_length > +- conn->sess->sess_ops->FirstBurstLength) ? +- conn->sess->sess_ops->FirstBurstLength : cmd->se_cmd.data_length)); ++ cmd->seq_end_offset = min(cmd->se_cmd.data_length, ++ conn->sess->sess_ops->FirstBurstLength); + return; + } + diff --git a/queue-3.18/uapi-fix-linux-mroute6.h-userspace-compilation-errors.patch b/queue-3.18/uapi-fix-linux-mroute6.h-userspace-compilation-errors.patch new file mode 100644 index 00000000000..baa632319b7 --- /dev/null +++ b/queue-3.18/uapi-fix-linux-mroute6.h-userspace-compilation-errors.patch @@ -0,0 +1,44 @@ +From foo@baz Thu Oct 19 15:22:10 CEST 2017 +From: "Dmitry V. Levin" +Date: Thu, 16 Feb 2017 18:04:29 +0300 +Subject: uapi: fix linux/mroute6.h userspace compilation errors + +From: "Dmitry V. Levin" + + +[ Upstream commit 72aa107df6a275cf03359934ca5799a2be7a1bf7 ] + +Include to fix the following linux/mroute6.h userspace +compilation errors: + +/usr/include/linux/mroute6.h:80:22: error: field 'mf6cc_origin' has incomplete type + struct sockaddr_in6 mf6cc_origin; /* Origin of mcast */ +/usr/include/linux/mroute6.h:81:22: error: field 'mf6cc_mcastgrp' has incomplete type + struct sockaddr_in6 mf6cc_mcastgrp; /* Group in question */ +/usr/include/linux/mroute6.h:91:22: error: field 'src' has incomplete type + struct sockaddr_in6 src; +/usr/include/linux/mroute6.h:92:22: error: field 'grp' has incomplete type + struct sockaddr_in6 grp; +/usr/include/linux/mroute6.h:132:18: error: field 'im6_src' has incomplete type + struct in6_addr im6_src, im6_dst; +/usr/include/linux/mroute6.h:132:27: error: field 'im6_dst' has incomplete type + struct in6_addr im6_src, im6_dst; + +Signed-off-by: Dmitry V. Levin +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/uapi/linux/mroute6.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/include/uapi/linux/mroute6.h ++++ b/include/uapi/linux/mroute6.h +@@ -3,6 +3,7 @@ + + #include + #include ++#include /* For struct sockaddr_in6. */ + + /* + * Based on the MROUTING 3.5 defines primarily to keep diff --git a/queue-3.18/uapi-fix-linux-rds.h-userspace-compilation-errors.patch b/queue-3.18/uapi-fix-linux-rds.h-userspace-compilation-errors.patch new file mode 100644 index 00000000000..88b59e3c29d --- /dev/null +++ b/queue-3.18/uapi-fix-linux-rds.h-userspace-compilation-errors.patch @@ -0,0 +1,143 @@ +From foo@baz Thu Oct 19 15:22:10 CEST 2017 +From: "Dmitry V. Levin" +Date: Thu, 16 Feb 2017 18:05:45 +0300 +Subject: uapi: fix linux/rds.h userspace compilation errors + +From: "Dmitry V. Levin" + + +[ Upstream commit feb0869d90e51ce8b6fd8a46588465b1b5a26d09 ] + +Consistently use types from linux/types.h to fix the following +linux/rds.h userspace compilation errors: + +/usr/include/linux/rds.h:106:2: error: unknown type name 'uint8_t' + uint8_t name[32]; +/usr/include/linux/rds.h:107:2: error: unknown type name 'uint64_t' + uint64_t value; +/usr/include/linux/rds.h:117:2: error: unknown type name 'uint64_t' + uint64_t next_tx_seq; +/usr/include/linux/rds.h:118:2: error: unknown type name 'uint64_t' + uint64_t next_rx_seq; +/usr/include/linux/rds.h:121:2: error: unknown type name 'uint8_t' + uint8_t transport[TRANSNAMSIZ]; /* null term ascii */ +/usr/include/linux/rds.h:122:2: error: unknown type name 'uint8_t' + uint8_t flags; +/usr/include/linux/rds.h:129:2: error: unknown type name 'uint64_t' + uint64_t seq; +/usr/include/linux/rds.h:130:2: error: unknown type name 'uint32_t' + uint32_t len; +/usr/include/linux/rds.h:135:2: error: unknown type name 'uint8_t' + uint8_t flags; +/usr/include/linux/rds.h:139:2: error: unknown type name 'uint32_t' + uint32_t sndbuf; +/usr/include/linux/rds.h:144:2: error: unknown type name 'uint32_t' + uint32_t rcvbuf; +/usr/include/linux/rds.h:145:2: error: unknown type name 'uint64_t' + uint64_t inum; +/usr/include/linux/rds.h:153:2: error: unknown type name 'uint64_t' + uint64_t hdr_rem; +/usr/include/linux/rds.h:154:2: error: unknown type name 'uint64_t' + uint64_t data_rem; +/usr/include/linux/rds.h:155:2: error: unknown type name 'uint32_t' + uint32_t last_sent_nxt; +/usr/include/linux/rds.h:156:2: error: unknown type name 'uint32_t' + uint32_t last_expected_una; +/usr/include/linux/rds.h:157:2: error: unknown type name 'uint32_t' + uint32_t last_seen_una; +/usr/include/linux/rds.h:164:2: error: unknown type name 'uint8_t' + uint8_t src_gid[RDS_IB_GID_LEN]; +/usr/include/linux/rds.h:165:2: error: unknown type name 'uint8_t' + uint8_t dst_gid[RDS_IB_GID_LEN]; +/usr/include/linux/rds.h:167:2: error: unknown type name 'uint32_t' + uint32_t max_send_wr; +/usr/include/linux/rds.h:168:2: error: unknown type name 'uint32_t' + uint32_t max_recv_wr; +/usr/include/linux/rds.h:169:2: error: unknown type name 'uint32_t' + uint32_t max_send_sge; +/usr/include/linux/rds.h:170:2: error: unknown type name 'uint32_t' + uint32_t rdma_mr_max; +/usr/include/linux/rds.h:171:2: error: unknown type name 'uint32_t' + uint32_t rdma_mr_size; +/usr/include/linux/rds.h:212:9: error: unknown type name 'uint64_t' + typedef uint64_t rds_rdma_cookie_t; +/usr/include/linux/rds.h:215:2: error: unknown type name 'uint64_t' + uint64_t addr; +/usr/include/linux/rds.h:216:2: error: unknown type name 'uint64_t' + uint64_t bytes; +/usr/include/linux/rds.h:221:2: error: unknown type name 'uint64_t' + uint64_t cookie_addr; +/usr/include/linux/rds.h:222:2: error: unknown type name 'uint64_t' + uint64_t flags; +/usr/include/linux/rds.h:228:2: error: unknown type name 'uint64_t' + uint64_t cookie_addr; +/usr/include/linux/rds.h:229:2: error: unknown type name 'uint64_t' + uint64_t flags; +/usr/include/linux/rds.h:234:2: error: unknown type name 'uint64_t' + uint64_t flags; +/usr/include/linux/rds.h:240:2: error: unknown type name 'uint64_t' + uint64_t local_vec_addr; +/usr/include/linux/rds.h:241:2: error: unknown type name 'uint64_t' + uint64_t nr_local; +/usr/include/linux/rds.h:242:2: error: unknown type name 'uint64_t' + uint64_t flags; +/usr/include/linux/rds.h:243:2: error: unknown type name 'uint64_t' + uint64_t user_token; +/usr/include/linux/rds.h:248:2: error: unknown type name 'uint64_t' + uint64_t local_addr; +/usr/include/linux/rds.h:249:2: error: unknown type name 'uint64_t' + uint64_t remote_addr; +/usr/include/linux/rds.h:252:4: error: unknown type name 'uint64_t' + uint64_t compare; +/usr/include/linux/rds.h:253:4: error: unknown type name 'uint64_t' + uint64_t swap; +/usr/include/linux/rds.h:256:4: error: unknown type name 'uint64_t' + uint64_t add; +/usr/include/linux/rds.h:259:4: error: unknown type name 'uint64_t' + uint64_t compare; +/usr/include/linux/rds.h:260:4: error: unknown type name 'uint64_t' + uint64_t swap; +/usr/include/linux/rds.h:261:4: error: unknown type name 'uint64_t' + uint64_t compare_mask; +/usr/include/linux/rds.h:262:4: error: unknown type name 'uint64_t' + uint64_t swap_mask; +/usr/include/linux/rds.h:265:4: error: unknown type name 'uint64_t' + uint64_t add; +/usr/include/linux/rds.h:266:4: error: unknown type name 'uint64_t' + uint64_t nocarry_mask; +/usr/include/linux/rds.h:269:2: error: unknown type name 'uint64_t' + uint64_t flags; +/usr/include/linux/rds.h:270:2: error: unknown type name 'uint64_t' + uint64_t user_token; +/usr/include/linux/rds.h:274:2: error: unknown type name 'uint64_t' + uint64_t user_token; +/usr/include/linux/rds.h:275:2: error: unknown type name 'int32_t' + int32_t status; + +Signed-off-by: Dmitry V. Levin +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/uapi/linux/rds.h | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/include/uapi/linux/rds.h ++++ b/include/uapi/linux/rds.h +@@ -35,6 +35,7 @@ + #define _LINUX_RDS_H + + #include ++#include /* For __kernel_sockaddr_storage. */ + + #define RDS_IB_ABI_VERSION 0x301 + +@@ -213,7 +214,7 @@ struct rds_get_mr_args { + }; + + struct rds_get_mr_for_dest_args { +- struct sockaddr_storage dest_addr; ++ struct __kernel_sockaddr_storage dest_addr; + struct rds_iovec vec; + uint64_t cookie_addr; + uint64_t flags; diff --git a/queue-3.18/watchdog-kempld-fix-gcc-4.3-build.patch b/queue-3.18/watchdog-kempld-fix-gcc-4.3-build.patch new file mode 100644 index 00000000000..bd7934ea43d --- /dev/null +++ b/queue-3.18/watchdog-kempld-fix-gcc-4.3-build.patch @@ -0,0 +1,53 @@ +From foo@baz Thu Oct 19 15:22:10 CEST 2017 +From: Arnd Bergmann +Date: Wed, 1 Mar 2017 10:15:29 +0100 +Subject: watchdog: kempld: fix gcc-4.3 build + +From: Arnd Bergmann + + +[ Upstream commit 3736d4eb6af37492aeded7fec0072dedd959c842 ] + +gcc-4.3 can't decide whether the constant value in +kempld_prescaler[PRESCALER_21] is built-time constant or +not, and gets confused by the logic in do_div(): + +drivers/watchdog/kempld_wdt.o: In function `kempld_wdt_set_stage_timeout': +kempld_wdt.c:(.text.kempld_wdt_set_stage_timeout+0x130): undefined reference to `__aeabi_uldivmod' + +This adds a call to ACCESS_ONCE() to force it to not consider +it to be constant, and leaves the more efficient normal case +in place for modern compilers, using an #ifdef to annotate +why we do this hack. + +Signed-off-by: Arnd Bergmann +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/watchdog/kempld_wdt.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/drivers/watchdog/kempld_wdt.c ++++ b/drivers/watchdog/kempld_wdt.c +@@ -140,12 +140,19 @@ static int kempld_wdt_set_stage_timeout( + unsigned int timeout) + { + struct kempld_device_data *pld = wdt_data->pld; +- u32 prescaler = kempld_prescaler[PRESCALER_21]; ++ u32 prescaler; + u64 stage_timeout64; + u32 stage_timeout; + u32 remainder; + u8 stage_cfg; + ++#if GCC_VERSION < 40400 ++ /* work around a bug compiling do_div() */ ++ prescaler = READ_ONCE(kempld_prescaler[PRESCALER_21]); ++#else ++ prescaler = kempld_prescaler[PRESCALER_21]; ++#endif ++ + if (!stage) + return -EINVAL; +