From: Greg Kroah-Hartman Date: Tue, 18 Nov 2014 20:24:31 +0000 (-0800) Subject: 3.14-stable patches X-Git-Tag: v3.10.61~24 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3e17f7e085a6d6bbc054025f56801f77a4c082a8;p=thirdparty%2Fkernel%2Fstable-queue.git 3.14-stable patches added patches: md-always-set-recovery_needed-when-clearing-recovery_frozen.patch nfs-don-t-try-to-reclaim-delegation-open-state-if-recovery-failed.patch nfs-fix-use-of-uninitialized-variable-in-nfs_getattr.patch nfsv4-ensure-that-we-remove-nfsv4.0-delegations-when-state-has-expired.patch nfsv4-fix-races-between-nfs_remove_bad_delegation-and-delegation-return.patch nfsv4.1-nfs41_clear_delegation_stateid-shouldn-t-trust-nfs_delegated_state.patch power-bq2415x_charger-fix-memory-leak-on-dts-parsing-error.patch power-bq2415x_charger-properly-handle-enodev-from-power_supply_get_by_phandle.patch power-charger-manager-fix-accessing-invalidated-power-supply-after-charger-unbind.patch power-charger-manager-fix-accessing-invalidated-power-supply-after-fuel-gauge-unbind.patch x86-kaslr-prevent-.bss-from-overlaping-initrd.patch x86-microcode-amd-fix-early-ucode-loading-on-32-bit.patch x86-microcode-amd-fix-ucode-patch-stashing-on-32-bit.patch --- diff --git a/queue-3.14/md-always-set-recovery_needed-when-clearing-recovery_frozen.patch b/queue-3.14/md-always-set-recovery_needed-when-clearing-recovery_frozen.patch new file mode 100644 index 00000000000..010d1969d12 --- /dev/null +++ b/queue-3.14/md-always-set-recovery_needed-when-clearing-recovery_frozen.patch @@ -0,0 +1,56 @@ +From 45eaf45dfa4850df16bc2e8e7903d89021137f40 Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Wed, 29 Oct 2014 08:49:50 +1100 +Subject: md: Always set RECOVERY_NEEDED when clearing RECOVERY_FROZEN + +From: NeilBrown + +commit 45eaf45dfa4850df16bc2e8e7903d89021137f40 upstream. + +md_check_recovery will skip any recovery and also clear +MD_RECOVERY_NEEDED if MD_RECOVERY_FROZEN is set. +So when we clear _FROZEN, we must set _NEEDED and ensure that +md_check_recovery gets run. +Otherwise we could miss out on something that is needed. + +In particular, this can make it impossible to remove a +failed device from an array is the 'recovery-needed' processing +didn't happen. +Suitable for stable kernels since 3.13. + +Reported-and-tested-by: Joe Lawrence +Fixes: 30b8feb730f9b9b3c5de02580897da03f59b6b16 +Signed-off-by: NeilBrown +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/md.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -5333,6 +5333,7 @@ static int md_set_readonly(struct mddev + printk("md: %s still in use.\n",mdname(mddev)); + if (did_freeze) { + clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); ++ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); + md_wakeup_thread(mddev->thread); + } + err = -EBUSY; +@@ -5347,6 +5348,8 @@ static int md_set_readonly(struct mddev + mddev->ro = 1; + set_disk_ro(mddev->gendisk, 1); + clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); ++ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); ++ md_wakeup_thread(mddev->thread); + sysfs_notify_dirent_safe(mddev->sysfs_state); + err = 0; + } +@@ -5390,6 +5393,7 @@ static int do_md_stop(struct mddev * mdd + mutex_unlock(&mddev->open_mutex); + if (did_freeze) { + clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); ++ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); + md_wakeup_thread(mddev->thread); + } + return -EBUSY; diff --git a/queue-3.14/nfs-don-t-try-to-reclaim-delegation-open-state-if-recovery-failed.patch b/queue-3.14/nfs-don-t-try-to-reclaim-delegation-open-state-if-recovery-failed.patch new file mode 100644 index 00000000000..7022ce8077f --- /dev/null +++ b/queue-3.14/nfs-don-t-try-to-reclaim-delegation-open-state-if-recovery-failed.patch @@ -0,0 +1,31 @@ +From f8ebf7a8ca35dde321f0cd385fee6f1950609367 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Fri, 17 Oct 2014 23:02:52 +0300 +Subject: NFS: Don't try to reclaim delegation open state if recovery failed + +From: Trond Myklebust + +commit f8ebf7a8ca35dde321f0cd385fee6f1950609367 upstream. + +If state recovery failed, then we should not attempt to reclaim delegated +state. + +http://lkml.kernel.org/r/CAN-5tyHwG=Cn2Q9KsHWadewjpTTy_K26ee+UnSvHvG4192p-Xw@mail.gmail.com +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/delegation.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/nfs/delegation.c ++++ b/fs/nfs/delegation.c +@@ -109,6 +109,8 @@ again: + continue; + if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) + continue; ++ if (!nfs4_valid_open_stateid(state)) ++ continue; + if (!nfs4_stateid_match(&state->stateid, stateid)) + continue; + get_nfs_open_context(ctx); diff --git a/queue-3.14/nfs-fix-use-of-uninitialized-variable-in-nfs_getattr.patch b/queue-3.14/nfs-fix-use-of-uninitialized-variable-in-nfs_getattr.patch new file mode 100644 index 00000000000..f7309ae60c6 --- /dev/null +++ b/queue-3.14/nfs-fix-use-of-uninitialized-variable-in-nfs_getattr.patch @@ -0,0 +1,32 @@ +From 16caf5b6101d03335b386e77e9e14136f989be87 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Thu, 23 Oct 2014 14:02:47 +0200 +Subject: nfs: Fix use of uninitialized variable in nfs_getattr() + +From: Jan Kara + +commit 16caf5b6101d03335b386e77e9e14136f989be87 upstream. + +Variable 'err' needn't be initialized when nfs_getattr() uses it to +check whether it should call generic_fillattr() or not. That can result +in spurious error returns. Initialize 'err' properly. + +Signed-off-by: Jan Kara +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/nfs/inode.c ++++ b/fs/nfs/inode.c +@@ -592,7 +592,7 @@ int nfs_getattr(struct vfsmount *mnt, st + { + struct inode *inode = dentry->d_inode; + int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; +- int err; ++ int err = 0; + + trace_nfs_getattr_enter(inode); + /* Flush out writes to the server in order to update c/mtime. */ diff --git a/queue-3.14/nfsv4-ensure-that-we-remove-nfsv4.0-delegations-when-state-has-expired.patch b/queue-3.14/nfsv4-ensure-that-we-remove-nfsv4.0-delegations-when-state-has-expired.patch new file mode 100644 index 00000000000..c30f16c8796 --- /dev/null +++ b/queue-3.14/nfsv4-ensure-that-we-remove-nfsv4.0-delegations-when-state-has-expired.patch @@ -0,0 +1,61 @@ +From 4dfd4f7af0afd201706ad186352ca423b0f17d4b Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Fri, 17 Oct 2014 15:10:25 +0300 +Subject: NFSv4: Ensure that we remove NFSv4.0 delegations when state has expired + +From: Trond Myklebust + +commit 4dfd4f7af0afd201706ad186352ca423b0f17d4b upstream. + +NFSv4.0 does not have TEST_STATEID/FREE_STATEID functionality, so +unlike NFSv4.1, the recovery procedure when stateids have expired or +have been revoked requires us to just forget the delegation. + +http://lkml.kernel.org/r/CAN-5tyHwG=Cn2Q9KsHWadewjpTTy_K26ee+UnSvHvG4192p-Xw@mail.gmail.com +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/nfs4proc.c | 24 +++++++++++++++++++++++- + 1 file changed, 23 insertions(+), 1 deletion(-) + +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -2034,6 +2034,28 @@ static int nfs4_open_expired(struct nfs4 + return ret; + } + ++static void nfs_finish_clear_delegation_stateid(struct nfs4_state *state) ++{ ++ nfs_remove_bad_delegation(state->inode); ++ write_seqlock(&state->seqlock); ++ nfs4_stateid_copy(&state->stateid, &state->open_stateid); ++ write_sequnlock(&state->seqlock); ++ clear_bit(NFS_DELEGATED_STATE, &state->flags); ++} ++ ++static void nfs40_clear_delegation_stateid(struct nfs4_state *state) ++{ ++ if (rcu_access_pointer(NFS_I(state->inode)->delegation) != NULL) ++ nfs_finish_clear_delegation_stateid(state); ++} ++ ++static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) ++{ ++ /* NFSv4.0 doesn't allow for delegation recovery on open expire */ ++ nfs40_clear_delegation_stateid(state); ++ return nfs4_open_expired(sp, state); ++} ++ + #if defined(CONFIG_NFS_V4_1) + static void nfs41_clear_delegation_stateid(struct nfs4_state *state) + { +@@ -8255,7 +8277,7 @@ static const struct nfs4_state_recovery_ + static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = { + .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, + .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, +- .recover_open = nfs4_open_expired, ++ .recover_open = nfs40_open_expired, + .recover_lock = nfs4_lock_expired, + .establish_clid = nfs4_init_clientid, + }; diff --git a/queue-3.14/nfsv4-fix-races-between-nfs_remove_bad_delegation-and-delegation-return.patch b/queue-3.14/nfsv4-fix-races-between-nfs_remove_bad_delegation-and-delegation-return.patch new file mode 100644 index 00000000000..057e0c4f6e0 --- /dev/null +++ b/queue-3.14/nfsv4-fix-races-between-nfs_remove_bad_delegation-and-delegation-return.patch @@ -0,0 +1,105 @@ +From 869f9dfa4d6d57b79e0afc3af14772c2a023eeb1 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Mon, 10 Nov 2014 18:43:56 -0500 +Subject: NFSv4: Fix races between nfs_remove_bad_delegation() and delegation return + +From: Trond Myklebust + +commit 869f9dfa4d6d57b79e0afc3af14772c2a023eeb1 upstream. + +Any attempt to call nfs_remove_bad_delegation() while a delegation is being +returned is currently a no-op. This means that we can end up looping +forever in nfs_end_delegation_return() if something causes the delegation +to be revoked. +This patch adds a mechanism whereby the state recovery code can communicate +to the delegation return code that the delegation is no longer valid and +that it should not be used when reclaiming state. +It also changes the return value for nfs4_handle_delegation_recall_error() +to ensure that nfs_end_delegation_return() does not reattempt the lock +reclaim before state recovery is done. + +http://lkml.kernel.org/r/CAN-5tyHwG=Cn2Q9KsHWadewjpTTy_K26ee+UnSvHvG4192p-Xw@mail.gmail.com +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/delegation.c | 23 +++++++++++++++++++++-- + fs/nfs/delegation.h | 1 + + fs/nfs/nfs4proc.c | 2 +- + 3 files changed, 23 insertions(+), 3 deletions(-) + +--- a/fs/nfs/delegation.c ++++ b/fs/nfs/delegation.c +@@ -179,7 +179,11 @@ static int nfs_do_return_delegation(stru + { + int res = 0; + +- res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid, issync); ++ if (!test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) ++ res = nfs4_proc_delegreturn(inode, ++ delegation->cred, ++ &delegation->stateid, ++ issync); + nfs_free_delegation(delegation); + return res; + } +@@ -366,11 +370,13 @@ static int nfs_end_delegation_return(str + { + struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; + struct nfs_inode *nfsi = NFS_I(inode); +- int err; ++ int err = 0; + + if (delegation == NULL) + return 0; + do { ++ if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) ++ break; + err = nfs_delegation_claim_opens(inode, &delegation->stateid); + if (!issync || err != -EAGAIN) + break; +@@ -591,10 +597,23 @@ static void nfs_client_mark_return_unuse + rcu_read_unlock(); + } + ++static void nfs_revoke_delegation(struct inode *inode) ++{ ++ struct nfs_delegation *delegation; ++ rcu_read_lock(); ++ delegation = rcu_dereference(NFS_I(inode)->delegation); ++ if (delegation != NULL) { ++ set_bit(NFS_DELEGATION_REVOKED, &delegation->flags); ++ nfs_mark_return_delegation(NFS_SERVER(inode), delegation); ++ } ++ rcu_read_unlock(); ++} ++ + void nfs_remove_bad_delegation(struct inode *inode) + { + struct nfs_delegation *delegation; + ++ nfs_revoke_delegation(inode); + delegation = nfs_inode_detach_delegation(inode); + if (delegation) { + nfs_inode_find_state_and_recover(inode, &delegation->stateid); +--- a/fs/nfs/delegation.h ++++ b/fs/nfs/delegation.h +@@ -31,6 +31,7 @@ enum { + NFS_DELEGATION_RETURN_IF_CLOSED, + NFS_DELEGATION_REFERENCED, + NFS_DELEGATION_RETURNING, ++ NFS_DELEGATION_REVOKED, + }; + + int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -1587,7 +1587,7 @@ static int nfs4_handle_delegation_recall + nfs_inode_find_state_and_recover(state->inode, + stateid); + nfs4_schedule_stateid_recovery(server, state); +- return 0; ++ return -EAGAIN; + case -NFS4ERR_DELAY: + case -NFS4ERR_GRACE: + set_bit(NFS_DELEGATED_STATE, &state->flags); diff --git a/queue-3.14/nfsv4.1-nfs41_clear_delegation_stateid-shouldn-t-trust-nfs_delegated_state.patch b/queue-3.14/nfsv4.1-nfs41_clear_delegation_stateid-shouldn-t-trust-nfs_delegated_state.patch new file mode 100644 index 00000000000..e12805a4b77 --- /dev/null +++ b/queue-3.14/nfsv4.1-nfs41_clear_delegation_stateid-shouldn-t-trust-nfs_delegated_state.patch @@ -0,0 +1,102 @@ +From 0c116cadd94b16b30b1dd90d38b2784d9b39b01a Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Wed, 12 Nov 2014 14:44:49 -0500 +Subject: NFSv4.1: nfs41_clear_delegation_stateid shouldn't trust NFS_DELEGATED_STATE + +From: Trond Myklebust + +commit 0c116cadd94b16b30b1dd90d38b2784d9b39b01a upstream. + +This patch removes the assumption made previously, that we only need to +check the delegation stateid when it matches the stateid on a cached +open. + +If we believe that we hold a delegation for this file, then we must assume +that its stateid may have been revoked or expired too. If we don't test it +then our state recovery process may end up caching open/lock state in a +situation where it should not. +We therefore rename the function nfs41_clear_delegation_stateid as +nfs41_check_delegation_stateid, and change it to always run through the +delegation stateid test and recovery process as outlined in RFC5661. + +http://lkml.kernel.org/r/CAN-5tyHwG=Cn2Q9KsHWadewjpTTy_K26ee+UnSvHvG4192p-Xw@mail.gmail.com +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/nfs4proc.c | 42 +++++++++++++++++------------------------- + 1 file changed, 17 insertions(+), 25 deletions(-) + +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -2057,45 +2057,37 @@ static int nfs40_open_expired(struct nfs + } + + #if defined(CONFIG_NFS_V4_1) +-static void nfs41_clear_delegation_stateid(struct nfs4_state *state) ++static void nfs41_check_delegation_stateid(struct nfs4_state *state) + { + struct nfs_server *server = NFS_SERVER(state->inode); +- nfs4_stateid *stateid = &state->stateid; ++ nfs4_stateid stateid; + struct nfs_delegation *delegation; +- struct rpc_cred *cred = NULL; +- int status = -NFS4ERR_BAD_STATEID; +- +- /* If a state reset has been done, test_stateid is unneeded */ +- if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) +- return; ++ struct rpc_cred *cred; ++ int status; + + /* Get the delegation credential for use by test/free_stateid */ + rcu_read_lock(); + delegation = rcu_dereference(NFS_I(state->inode)->delegation); +- if (delegation != NULL && +- nfs4_stateid_match(&delegation->stateid, stateid)) { +- cred = get_rpccred(delegation->cred); +- rcu_read_unlock(); +- status = nfs41_test_stateid(server, stateid, cred); +- trace_nfs4_test_delegation_stateid(state, NULL, status); +- } else ++ if (delegation == NULL) { + rcu_read_unlock(); ++ return; ++ } ++ ++ nfs4_stateid_copy(&stateid, &delegation->stateid); ++ cred = get_rpccred(delegation->cred); ++ rcu_read_unlock(); ++ status = nfs41_test_stateid(server, &stateid, cred); ++ trace_nfs4_test_delegation_stateid(state, NULL, status); + + if (status != NFS_OK) { + /* Free the stateid unless the server explicitly + * informs us the stateid is unrecognized. */ + if (status != -NFS4ERR_BAD_STATEID) +- nfs41_free_stateid(server, stateid, cred); +- nfs_remove_bad_delegation(state->inode); +- +- write_seqlock(&state->seqlock); +- nfs4_stateid_copy(&state->stateid, &state->open_stateid); +- write_sequnlock(&state->seqlock); +- clear_bit(NFS_DELEGATED_STATE, &state->flags); ++ nfs41_free_stateid(server, &stateid, cred); ++ nfs_finish_clear_delegation_stateid(state); + } + +- if (cred != NULL) +- put_rpccred(cred); ++ put_rpccred(cred); + } + + /** +@@ -2139,7 +2131,7 @@ static int nfs41_open_expired(struct nfs + { + int status; + +- nfs41_clear_delegation_stateid(state); ++ nfs41_check_delegation_stateid(state); + status = nfs41_check_open_stateid(state); + if (status != NFS_OK) + status = nfs4_open_expired(sp, state); diff --git a/queue-3.14/power-bq2415x_charger-fix-memory-leak-on-dts-parsing-error.patch b/queue-3.14/power-bq2415x_charger-fix-memory-leak-on-dts-parsing-error.patch new file mode 100644 index 00000000000..42fb6b35d43 --- /dev/null +++ b/queue-3.14/power-bq2415x_charger-fix-memory-leak-on-dts-parsing-error.patch @@ -0,0 +1,63 @@ +From 21e863b233553998737e1b506c823a00bf012e00 Mon Sep 17 00:00:00 2001 +From: Krzysztof Kozlowski +Date: Wed, 15 Oct 2014 16:25:10 +0200 +Subject: power: bq2415x_charger: Fix memory leak on DTS parsing error + +From: Krzysztof Kozlowski + +commit 21e863b233553998737e1b506c823a00bf012e00 upstream. + +Memory allocated for 'name' was leaking if required binding properties +were not present. + +The memory for 'name' was allocated early at probe with kasprintf(). It +was freed in error paths executed before and after parsing DTS but not +in that error path. + +Fix the error path for parsing device tree properties. + +Signed-off-by: Krzysztof Kozlowski +Fixes: faffd234cf85 ("bq2415x_charger: Add DT support") +Signed-off-by: Sebastian Reichel +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/power/bq2415x_charger.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/power/bq2415x_charger.c ++++ b/drivers/power/bq2415x_charger.c +@@ -1609,27 +1609,27 @@ static int bq2415x_probe(struct i2c_clie + ret = of_property_read_u32(np, "ti,current-limit", + &bq->init_data.current_limit); + if (ret) +- return ret; ++ goto error_2; + ret = of_property_read_u32(np, "ti,weak-battery-voltage", + &bq->init_data.weak_battery_voltage); + if (ret) +- return ret; ++ goto error_2; + ret = of_property_read_u32(np, "ti,battery-regulation-voltage", + &bq->init_data.battery_regulation_voltage); + if (ret) +- return ret; ++ goto error_2; + ret = of_property_read_u32(np, "ti,charge-current", + &bq->init_data.charge_current); + if (ret) +- return ret; ++ goto error_2; + ret = of_property_read_u32(np, "ti,termination-current", + &bq->init_data.termination_current); + if (ret) +- return ret; ++ goto error_2; + ret = of_property_read_u32(np, "ti,resistor-sense", + &bq->init_data.resistor_sense); + if (ret) +- return ret; ++ goto error_2; + } else { + memcpy(&bq->init_data, pdata, sizeof(bq->init_data)); + } diff --git a/queue-3.14/power-bq2415x_charger-properly-handle-enodev-from-power_supply_get_by_phandle.patch b/queue-3.14/power-bq2415x_charger-properly-handle-enodev-from-power_supply_get_by_phandle.patch new file mode 100644 index 00000000000..7fe966bb875 --- /dev/null +++ b/queue-3.14/power-bq2415x_charger-properly-handle-enodev-from-power_supply_get_by_phandle.patch @@ -0,0 +1,52 @@ +From 0eaf437aa14949d2230aeab7364f4ab47901304a Mon Sep 17 00:00:00 2001 +From: Krzysztof Kozlowski +Date: Wed, 15 Oct 2014 16:25:09 +0200 +Subject: power: bq2415x_charger: Properly handle ENODEV from power_supply_get_by_phandle + +From: Krzysztof Kozlowski + +commit 0eaf437aa14949d2230aeab7364f4ab47901304a upstream. + +The power_supply_get_by_phandle() on error returns ENODEV or NULL. +The driver later expects obtained pointer to power supply to be +valid or NULL. If it is not NULL then it dereferences it in +bq2415x_notifier_call() which would lead to dereferencing ENODEV-value +pointer. + +Properly handle the power_supply_get_by_phandle() error case by +replacing error value with NULL. This indicates that usb charger +detection won't be used. + +Fix also memory leak of 'name' if power_supply_get_by_phandle() fails +with NULL and probe should defer. + +Signed-off-by: Krzysztof Kozlowski +Fixes: faffd234cf85 ("bq2415x_charger: Add DT support") +[small fix regarding the missing ti,usb-charger-detection info message] +Signed-off-by: Sebastian Reichel +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/power/bq2415x_charger.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/drivers/power/bq2415x_charger.c ++++ b/drivers/power/bq2415x_charger.c +@@ -1579,8 +1579,15 @@ static int bq2415x_probe(struct i2c_clie + if (np) { + bq->notify_psy = power_supply_get_by_phandle(np, "ti,usb-charger-detection"); + +- if (!bq->notify_psy) +- return -EPROBE_DEFER; ++ if (IS_ERR(bq->notify_psy)) { ++ dev_info(&client->dev, ++ "no 'ti,usb-charger-detection' property (err=%ld)\n", ++ PTR_ERR(bq->notify_psy)); ++ bq->notify_psy = NULL; ++ } else if (!bq->notify_psy) { ++ ret = -EPROBE_DEFER; ++ goto error_2; ++ } + } + else if (pdata->notify_device) + bq->notify_psy = power_supply_get_by_name(pdata->notify_device); diff --git a/queue-3.14/power-charger-manager-fix-accessing-invalidated-power-supply-after-charger-unbind.patch b/queue-3.14/power-charger-manager-fix-accessing-invalidated-power-supply-after-charger-unbind.patch new file mode 100644 index 00000000000..15aa8ed70ee --- /dev/null +++ b/queue-3.14/power-charger-manager-fix-accessing-invalidated-power-supply-after-charger-unbind.patch @@ -0,0 +1,211 @@ +From cdaf3e15385d3232b52287e50692506f8fd01a09 Mon Sep 17 00:00:00 2001 +From: Krzysztof Kozlowski +Date: Mon, 13 Oct 2014 15:34:31 +0200 +Subject: power: charger-manager: Fix accessing invalidated power supply after charger unbind + +From: Krzysztof Kozlowski + +commit cdaf3e15385d3232b52287e50692506f8fd01a09 upstream. + +The charger manager obtained in probe references to power supplies for +all chargers with power_supply_get_by_name() for later usage. However +if such charger driver was removed then this reference would point to +old power supply (from driver which was removed). + +This lead to accessing invalid memory which could be observed with: +$ echo "max77693-charger" > /sys/bus/platform/drivers/max77693-charger/unbind +$ grep . /sys/devices/virtual/power_supply/battery/charger.0/* +$ grep . /sys/devices/virtual/power_supply/battery/* +[ 15.339817] Unable to handle kernel paging request at virtual address 0001c12c +[ 15.346187] pgd = edd08000 +[ 15.348814] [0001c12c] *pgd=6dce2831, *pte=00000000, *ppte=00000000 +[ 15.355075] Internal error: Oops: 80000007 [#1] PREEMPT SMP ARM +[ 15.360967] Modules linked in: +[ 15.364010] CPU: 2 PID: 1388 Comm: grep Not tainted 3.17.0-next-20141007-00027-ga95e761db1b0 #245 +[ 15.372859] task: ee03ad00 ti: edcf6000 task.ti: edcf6000 +[ 15.378241] PC is at 0x1c12c +[ 15.381113] LR is at is_ext_pwr_online+0x30/0x6c +[ 15.385706] pc : [<0001c12c>] lr : [] psr: a0000013 +[ 15.385706] sp : edcf7e88 ip : 00000000 fp : 00000000 +[ 15.397161] r10: eeb02c08 r9 : c04b1f84 r8 : eeb02c00 +[ 15.402369] r7 : edc69a10 r6 : eea6ac10 r5 : eea6ac10 r4 : 00000004 +[ 15.408878] r3 : 0001c12c r2 : edcf7e8c r1 : 00000004 r0 : ee914418 +[ 15.415390] Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user +[ 15.422506] Control: 10c5387d Table: 6dd0804a DAC: 00000015 +[ 15.428236] Process grep (pid: 1388, stack limit = 0xedcf6240) +[ 15.434050] Stack: (0xedcf7e88 to 0xedcf8000) +[ 15.438395] 7e80: ee03ad00 00000000 edcf7f80 eea6aca8 edcf7ec4 c033b7b0 +[ 15.446554] 7ea0: 00000001 ee1cc3f0 00000004 c06e1e44 eebdc000 c06e1e44 eeb02c00 c0337144 +[ 15.454713] 7ec0: ee2dac68 c005cffc ee1cc3c0 c06e1e44 00000fff 00001000 eebdc000 c0278ca8 +[ 15.462872] 7ee0: c0278c8c ee1cc3c0 eeb7ce00 c014422c edcf7f20 00008000 ee1cc3c0 ee9a48c0 +[ 15.471030] 7f00: 00000001 00000001 edcf7f80 c0142d94 c0142d70 c01060f4 00021000 ee1cc3f0 +[ 15.479190] 7f20: 00000000 00000000 c06a2150 eebdc000 2e7ec000 ee9a48c0 00008000 00021000 +[ 15.487349] 7f40: edcf7f80 00008000 edcf6000 00021000 00021000 c00e39a4 00000000 ee9a48c0 +[ 15.495508] 7f60: 00004000 00000000 00000000 ee9a48c0 ee9a48c0 00008000 00021000 c00e3aa0 +[ 15.503668] 7f80: 00000000 00000000 0001f2e0 0001f2e0 00021000 00001000 00000003 c000f364 +[ 15.511826] 7fa0: 00000000 c000f1a0 0001f2e0 00021000 00000003 00021000 00008000 00000000 +[ 15.519986] 7fc0: 0001f2e0 00021000 00001000 00000003 00000001 000205e8 00000000 00021000 +[ 15.528145] 7fe0: 00008000 bebbe910 0000a7ad b6edc49c 60000010 00000003 aaaaaaaa aaaaaaaa +[ 15.536320] [] (is_ext_pwr_online) from [] (charger_get_property+0x170/0x314) +[ 15.545164] [] (charger_get_property) from [] (power_supply_show_property+0x48/0x20c) +[ 15.554719] [] (power_supply_show_property) from [] (dev_attr_show+0x1c/0x48) +[ 15.563577] [] (dev_attr_show) from [] (sysfs_kf_seq_show+0x84/0x104) +[ 15.571725] [] (sysfs_kf_seq_show) from [] (kernfs_seq_show+0x24/0x28) +[ 15.579973] [] (kernfs_seq_show) from [] (seq_read+0x1b0/0x484) +[ 15.587614] [] (seq_read) from [] (vfs_read+0x88/0x144) +[ 15.594552] [] (vfs_read) from [] (SyS_read+0x40/0x8c) +[ 15.601417] [] (SyS_read) from [] (ret_fast_syscall+0x0/0x48) +[ 15.608877] Code: bad PC value +[ 15.611991] ---[ end trace a88fcc95208db283 ]--- + +The charger-manager should get reference to charger power supply on +each use of get_property callback. + +Signed-off-by: Krzysztof Kozlowski +Fixes: 3bb3dbbd56ea ("power_supply: Add initial Charger-Manager driver") +Signed-off-by: Sebastian Reichel +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/power/charger-manager.c | 64 ++++++++++++++++++++-------------- + include/linux/power/charger-manager.h | 2 - + 2 files changed, 39 insertions(+), 27 deletions(-) + +--- a/drivers/power/charger-manager.c ++++ b/drivers/power/charger-manager.c +@@ -118,10 +118,17 @@ static bool is_batt_present(struct charg + present = true; + break; + case CM_CHARGER_STAT: +- for (i = 0; cm->charger_stat[i]; i++) { +- ret = cm->charger_stat[i]->get_property( +- cm->charger_stat[i], +- POWER_SUPPLY_PROP_PRESENT, &val); ++ for (i = 0; cm->desc->psy_charger_stat[i]; i++) { ++ psy = power_supply_get_by_name( ++ cm->desc->psy_charger_stat[i]); ++ if (!psy) { ++ dev_err(cm->dev, "Cannot find power supply \"%s\"\n", ++ cm->desc->psy_charger_stat[i]); ++ continue; ++ } ++ ++ ret = psy->get_property(psy, POWER_SUPPLY_PROP_PRESENT, ++ &val); + if (ret == 0 && val.intval) { + present = true; + break; +@@ -144,14 +151,20 @@ static bool is_batt_present(struct charg + static bool is_ext_pwr_online(struct charger_manager *cm) + { + union power_supply_propval val; ++ struct power_supply *psy; + bool online = false; + int i, ret; + + /* If at least one of them has one, it's yes. */ +- for (i = 0; cm->charger_stat[i]; i++) { +- ret = cm->charger_stat[i]->get_property( +- cm->charger_stat[i], +- POWER_SUPPLY_PROP_ONLINE, &val); ++ for (i = 0; cm->desc->psy_charger_stat[i]; i++) { ++ psy = power_supply_get_by_name(cm->desc->psy_charger_stat[i]); ++ if (!psy) { ++ dev_err(cm->dev, "Cannot find power supply \"%s\"\n", ++ cm->desc->psy_charger_stat[i]); ++ continue; ++ } ++ ++ ret = psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &val); + if (ret == 0 && val.intval) { + online = true; + break; +@@ -196,6 +209,7 @@ static bool is_charging(struct charger_m + { + int i, ret; + bool charging = false; ++ struct power_supply *psy; + union power_supply_propval val; + + /* If there is no battery, it cannot be charged */ +@@ -203,17 +217,22 @@ static bool is_charging(struct charger_m + return false; + + /* If at least one of the charger is charging, return yes */ +- for (i = 0; cm->charger_stat[i]; i++) { ++ for (i = 0; cm->desc->psy_charger_stat[i]; i++) { + /* 1. The charger sholuld not be DISABLED */ + if (cm->emergency_stop) + continue; + if (!cm->charger_enabled) + continue; + ++ psy = power_supply_get_by_name(cm->desc->psy_charger_stat[i]); ++ if (!psy) { ++ dev_err(cm->dev, "Cannot find power supply \"%s\"\n", ++ cm->desc->psy_charger_stat[i]); ++ continue; ++ } ++ + /* 2. The charger should be online (ext-power) */ +- ret = cm->charger_stat[i]->get_property( +- cm->charger_stat[i], +- POWER_SUPPLY_PROP_ONLINE, &val); ++ ret = psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &val); + if (ret) { + dev_warn(cm->dev, "Cannot read ONLINE value from %s\n", + cm->desc->psy_charger_stat[i]); +@@ -226,9 +245,7 @@ static bool is_charging(struct charger_m + * 3. The charger should not be FULL, DISCHARGING, + * or NOT_CHARGING. + */ +- ret = cm->charger_stat[i]->get_property( +- cm->charger_stat[i], +- POWER_SUPPLY_PROP_STATUS, &val); ++ ret = psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &val); + if (ret) { + dev_warn(cm->dev, "Cannot read STATUS value from %s\n", + cm->desc->psy_charger_stat[i]); +@@ -1772,15 +1789,12 @@ static int charger_manager_probe(struct + while (desc->psy_charger_stat[i]) + i++; + +- cm->charger_stat = devm_kzalloc(&pdev->dev, +- sizeof(struct power_supply *) * i, GFP_KERNEL); +- if (!cm->charger_stat) +- return -ENOMEM; +- ++ /* Check if charger's supplies are present at probe */ + for (i = 0; desc->psy_charger_stat[i]; i++) { +- cm->charger_stat[i] = power_supply_get_by_name( +- desc->psy_charger_stat[i]); +- if (!cm->charger_stat[i]) { ++ struct power_supply *psy; ++ ++ psy = power_supply_get_by_name(desc->psy_charger_stat[i]); ++ if (!psy) { + dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n", + desc->psy_charger_stat[i]); + return -ENODEV; +@@ -2102,8 +2116,8 @@ static bool find_power_supply(struct cha + int i; + bool found = false; + +- for (i = 0; cm->charger_stat[i]; i++) { +- if (psy == cm->charger_stat[i]) { ++ for (i = 0; cm->desc->psy_charger_stat[i]; i++) { ++ if (!strcmp(psy->name, cm->desc->psy_charger_stat[i])) { + found = true; + break; + } +--- a/include/linux/power/charger-manager.h ++++ b/include/linux/power/charger-manager.h +@@ -253,8 +253,6 @@ struct charger_manager { + struct device *dev; + struct charger_desc *desc; + +- struct power_supply **charger_stat; +- + #ifdef CONFIG_THERMAL + struct thermal_zone_device *tzd_batt; + #endif diff --git a/queue-3.14/power-charger-manager-fix-accessing-invalidated-power-supply-after-fuel-gauge-unbind.patch b/queue-3.14/power-charger-manager-fix-accessing-invalidated-power-supply-after-fuel-gauge-unbind.patch new file mode 100644 index 00000000000..0f9b4bf7691 --- /dev/null +++ b/queue-3.14/power-charger-manager-fix-accessing-invalidated-power-supply-after-fuel-gauge-unbind.patch @@ -0,0 +1,339 @@ +From bdbe81445407644492b9ac69a24d35e3202d773b Mon Sep 17 00:00:00 2001 +From: Krzysztof Kozlowski +Date: Mon, 13 Oct 2014 15:34:30 +0200 +Subject: power: charger-manager: Fix accessing invalidated power supply after fuel gauge unbind + +From: Krzysztof Kozlowski + +commit bdbe81445407644492b9ac69a24d35e3202d773b upstream. + +The charger manager obtained reference to fuel gauge power supply in probe +with power_supply_get_by_name() for later usage. However if fuel gauge +driver was removed and re-added then this reference would point to old +power supply (from driver which was removed). + +This lead to accessing old (and probably invalid) memory which could be +observed with: +$ echo "12-0036" > /sys/bus/i2c/drivers/max17042/unbind +$ echo "12-0036" > /sys/bus/i2c/drivers/max17042/bind +$ cat /sys/devices/virtual/power_supply/battery/capacity +[ 240.480084] INFO: task cat:1393 blocked for more than 120 seconds. +[ 240.484799] Not tainted 3.17.0-next-20141007-00028-ge60b6dd79570 #203 +[ 240.491782] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. +[ 240.499589] cat D c0469530 0 1393 1 0x00000000 +[ 240.505947] [] (__schedule) from [] (schedule_preempt_disabled+0x14/0x20) +[ 240.514449] [] (schedule_preempt_disabled) from [] (mutex_lock_nested+0x1bc/0x458) +[ 240.523736] [] (mutex_lock_nested) from [] (regmap_read+0x30/0x60) +[ 240.531647] [] (regmap_read) from [] (max17042_get_property+0x2e8/0x350) +[ 240.540055] [] (max17042_get_property) from [] (charger_get_property+0x264/0x348) +[ 240.549252] [] (charger_get_property) from [] (power_supply_show_property+0x48/0x1e0) +[ 240.558808] [] (power_supply_show_property) from [] (dev_attr_show+0x1c/0x48) +[ 240.567664] [] (dev_attr_show) from [] (sysfs_kf_seq_show+0x84/0x104) +[ 240.575814] [] (sysfs_kf_seq_show) from [] (kernfs_seq_show+0x24/0x28) +[ 240.584061] [] (kernfs_seq_show) from [] (seq_read+0x1b0/0x484) +[ 240.591702] [] (seq_read) from [] (vfs_read+0x88/0x144) +[ 240.598640] [] (vfs_read) from [] (SyS_read+0x40/0x8c) +[ 240.605507] [] (SyS_read) from [] (ret_fast_syscall+0x0/0x48) +[ 240.612952] 4 locks held by cat/1393: +[ 240.616589] #0: (&p->lock){+.+.+.}, at: [] seq_read+0x30/0x484 +[ 240.623414] #1: (&of->mutex){+.+.+.}, at: [] kernfs_seq_start+0x1c/0x8c +[ 240.631086] #2: (s_active#31){++++.+}, at: [] kernfs_seq_start+0x24/0x8c +[ 240.638777] #3: (&map->mutex){+.+...}, at: [] regmap_read+0x30/0x60 + +The charger-manager should get reference to fuel gauge power supply on +each use of get_property callback. The thermal zone 'tzd' field of +power supply should not be used because of the same reason. + +Additionally this change solves also the issue with nested +thermal_zone_get_temp() calls and related false lockdep positive for +deadlock for thermal zone's mutex [1]. When fuel gauge is used as source of +temperature then the charger manager forwards its get_temp calls to fuel +gauge thermal zone. So actually different mutexes are used (one for +charger manager thermal zone and second for fuel gauge thermal zone) but +for lockdep this is one class of mutex. + +The recursion is removed by retrieving temperature through power +supply's get_property(). + +In case external thermal zone is used ('cm-thermal-zone' property is +present in DTS) the recursion does not exist. Charger manager simply +exports POWER_SUPPLY_PROP_TEMP_AMBIENT property (instead of +POWER_SUPPLY_PROP_TEMP) thus no thermal zone is created for this power +supply. + +[1] https://lkml.org/lkml/2014/10/6/309 + +Signed-off-by: Krzysztof Kozlowski +Fixes: 3bb3dbbd56ea ("power_supply: Add initial Charger-Manager driver") +Signed-off-by: Sebastian Reichel +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/power/charger-manager.c | 99 ++++++++++++++++++++++++---------- + include/linux/power/charger-manager.h | 1 + 2 files changed, 71 insertions(+), 29 deletions(-) + +--- a/drivers/power/charger-manager.c ++++ b/drivers/power/charger-manager.c +@@ -97,6 +97,7 @@ static struct charger_global_desc *g_des + static bool is_batt_present(struct charger_manager *cm) + { + union power_supply_propval val; ++ struct power_supply *psy; + bool present = false; + int i, ret; + +@@ -107,7 +108,11 @@ static bool is_batt_present(struct charg + case CM_NO_BATTERY: + break; + case CM_FUEL_GAUGE: +- ret = cm->fuel_gauge->get_property(cm->fuel_gauge, ++ psy = power_supply_get_by_name(cm->desc->psy_fuel_gauge); ++ if (!psy) ++ break; ++ ++ ret = psy->get_property(psy, + POWER_SUPPLY_PROP_PRESENT, &val); + if (ret == 0 && val.intval) + present = true; +@@ -167,12 +172,14 @@ static bool is_ext_pwr_online(struct cha + static int get_batt_uV(struct charger_manager *cm, int *uV) + { + union power_supply_propval val; ++ struct power_supply *fuel_gauge; + int ret; + +- if (!cm->fuel_gauge) ++ fuel_gauge = power_supply_get_by_name(cm->desc->psy_fuel_gauge); ++ if (!fuel_gauge) + return -ENODEV; + +- ret = cm->fuel_gauge->get_property(cm->fuel_gauge, ++ ret = fuel_gauge->get_property(fuel_gauge, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &val); + if (ret) + return ret; +@@ -248,6 +255,7 @@ static bool is_full_charged(struct charg + { + struct charger_desc *desc = cm->desc; + union power_supply_propval val; ++ struct power_supply *fuel_gauge; + int ret = 0; + int uV; + +@@ -255,11 +263,15 @@ static bool is_full_charged(struct charg + if (!is_batt_present(cm)) + return false; + +- if (cm->fuel_gauge && desc->fullbatt_full_capacity > 0) { ++ fuel_gauge = power_supply_get_by_name(cm->desc->psy_fuel_gauge); ++ if (!fuel_gauge) ++ return false; ++ ++ if (desc->fullbatt_full_capacity > 0) { + val.intval = 0; + + /* Not full if capacity of fuel gauge isn't full */ +- ret = cm->fuel_gauge->get_property(cm->fuel_gauge, ++ ret = fuel_gauge->get_property(fuel_gauge, + POWER_SUPPLY_PROP_CHARGE_FULL, &val); + if (!ret && val.intval > desc->fullbatt_full_capacity) + return true; +@@ -273,10 +285,10 @@ static bool is_full_charged(struct charg + } + + /* Full, if the capacity is more than fullbatt_soc */ +- if (cm->fuel_gauge && desc->fullbatt_soc > 0) { ++ if (desc->fullbatt_soc > 0) { + val.intval = 0; + +- ret = cm->fuel_gauge->get_property(cm->fuel_gauge, ++ ret = fuel_gauge->get_property(fuel_gauge, + POWER_SUPPLY_PROP_CAPACITY, &val); + if (!ret && val.intval >= desc->fullbatt_soc) + return true; +@@ -551,6 +563,20 @@ static int check_charging_duration(struc + return ret; + } + ++static int cm_get_battery_temperature_by_psy(struct charger_manager *cm, ++ int *temp) ++{ ++ struct power_supply *fuel_gauge; ++ ++ fuel_gauge = power_supply_get_by_name(cm->desc->psy_fuel_gauge); ++ if (!fuel_gauge) ++ return -ENODEV; ++ ++ return fuel_gauge->get_property(fuel_gauge, ++ POWER_SUPPLY_PROP_TEMP, ++ (union power_supply_propval *)temp); ++} ++ + static int cm_get_battery_temperature(struct charger_manager *cm, + int *temp) + { +@@ -560,15 +586,18 @@ static int cm_get_battery_temperature(st + return -ENODEV; + + #ifdef CONFIG_THERMAL +- ret = thermal_zone_get_temp(cm->tzd_batt, (unsigned long *)temp); +- if (!ret) +- /* Calibrate temperature unit */ +- *temp /= 100; +-#else +- ret = cm->fuel_gauge->get_property(cm->fuel_gauge, +- POWER_SUPPLY_PROP_TEMP, +- (union power_supply_propval *)temp); ++ if (cm->tzd_batt) { ++ ret = thermal_zone_get_temp(cm->tzd_batt, (unsigned long *)temp); ++ if (!ret) ++ /* Calibrate temperature unit */ ++ *temp /= 100; ++ } else + #endif ++ { ++ /* if-else continued from CONFIG_THERMAL */ ++ ret = cm_get_battery_temperature_by_psy(cm, temp); ++ } ++ + return ret; + } + +@@ -827,6 +856,7 @@ static int charger_get_property(struct p + struct charger_manager *cm = container_of(psy, + struct charger_manager, charger_psy); + struct charger_desc *desc = cm->desc; ++ struct power_supply *fuel_gauge; + int ret = 0; + int uV; + +@@ -857,14 +887,20 @@ static int charger_get_property(struct p + ret = get_batt_uV(cm, &val->intval); + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: +- ret = cm->fuel_gauge->get_property(cm->fuel_gauge, ++ fuel_gauge = power_supply_get_by_name(cm->desc->psy_fuel_gauge); ++ if (!fuel_gauge) { ++ ret = -ENODEV; ++ break; ++ } ++ ret = fuel_gauge->get_property(fuel_gauge, + POWER_SUPPLY_PROP_CURRENT_NOW, val); + break; + case POWER_SUPPLY_PROP_TEMP: + case POWER_SUPPLY_PROP_TEMP_AMBIENT: + return cm_get_battery_temperature(cm, &val->intval); + case POWER_SUPPLY_PROP_CAPACITY: +- if (!cm->fuel_gauge) { ++ fuel_gauge = power_supply_get_by_name(cm->desc->psy_fuel_gauge); ++ if (!fuel_gauge) { + ret = -ENODEV; + break; + } +@@ -875,7 +911,7 @@ static int charger_get_property(struct p + break; + } + +- ret = cm->fuel_gauge->get_property(cm->fuel_gauge, ++ ret = fuel_gauge->get_property(fuel_gauge, + POWER_SUPPLY_PROP_CAPACITY, val); + if (ret) + break; +@@ -924,7 +960,14 @@ static int charger_get_property(struct p + break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + if (is_charging(cm)) { +- ret = cm->fuel_gauge->get_property(cm->fuel_gauge, ++ fuel_gauge = power_supply_get_by_name( ++ cm->desc->psy_fuel_gauge); ++ if (!fuel_gauge) { ++ ret = -ENODEV; ++ break; ++ } ++ ++ ret = fuel_gauge->get_property(fuel_gauge, + POWER_SUPPLY_PROP_CHARGE_NOW, + val); + if (ret) { +@@ -1485,14 +1528,15 @@ err: + return ret; + } + +-static int cm_init_thermal_data(struct charger_manager *cm) ++static int cm_init_thermal_data(struct charger_manager *cm, ++ struct power_supply *fuel_gauge) + { + struct charger_desc *desc = cm->desc; + union power_supply_propval val; + int ret; + + /* Verify whether fuel gauge provides battery temperature */ +- ret = cm->fuel_gauge->get_property(cm->fuel_gauge, ++ ret = fuel_gauge->get_property(fuel_gauge, + POWER_SUPPLY_PROP_TEMP, &val); + + if (!ret) { +@@ -1502,8 +1546,6 @@ static int cm_init_thermal_data(struct c + cm->desc->measure_battery_temp = true; + } + #ifdef CONFIG_THERMAL +- cm->tzd_batt = cm->fuel_gauge->tzd; +- + if (ret && desc->thermal_zone) { + cm->tzd_batt = + thermal_zone_get_zone_by_name(desc->thermal_zone); +@@ -1666,6 +1708,7 @@ static int charger_manager_probe(struct + int ret = 0, i = 0; + int j = 0; + union power_supply_propval val; ++ struct power_supply *fuel_gauge; + + if (g_desc && !rtc_dev && g_desc->rtc_name) { + rtc_dev = rtc_class_open(g_desc->rtc_name); +@@ -1744,8 +1787,8 @@ static int charger_manager_probe(struct + } + } + +- cm->fuel_gauge = power_supply_get_by_name(desc->psy_fuel_gauge); +- if (!cm->fuel_gauge) { ++ fuel_gauge = power_supply_get_by_name(desc->psy_fuel_gauge); ++ if (!fuel_gauge) { + dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n", + desc->psy_fuel_gauge); + return -ENODEV; +@@ -1788,13 +1831,13 @@ static int charger_manager_probe(struct + cm->charger_psy.num_properties = psy_default.num_properties; + + /* Find which optional psy-properties are available */ +- if (!cm->fuel_gauge->get_property(cm->fuel_gauge, ++ if (!fuel_gauge->get_property(fuel_gauge, + POWER_SUPPLY_PROP_CHARGE_NOW, &val)) { + cm->charger_psy.properties[cm->charger_psy.num_properties] = + POWER_SUPPLY_PROP_CHARGE_NOW; + cm->charger_psy.num_properties++; + } +- if (!cm->fuel_gauge->get_property(cm->fuel_gauge, ++ if (!fuel_gauge->get_property(fuel_gauge, + POWER_SUPPLY_PROP_CURRENT_NOW, + &val)) { + cm->charger_psy.properties[cm->charger_psy.num_properties] = +@@ -1802,7 +1845,7 @@ static int charger_manager_probe(struct + cm->charger_psy.num_properties++; + } + +- ret = cm_init_thermal_data(cm); ++ ret = cm_init_thermal_data(cm, fuel_gauge); + if (ret) { + dev_err(&pdev->dev, "Failed to initialize thermal data\n"); + cm->desc->measure_battery_temp = false; +--- a/include/linux/power/charger-manager.h ++++ b/include/linux/power/charger-manager.h +@@ -253,7 +253,6 @@ struct charger_manager { + struct device *dev; + struct charger_desc *desc; + +- struct power_supply *fuel_gauge; + struct power_supply **charger_stat; + + #ifdef CONFIG_THERMAL diff --git a/queue-3.14/series b/queue-3.14/series index 35ab7b36eeb..e0529d3bc54 100644 --- a/queue-3.14/series +++ b/queue-3.14/series @@ -57,3 +57,16 @@ input-synaptics-add-min-max-quirk-for-lenovo-t440s.patch input-alps-ignore-potential-bare-packets-when-device-is-out-of-sync.patch input-alps-allow-up-to-2-invalid-packets-without-resetting-device.patch input-alps-ignore-bad-data-on-dell-latitudes-e6440-and-e7440.patch +power-charger-manager-fix-accessing-invalidated-power-supply-after-fuel-gauge-unbind.patch +power-charger-manager-fix-accessing-invalidated-power-supply-after-charger-unbind.patch +power-bq2415x_charger-properly-handle-enodev-from-power_supply_get_by_phandle.patch +power-bq2415x_charger-fix-memory-leak-on-dts-parsing-error.patch +x86-microcode-amd-fix-early-ucode-loading-on-32-bit.patch +x86-microcode-amd-fix-ucode-patch-stashing-on-32-bit.patch +x86-kaslr-prevent-.bss-from-overlaping-initrd.patch +md-always-set-recovery_needed-when-clearing-recovery_frozen.patch +nfsv4-ensure-that-we-remove-nfsv4.0-delegations-when-state-has-expired.patch +nfs-don-t-try-to-reclaim-delegation-open-state-if-recovery-failed.patch +nfs-fix-use-of-uninitialized-variable-in-nfs_getattr.patch +nfsv4-fix-races-between-nfs_remove_bad_delegation-and-delegation-return.patch +nfsv4.1-nfs41_clear_delegation_stateid-shouldn-t-trust-nfs_delegated_state.patch diff --git a/queue-3.14/x86-kaslr-prevent-.bss-from-overlaping-initrd.patch b/queue-3.14/x86-kaslr-prevent-.bss-from-overlaping-initrd.patch new file mode 100644 index 00000000000..3f7d4475cc3 --- /dev/null +++ b/queue-3.14/x86-kaslr-prevent-.bss-from-overlaping-initrd.patch @@ -0,0 +1,218 @@ +From e6023367d779060fddc9a52d1f474085b2b36298 Mon Sep 17 00:00:00 2001 +From: Junjie Mao +Date: Fri, 31 Oct 2014 21:40:38 +0800 +Subject: x86, kaslr: Prevent .bss from overlaping initrd + +From: Junjie Mao + +commit e6023367d779060fddc9a52d1f474085b2b36298 upstream. + +When choosing a random address, the current implementation does not take into +account the reversed space for .bss and .brk sections. Thus the relocated kernel +may overlap other components in memory. Here is an example of the overlap from a +x86_64 kernel in qemu (the ranges of physical addresses are presented): + + Physical Address + + 0x0fe00000 --+--------------------+ <-- randomized base + / | relocated kernel | + vmlinux.bin | (from vmlinux.bin) | + 0x1336d000 (an ELF file) +--------------------+-- + \ | | \ + 0x1376d870 --+--------------------+ | + | relocs table | | + 0x13c1c2a8 +--------------------+ .bss and .brk + | | | + 0x13ce6000 +--------------------+ | + | | / + 0x13f77000 | initrd |-- + | | + 0x13fef374 +--------------------+ + +The initrd image will then be overwritten by the memset during early +initialization: + +[ 1.655204] Unpacking initramfs... +[ 1.662831] Initramfs unpacking failed: junk in compressed archive + +This patch prevents the above situation by requiring a larger space when looking +for a random kernel base, so that existing logic can effectively avoids the +overlap. + +[kees: switched to perl to avoid hex translation pain in mawk vs gawk] +[kees: calculated overlap without relocs table] + +Fixes: 82fa9637a2 ("x86, kaslr: Select random position from e820 maps") +Reported-by: Fengguang Wu +Signed-off-by: Junjie Mao +Signed-off-by: Kees Cook +Cc: Josh Triplett +Cc: Matt Fleming +Cc: Ard Biesheuvel +Cc: Vivek Goyal +Cc: Andi Kleen +Link: http://lkml.kernel.org/r/1414762838-13067-1-git-send-email-eternal.n08@gmail.com +Signed-off-by: Thomas Gleixner +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/boot/compressed/Makefile | 4 +++- + arch/x86/boot/compressed/head_32.S | 5 +++-- + arch/x86/boot/compressed/head_64.S | 5 ++++- + arch/x86/boot/compressed/misc.c | 13 ++++++++++--- + arch/x86/boot/compressed/mkpiggy.c | 9 +++++++-- + arch/x86/tools/calc_run_size.pl | 30 ++++++++++++++++++++++++++++++ + 6 files changed, 57 insertions(+), 9 deletions(-) + +--- a/arch/x86/boot/compressed/Makefile ++++ b/arch/x86/boot/compressed/Makefile +@@ -75,8 +75,10 @@ suffix-$(CONFIG_KERNEL_XZ) := xz + suffix-$(CONFIG_KERNEL_LZO) := lzo + suffix-$(CONFIG_KERNEL_LZ4) := lz4 + ++RUN_SIZE = $(shell objdump -h vmlinux | \ ++ perl $(srctree)/arch/x86/tools/calc_run_size.pl) + quiet_cmd_mkpiggy = MKPIGGY $@ +- cmd_mkpiggy = $(obj)/mkpiggy $< > $@ || ( rm -f $@ ; false ) ++ cmd_mkpiggy = $(obj)/mkpiggy $< $(RUN_SIZE) > $@ || ( rm -f $@ ; false ) + + targets += piggy.S + $(obj)/piggy.S: $(obj)/vmlinux.bin.$(suffix-y) $(obj)/mkpiggy FORCE +--- a/arch/x86/boot/compressed/head_32.S ++++ b/arch/x86/boot/compressed/head_32.S +@@ -186,7 +186,8 @@ relocated: + * Do the decompression, and jump to the new kernel.. + */ + /* push arguments for decompress_kernel: */ +- pushl $z_output_len /* decompressed length */ ++ pushl $z_run_size /* size of kernel with .bss and .brk */ ++ pushl $z_output_len /* decompressed length, end of relocs */ + leal z_extract_offset_negative(%ebx), %ebp + pushl %ebp /* output address */ + pushl $z_input_len /* input_len */ +@@ -196,7 +197,7 @@ relocated: + pushl %eax /* heap area */ + pushl %esi /* real mode pointer */ + call decompress_kernel /* returns kernel location in %eax */ +- addl $24, %esp ++ addl $28, %esp + + /* + * Jump to the decompressed kernel. +--- a/arch/x86/boot/compressed/head_64.S ++++ b/arch/x86/boot/compressed/head_64.S +@@ -334,13 +334,16 @@ relocated: + * Do the decompression, and jump to the new kernel.. + */ + pushq %rsi /* Save the real mode argument */ ++ movq $z_run_size, %r9 /* size of kernel with .bss and .brk */ ++ pushq %r9 + movq %rsi, %rdi /* real mode address */ + leaq boot_heap(%rip), %rsi /* malloc area for uncompression */ + leaq input_data(%rip), %rdx /* input_data */ + movl $z_input_len, %ecx /* input_len */ + movq %rbp, %r8 /* output target address */ +- movq $z_output_len, %r9 /* decompressed length */ ++ movq $z_output_len, %r9 /* decompressed length, end of relocs */ + call decompress_kernel /* returns kernel location in %rax */ ++ popq %r9 + popq %rsi + + /* +--- a/arch/x86/boot/compressed/misc.c ++++ b/arch/x86/boot/compressed/misc.c +@@ -393,7 +393,8 @@ asmlinkage void *decompress_kernel(void + unsigned char *input_data, + unsigned long input_len, + unsigned char *output, +- unsigned long output_len) ++ unsigned long output_len, ++ unsigned long run_size) + { + real_mode = rmode; + +@@ -416,8 +417,14 @@ asmlinkage void *decompress_kernel(void + free_mem_ptr = heap; /* Heap */ + free_mem_end_ptr = heap + BOOT_HEAP_SIZE; + +- output = choose_kernel_location(input_data, input_len, +- output, output_len); ++ /* ++ * The memory hole needed for the kernel is the larger of either ++ * the entire decompressed kernel plus relocation table, or the ++ * entire decompressed kernel plus .bss and .brk sections. ++ */ ++ output = choose_kernel_location(input_data, input_len, output, ++ output_len > run_size ? output_len ++ : run_size); + + /* Validate memory location choices. */ + if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1)) +--- a/arch/x86/boot/compressed/mkpiggy.c ++++ b/arch/x86/boot/compressed/mkpiggy.c +@@ -36,11 +36,13 @@ int main(int argc, char *argv[]) + uint32_t olen; + long ilen; + unsigned long offs; ++ unsigned long run_size; + FILE *f = NULL; + int retval = 1; + +- if (argc < 2) { +- fprintf(stderr, "Usage: %s compressed_file\n", argv[0]); ++ if (argc < 3) { ++ fprintf(stderr, "Usage: %s compressed_file run_size\n", ++ argv[0]); + goto bail; + } + +@@ -74,6 +76,7 @@ int main(int argc, char *argv[]) + offs += olen >> 12; /* Add 8 bytes for each 32K block */ + offs += 64*1024 + 128; /* Add 64K + 128 bytes slack */ + offs = (offs+4095) & ~4095; /* Round to a 4K boundary */ ++ run_size = atoi(argv[2]); + + printf(".section \".rodata..compressed\",\"a\",@progbits\n"); + printf(".globl z_input_len\n"); +@@ -85,6 +88,8 @@ int main(int argc, char *argv[]) + /* z_extract_offset_negative allows simplification of head_32.S */ + printf(".globl z_extract_offset_negative\n"); + printf("z_extract_offset_negative = -0x%lx\n", offs); ++ printf(".globl z_run_size\n"); ++ printf("z_run_size = %lu\n", run_size); + + printf(".globl input_data, input_data_end\n"); + printf("input_data:\n"); +--- /dev/null ++++ b/arch/x86/tools/calc_run_size.pl +@@ -0,0 +1,30 @@ ++#!/usr/bin/perl ++# ++# Calculate the amount of space needed to run the kernel, including room for ++# the .bss and .brk sections. ++# ++# Usage: ++# objdump -h a.out | perl calc_run_size.pl ++use strict; ++ ++my $mem_size = 0; ++my $file_offset = 0; ++ ++my $sections=" *[0-9]+ \.(?:bss|brk) +"; ++while (<>) { ++ if (/^$sections([0-9a-f]+) +(?:[0-9a-f]+ +){2}([0-9a-f]+)/) { ++ my $size = hex($1); ++ my $offset = hex($2); ++ $mem_size += $size; ++ if ($file_offset == 0) { ++ $file_offset = $offset; ++ } elsif ($file_offset != $offset) { ++ die ".bss and .brk lack common file offset\n"; ++ } ++ } ++} ++ ++if ($file_offset == 0) { ++ die "Never found .bss or .brk file offset\n"; ++} ++printf("%d\n", $mem_size + $file_offset); diff --git a/queue-3.14/x86-microcode-amd-fix-early-ucode-loading-on-32-bit.patch b/queue-3.14/x86-microcode-amd-fix-early-ucode-loading-on-32-bit.patch new file mode 100644 index 00000000000..3cf11a1d8b8 --- /dev/null +++ b/queue-3.14/x86-microcode-amd-fix-early-ucode-loading-on-32-bit.patch @@ -0,0 +1,113 @@ +From 4750a0d112cbfcc744929f1530ffe3193436766c Mon Sep 17 00:00:00 2001 +From: Borislav Petkov +Date: Fri, 31 Oct 2014 23:23:43 +0100 +Subject: x86, microcode, AMD: Fix early ucode loading on 32-bit + +From: Borislav Petkov + +commit 4750a0d112cbfcc744929f1530ffe3193436766c upstream. + +Konrad triggered the following splat below in a 32-bit guest on an AMD +box. As it turns out, in save_microcode_in_initrd_amd() we're using the +*physical* address of the container *after* we have enabled paging and +thus we #PF in load_microcode_amd() when trying to access the microcode +container in the ramdisk range. + +Because the ramdisk is exactly there: + +[ 0.000000] RAMDISK: [mem 0x35e04000-0x36ef9fff] + +and we fault at 0x35e04304. + +And since this guest doesn't relocate the ramdisk, we don't do the +computation which will give us the correct virtual address and we end up +with the PA. + +So, we should actually be using virtual addresses on 32-bit too by the +time we're freeing the initrd. Do that then! + +Unpacking initramfs... +BUG: unable to handle kernel paging request at 35d4e304 +IP: [] load_microcode_amd+0x25/0x4a0 +*pde = 00000000 +Oops: 0000 [#1] SMP +Modules linked in: +CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.17.1-302.fc21.i686 #1 +Hardware name: Xen HVM domU, BIOS 4.4.1 10/01/2014 +task: f5098000 ti: f50d0000 task.ti: f50d0000 +EIP: 0060:[] EFLAGS: 00010246 CPU: 0 +EIP is at load_microcode_amd+0x25/0x4a0 +EAX: 00000000 EBX: f6e9ec4c ECX: 00001ec4 EDX: 00000000 +ESI: f5d4e000 EDI: 35d4e2fc EBP: f50d1ed0 ESP: f50d1e94 + DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 +CR0: 8005003b CR2: 35d4e304 CR3: 00e33000 CR4: 000406d0 +Stack: + 00000000 00000000 f50d1ebc f50d1ec4 f5d4e000 c0d7735a f50d1ed0 15a3d17f + f50d1ec4 00600f20 00001ec4 bfb83203 f6e9ec4c f5d4e000 c0d7735a f50d1ed8 + c0d80861 f50d1ee0 c0d80429 f50d1ef0 c0d889a9 f5d4e000 c0000000 f50d1f04 +Call Trace: +? unpack_to_rootfs +? unpack_to_rootfs +save_microcode_in_initrd_amd +save_microcode_in_initrd +free_initrd_mem +populate_rootfs +? unpack_to_rootfs +do_one_initcall +? unpack_to_rootfs +? repair_env_string +? proc_mkdir +kernel_init_freeable +kernel_init +ret_from_kernel_thread +? rest_init + +Reported-and-tested-by: Konrad Rzeszutek Wilk +References: https://bugzilla.redhat.com/show_bug.cgi?id=1158204 +Fixes: 75a1ba5b2c52 ("x86, microcode, AMD: Unify valid container checks") +Signed-off-by: Borislav Petkov +Link: http://lkml.kernel.org/r/20141101100100.GA4462@pd.tnic +Signed-off-by: Thomas Gleixner +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kernel/cpu/microcode/amd_early.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/amd_early.c ++++ b/arch/x86/kernel/cpu/microcode/amd_early.c +@@ -348,6 +348,7 @@ int __init save_microcode_in_initrd_amd( + { + unsigned long cont; + enum ucode_state ret; ++ u8 *cont_va; + u32 eax; + + if (!container) +@@ -355,13 +356,15 @@ int __init save_microcode_in_initrd_amd( + + #ifdef CONFIG_X86_32 + get_bsp_sig(); +- cont = (unsigned long)container; ++ cont = (unsigned long)container; ++ cont_va = __va(container); + #else + /* + * We need the physical address of the container for both bitness since + * boot_params.hdr.ramdisk_image is a physical address. + */ +- cont = __pa(container); ++ cont = __pa(container); ++ cont_va = container; + #endif + + /* +@@ -372,6 +375,8 @@ int __init save_microcode_in_initrd_amd( + if (relocated_ramdisk) + container = (u8 *)(__va(relocated_ramdisk) + + (cont - boot_params.hdr.ramdisk_image)); ++ else ++ container = cont_va; + + if (ucode_new_rev) + pr_info("microcode: updated early to new patch_level=0x%08x\n", diff --git a/queue-3.14/x86-microcode-amd-fix-ucode-patch-stashing-on-32-bit.patch b/queue-3.14/x86-microcode-amd-fix-ucode-patch-stashing-on-32-bit.patch new file mode 100644 index 00000000000..c4c6069f2af --- /dev/null +++ b/queue-3.14/x86-microcode-amd-fix-ucode-patch-stashing-on-32-bit.patch @@ -0,0 +1,128 @@ +From c0a717f23dccdb6e3b03471bc846fdc636f2b353 Mon Sep 17 00:00:00 2001 +From: Borislav Petkov +Date: Wed, 5 Nov 2014 17:42:42 +0100 +Subject: x86, microcode, AMD: Fix ucode patch stashing on 32-bit + +From: Borislav Petkov + +commit c0a717f23dccdb6e3b03471bc846fdc636f2b353 upstream. + +Save the patch while we're running on the BSP instead of later, before +the initrd has been jettisoned. More importantly, on 32-bit we need to +access the physical address instead of the virtual. + +This way we actually do find it on the APs instead of having to go +through the initrd each time. + +Tested-by: Richard Hendershot +Fixes: 5335ba5cf475 ("x86, microcode, AMD: Fix early ucode loading") +Signed-off-by: Borislav Petkov +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kernel/cpu/microcode/amd_early.c | 24 ++++++++++++++---------- + 1 file changed, 14 insertions(+), 10 deletions(-) + +--- a/arch/x86/kernel/cpu/microcode/amd_early.c ++++ b/arch/x86/kernel/cpu/microcode/amd_early.c +@@ -108,12 +108,13 @@ static size_t compute_container_size(u8 + * load_microcode_amd() to save equivalent cpu table and microcode patches in + * kernel heap memory. + */ +-static void apply_ucode_in_initrd(void *ucode, size_t size) ++static void apply_ucode_in_initrd(void *ucode, size_t size, bool save_patch) + { + struct equiv_cpu_entry *eq; + size_t *cont_sz; + u32 *header; + u8 *data, **cont; ++ u8 (*patch)[PATCH_MAX_SIZE]; + u16 eq_id = 0; + int offset, left; + u32 rev, eax, ebx, ecx, edx; +@@ -123,10 +124,12 @@ static void apply_ucode_in_initrd(void * + new_rev = (u32 *)__pa_nodebug(&ucode_new_rev); + cont_sz = (size_t *)__pa_nodebug(&container_size); + cont = (u8 **)__pa_nodebug(&container); ++ patch = (u8 (*)[PATCH_MAX_SIZE])__pa_nodebug(&amd_ucode_patch); + #else + new_rev = &ucode_new_rev; + cont_sz = &container_size; + cont = &container; ++ patch = &amd_ucode_patch; + #endif + + data = ucode; +@@ -213,9 +216,9 @@ static void apply_ucode_in_initrd(void * + rev = mc->hdr.patch_id; + *new_rev = rev; + +- /* save ucode patch */ +- memcpy(amd_ucode_patch, mc, +- min_t(u32, header[1], PATCH_MAX_SIZE)); ++ if (save_patch) ++ memcpy(patch, mc, ++ min_t(u32, header[1], PATCH_MAX_SIZE)); + } + } + +@@ -246,7 +249,7 @@ void __init load_ucode_amd_bsp(void) + *data = cp.data; + *size = cp.size; + +- apply_ucode_in_initrd(cp.data, cp.size); ++ apply_ucode_in_initrd(cp.data, cp.size, true); + } + + #ifdef CONFIG_X86_32 +@@ -263,7 +266,7 @@ void load_ucode_amd_ap(void) + size_t *usize; + void **ucode; + +- mc = (struct microcode_amd *)__pa(amd_ucode_patch); ++ mc = (struct microcode_amd *)__pa_nodebug(amd_ucode_patch); + if (mc->hdr.patch_id && mc->hdr.processor_rev_id) { + __apply_microcode_amd(mc); + return; +@@ -275,7 +278,7 @@ void load_ucode_amd_ap(void) + if (!*ucode || !*usize) + return; + +- apply_ucode_in_initrd(*ucode, *usize); ++ apply_ucode_in_initrd(*ucode, *usize, false); + } + + static void __init collect_cpu_sig_on_bsp(void *arg) +@@ -339,7 +342,7 @@ void load_ucode_amd_ap(void) + * AP has a different equivalence ID than BSP, looks like + * mixed-steppings silicon so go through the ucode blob anew. + */ +- apply_ucode_in_initrd(ucode_cpio.data, ucode_cpio.size); ++ apply_ucode_in_initrd(ucode_cpio.data, ucode_cpio.size, false); + } + } + #endif +@@ -347,6 +350,7 @@ void load_ucode_amd_ap(void) + int __init save_microcode_in_initrd_amd(void) + { + unsigned long cont; ++ int retval = 0; + enum ucode_state ret; + u8 *cont_va; + u32 eax; +@@ -387,7 +391,7 @@ int __init save_microcode_in_initrd_amd( + + ret = load_microcode_amd(eax, container, container_size); + if (ret != UCODE_OK) +- return -EINVAL; ++ retval = -EINVAL; + + /* + * This will be freed any msec now, stash patches for the current +@@ -396,5 +400,5 @@ int __init save_microcode_in_initrd_amd( + container = NULL; + container_size = 0; + +- return 0; ++ return retval; + }