diff mbox series

[2/2] mtd: cfi_cmdset_0002: Avoid point less unlocking/locking

Message ID 20180605140710.8624-2-joakim.tjernlund@infinera.com
State Superseded
Headers show
Series [1/2] mtd: cfi_cmdset_0002: fix SEGV unlocking multiple chips | expand

Commit Message

Joakim Tjernlund June 5, 2018, 2:07 p.m. UTC
cfi_ppb_unlock() walks all flash chips when unlocking sectors.
This is a waste when crossing chip boundaris unaffected
by the unlock operation.

Fixes: 1648eaaa1575e
Signed-off-by: Joakim Tjernlund <joakim.tjernlund@infinera.com>
---
 drivers/mtd/chips/cfi_cmdset_0002.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

Comments

Boris Brezillon June 5, 2018, 3:14 p.m. UTC | #1
On Tue,  5 Jun 2018 16:07:10 +0200
Joakim Tjernlund <joakim.tjernlund@infinera.com> wrote:

> cfi_ppb_unlock() walks all flash chips when unlocking sectors.
> This is a waste when crossing chip boundaris unaffected

				      ^ boundaries.

> by the unlock operation.

AFAICT there are 2 unrelated changes in this commit:
1/ Fix the boundary check which is broken if the unlock operation
   crosses a chip boundary (adr is reset to 0 when that happens).
2/ Avoid unlocking chips that are outside the requested unlock range.

#1 is a fix, #2 is not. You should split that in 2 different commits,
and tag #1 with Fixes and Cc-stable.

