kernel: don't export parse_mtd_partitions_by_type() in 4.9 and 4.14
[oweals/openwrt.git] / target / linux / generic / pending-4.9 / 411-mtd-partial_eraseblock_write.patch
1 From: Felix Fietkau <nbd@nbd.name>
2 Subject: mtd: implement write support for partitions covering only a part of an eraseblock (buffer data that would otherwise be erased)
3
4 lede-commit: 87a8e8ac1067f58ba831c4aae443f3655c31cd80
5 Signed-off-by: Felix Fietkau <nbd@nbd.name>
6 ---
7  drivers/mtd/mtdpart.c   | 90 ++++++++++++++++++++++++++++++++++++++++++++-----
8  include/linux/mtd/mtd.h |  4 +++
9  2 files changed, 85 insertions(+), 9 deletions(-)
10
11 --- a/drivers/mtd/mtdpart.c
12 +++ b/drivers/mtd/mtdpart.c
13 @@ -37,6 +37,8 @@
14  #include "mtdcore.h"
15  #include "mtdsplit/mtdsplit.h"
16  
17 +#define MTD_ERASE_PARTIAL      0x8000 /* partition only covers parts of an erase block */
18 +
19  /* Our partition linked list */
20  static LIST_HEAD(mtd_partitions);
21  static DEFINE_MUTEX(mtd_partitions_mutex);
22 @@ -246,13 +248,61 @@ static int part_erase(struct mtd_info *m
23         struct mtd_part *part = mtd_to_part(mtd);
24         int ret;
25  
26 +
27 +       instr->partial_start = false;
28 +       if (mtd->flags & MTD_ERASE_PARTIAL) {
29 +               size_t readlen = 0;
30 +               u64 mtd_ofs;
31 +
32 +               instr->erase_buf = kmalloc(part->parent->erasesize, GFP_ATOMIC);
33 +               if (!instr->erase_buf)
34 +                       return -ENOMEM;
35 +
36 +               mtd_ofs = part->offset + instr->addr;
37 +               instr->erase_buf_ofs = do_div(mtd_ofs, part->parent->erasesize);
38 +
39 +               if (instr->erase_buf_ofs > 0) {
40 +                       instr->addr -= instr->erase_buf_ofs;
41 +                       ret = mtd_read(part->parent,
42 +                               instr->addr + part->offset,
43 +                               part->parent->erasesize,
44 +                               &readlen, instr->erase_buf);
45 +
46 +                       instr->len += instr->erase_buf_ofs;
47 +                       instr->partial_start = true;
48 +               } else {
49 +                       mtd_ofs = part->offset + part->mtd.size;
50 +                       instr->erase_buf_ofs = part->parent->erasesize -
51 +                               do_div(mtd_ofs, part->parent->erasesize);
52 +
53 +                       if (instr->erase_buf_ofs > 0) {
54 +                               instr->len += instr->erase_buf_ofs;
55 +                               ret = mtd_read(part->parent,
56 +                                       part->offset + instr->addr +
57 +                                       instr->len - part->parent->erasesize,
58 +                                       part->parent->erasesize, &readlen,
59 +                                       instr->erase_buf);
60 +                       } else {
61 +                               ret = 0;
62 +                       }
63 +               }
64 +               if (ret < 0) {
65 +                       kfree(instr->erase_buf);
66 +                       return ret;
67 +               }
68 +
69 +       }
70 +
71         instr->addr += part->offset;
72         ret = part->parent->_erase(part->parent, instr);
73         if (ret) {
74                 if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
75                         instr->fail_addr -= part->offset;
76                 instr->addr -= part->offset;
77 +               if (mtd->flags & MTD_ERASE_PARTIAL)
78 +                       kfree(instr->erase_buf);
79         }
80 +
81         return ret;
82  }
83  
84 @@ -260,6 +310,25 @@ void mtd_erase_callback(struct erase_inf
85  {
86         if (instr->mtd->_erase == part_erase) {
87                 struct mtd_part *part = mtd_to_part(instr->mtd);
88 +               size_t wrlen = 0;
89 +
90 +               if (instr->mtd->flags & MTD_ERASE_PARTIAL) {
91 +                       if (instr->partial_start) {
92 +                               part->parent->_write(part->parent,
93 +                                       instr->addr, instr->erase_buf_ofs,
94 +                                       &wrlen, instr->erase_buf);
95 +                               instr->addr += instr->erase_buf_ofs;
96 +                       } else {
97 +                               instr->len -= instr->erase_buf_ofs;
98 +                               part->parent->_write(part->parent,
99 +                                       instr->addr + instr->len,
100 +                                       instr->erase_buf_ofs, &wrlen,
101 +                                       instr->erase_buf +
102 +                                       part->parent->erasesize -
103 +                                       instr->erase_buf_ofs);
104 +                       }
105 +                       kfree(instr->erase_buf);
106 +               }
107  
108                 if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
109                         instr->fail_addr -= part->offset;
110 @@ -566,19 +635,22 @@ static struct mtd_part *allocate_partiti
111         remainder = do_div(tmp, wr_alignment);
112         if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
113                 /* Doesn't start on a boundary of major erase size */
114 -               /* FIXME: Let it be writable if it is on a boundary of
115 -                * _minor_ erase size though */
116 -               slave->mtd.flags &= ~MTD_WRITEABLE;
117 -               printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n",
118 -                       part->name);
119 +               slave->mtd.flags |= MTD_ERASE_PARTIAL;
120 +               if (((u32)slave->mtd.size) > parent->erasesize)
121 +                       slave->mtd.flags &= ~MTD_WRITEABLE;
122 +               else
123 +                       slave->mtd.erasesize = slave->mtd.size;
124         }
125  
126 -       tmp = slave->mtd.size;
127 +       tmp = slave->offset + slave->mtd.size;
128         remainder = do_div(tmp, wr_alignment);
129         if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
130 -               slave->mtd.flags &= ~MTD_WRITEABLE;
131 -               printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n",
132 -                       part->name);
133 +               slave->mtd.flags |= MTD_ERASE_PARTIAL;
134 +
135 +               if ((u32)slave->mtd.size > parent->erasesize)
136 +                       slave->mtd.flags &= ~MTD_WRITEABLE;
137 +               else
138 +                       slave->mtd.erasesize = slave->mtd.size;
139         }
140  
141         mtd_set_ooblayout(&slave->mtd, &part_ooblayout_ops);
142 --- a/include/linux/mtd/mtd.h
143 +++ b/include/linux/mtd/mtd.h
144 @@ -55,6 +55,10 @@ struct erase_info {
145         u_long priv;
146         u_char state;
147         struct erase_info *next;
148 +
149 +       u8 *erase_buf;
150 +       u32 erase_buf_ofs;
151 +       bool partial_start;
152  };
153  
154  struct mtd_erase_region_info {