> 
> Fixes: 1648eaaa1575e
> Signed-off-by: Joakim Tjernlund <joakim.tjernlund@infinera.com>
> ---
>  drivers/mtd/chips/cfi_cmdset_0002.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
> index c74c53b886be..ee8b70e54298 100644
> --- a/drivers/mtd/chips/cfi_cmdset_0002.c
> +++ b/drivers/mtd/chips/cfi_cmdset_0002.c
> @@ -2669,7 +2669,7 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs,
>  		 * sectors shall be unlocked, so lets keep their locking
>  		 * status at "unlocked" (locked=0) for the final re-locking.
>  		 */
> -		if ((adr < ofs) || (adr >= (ofs + len))) {
> +		if ((offset < ofs) || (offset >= (ofs + len))) {
>  			sect[sectors].chip = &cfi->chips[chipnum];
>  			sect[sectors].adr = adr;
>  			sect[sectors].locked = do_ppb_xxlock(
> @@ -2685,6 +2685,8 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs,
>  			i++;
>  
>  		if (adr >> cfi->chipshift) {
> +			if (offset >= (ofs + len))
> +				break;
>  			adr = 0;
>  			chipnum++;
>  			if (chipnum >= cfi->numchips)
Joakim Tjernlund June 5, 2018, 4:57 p.m. UTC | #2
On Tue, 2018-06-05 at 17:14 +0200, Boris Brezillon wrote:
> CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you recognize the sender and know the content is safe.
> 
> 
> On Tue,  5 Jun 2018 16:07:10 +0200
> Joakim Tjernlund <joakim.tjernlund@infinera.com> wrote:
> 
> > cfi_ppb_unlock() walks all flash chips when unlocking sectors.
> > This is a waste when crossing chip boundaris unaffected
> 
>                                       ^ boundaries.
> 
> > by the unlock operation.
> 
> AFAICT there are 2 unrelated changes in this commit:
> 1/ Fix the boundary check which is broken if the unlock operation
>    crosses a chip boundary (adr is reset to 0 when that happens).

not broken, the driver will just relock the same sector needlessly.
I did not notice anything breaking when that happened.
These two changes optimizes the unlock operation.
Still need two commits?

> 2/ Avoid unlocking chips that are outside the requested unlock range.
> 
> #1 is a fix, #2 is not. You should split that in 2 different commits,
> and tag #1 with Fixes and Cc-stable.
> 
> > 
> > Fixes: 1648eaaa1575e
> > Signed-off-by: Joakim Tjernlund <joakim.tjernlund@infinera.com>
> > ---
> >  drivers/mtd/chips/cfi_cmdset_0002.c | 4 +++-
> >  1 file changed, 3 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
> > index c74c53b886be..ee8b70e54298 100644
> > --- a/drivers/mtd/chips/cfi_cmdset_0002.c
> > +++ b/drivers/mtd/chips/cfi_cmdset_0002.c
> > @@ -2669,7 +2669,7 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs,
> >                * sectors shall be unlocked, so lets keep their locking
> >                * status at "unlocked" (locked=0) for the final re-locking.
> >                */
> > -             if ((adr < ofs) || (adr >= (ofs + len))) {
> > +             if ((offset < ofs) || (offset >= (ofs + len))) {
> >                       sect[sectors].chip = &cfi->chips[chipnum];
> >                       sect[sectors].adr = adr;
> >                       sect[sectors].locked = do_ppb_xxlock(
> > @@ -2685,6 +2685,8 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs,
> >                       i++;
> > 
> >               if (adr >> cfi->chipshift) {
> > +                     if (offset >= (ofs + len))
> > +                             break;
> >                       adr = 0;
> >                       chipnum++;
> >                       if (chipnum >= cfi->numchips)
> 
>
Joakim Tjernlund June 6, 2018, 10:15 a.m. UTC | #3
On Tue, 2018-06-05 at 18:57 +0200, Joakim Tjernlund wrote:
> On Tue, 2018-06-05 at 17:14 +0200, Boris Brezillon wrote:
> > CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you recognize the sender and know the content is safe.
> > 
> > 
> > On Tue,  5 Jun 2018 16:07:10 +0200
> > Joakim Tjernlund <joakim.tjernlund@infinera.com> wrote:
> > 
> > > cfi_ppb_unlock() walks all flash chips when unlocking sectors.
> > > This is a waste when crossing chip boundaris unaffected
> > 
> >                                       ^ boundaries.
> > 
> > > by the unlock operation.
> > 
> > AFAICT there are 2 unrelated changes in this commit:
> > 1/ Fix the boundary check which is broken if the unlock operation
> >    crosses a chip boundary (adr is reset to 0 when that happens).
> 
> not broken, the driver will just relock the same sector needlessly.
> I did not notice anything breaking when that happened.
> These two changes optimizes the unlock operation.
> Still need two commits?

I just assumed you did and reset both patches split up into 4.

 Jocke
Joakim Tjernlund June 19, 2018, 5:23 p.m. UTC | #4
On Wed, 2018-06-06 at 12:15 +0200, Joakim Tjernlund wrote:
> On Tue, 2018-06-05 at 18:57 +0200, Joakim Tjernlund wrote:
> > On Tue, 2018-06-05 at 17:14 +0200, Boris Brezillon wrote:
> > > CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you recognize the sender and know the content is safe.
> > > 
> > > 
> > > On Tue,  5 Jun 2018 16:07:10 +0200
> > > Joakim Tjernlund <joakim.tjernlund@infinera.com> wrote:
> > > 
> > > > cfi_ppb_unlock() walks all flash chips when unlocking sectors.
> > > > This is a waste when crossing chip boundaris unaffected
> > > 
> > >                                       ^ boundaries.
> > > 
> > > > by the unlock operation.
> > > 
> > > AFAICT there are 2 unrelated changes in this commit:
> > > 1/ Fix the boundary check which is broken if the unlock operation
> > >    crosses a chip boundary (adr is reset to 0 when that happens).
> > 
> > not broken, the driver will just relock the same sector needlessly.
> > I did not notice anything breaking when that happened.
> > These two changes optimizes the unlock operation.
> > Still need two commits?
> 
> I just assumed you did and reset both patches split up into 4.
> 
>  Jocke

Did this get lost? It is a somewhat nasty bug when it hits, you get(and then kernel freezes):

[   38.462607] Unable to handle kernel paging request for data at address 0xd91a0000
[   38.470082] Faulting instruction address: 0xc01b6fec
[   38.475040] Oops: Kernel access of bad area, sig: 11 [#1]
[   38.480418] TMCUTU
[   38.482426] Modules linked in:
[   38.485493] CPU: 0 PID: 437 Comm: fw_setenv Not tainted 4.1.43+ #38
[   38.491748] task: cec0e070 ti: cf8c8000 task.ti: cf8c8000
[   38.497133] NIP: c01b6fec LR: c01b0b04 CTR: c01b6fe4
[   38.502087] REGS: cf8c9c20 TRAP: 0300   Not tainted  (4.1.43+)
[   38.507899] MSR: 00009032 <EE,ME,IR,DR,RI>  CR: 22022428  XER: 20000000
[   38.514539] DAR: d91a0000 DSISR: 22000000 
GPR00: c01b07ec cf8c9cd0 cec0e070 cf89a21c cf8c9cd8 080a0000 0000000f 00000001 
GPR08: c01b6fe4 d1100000 000000a0 04000000 22022422 1001b704 000003ff 00000002 
GPR16: 00000000 04000000 00000002 cec43090 00000000 00020000 00000000 00020000 
GPR24: 00000000 cf8c9cd8 cf93f288 00000001 cf93f200 040a0000 cf89a21c cf93f2a4 
[   38.546903] NIP [c01b6fec] simple_map_write+0x8/0x14
[   38.551882] LR [c01b0b04] do_ppb_xxlock+0x360/0x468
[   38.556743] Call Trace:
[   38.559202] [cf8c9cd0] [c01b07ec] do_ppb_xxlock+0x48/0x468 (unreliable)
[   38.565817] [cf8c9d00] [c01b0e74] cfi_ppb_unlock+0x268/0x360
[   38.571474] [cf8c9d90] [c01a87c4] mtdchar_ioctl+0x750/0x112c
[   38.577131] [cf8c9eb0] [c01a91dc] mtdchar_unlocked_ioctl+0x3c/0x60
[   38.583304] [cf8c9ed0] [c00c3948] do_vfs_ioctl+0x3a4/0x658
[   38.588784] [cf8c9f20] [c00c3c3c] SyS_ioctl+0x40/0x74
[   38.593847] [cf8c9f40] [c000e564] ret_from_syscall+0x0/0x38
[   38.599415] --- interrupt: c01 at 0xff502f8
[   38.599415]     LR = 0xffeca78
[   38.606616] Instruction dump:
[   38.609579] 813c0004 7fe3fb78 913f000c 39200000 913f0008 4bffff2c 8124000c 7d292a2e 
[   38.617343] 91230000 4e800020 a1440002 8123000c <7d492b2e> 7c0004ac 4e800020 81230018 
[   38.625288] ---[ end trace d5c466b3bd564140 ]---
diff mbox series

Patch

diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index c74c53b886be..ee8b70e54298 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -2669,7 +2669,7 @@  static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs,
 		 * sectors shall be unlocked, so lets keep their locking
 		 * status at "unlocked" (locked=0) for the final re-locking.
 		 */
-		if ((adr < ofs) || (adr >= (ofs + len))) {
+		if ((offset < ofs) || (offset >= (ofs + len))) {
 			sect[sectors].chip = &cfi->chips[chipnum];
 			sect[sectors].adr = adr;
 			sect[sectors].locked = do_ppb_xxlock(
@@ -2685,6 +2685,8 @@  static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs,
 			i++;
 
 		if (adr >> cfi->chipshift) {
+			if (offset >= (ofs + len))
+				break;
 			adr = 0;
 			chipnum++;
 			if (chipnum >= cfi->numchips)