gemini: drop kernel 3.9 support
[openwrt.git] / target / linux / generic / patches-3.9 / 441-block2mtd_refresh.patch
1 --- a/drivers/mtd/devices/block2mtd.c
2 +++ b/drivers/mtd/devices/block2mtd.c
3 @@ -29,6 +29,8 @@ struct block2mtd_dev {
4         struct block_device *blkdev;
5         struct mtd_info mtd;
6         struct mutex write_mutex;
7 +       rwlock_t bdev_mutex;
8 +       char devname[0];
9  };
10  
11  
12 @@ -80,6 +82,12 @@ static int block2mtd_erase(struct mtd_in
13         size_t len = instr->len;
14         int err;
15  
16 +       read_lock(&dev->bdev_mutex);
17 +       if (!dev->blkdev) {
18 +               err = -EINVAL;
19 +               goto done;
20 +       }
21 +
22         instr->state = MTD_ERASING;
23         mutex_lock(&dev->write_mutex);
24         err = _block2mtd_erase(dev, from, len);
25 @@ -91,6 +99,10 @@ static int block2mtd_erase(struct mtd_in
26                 instr->state = MTD_ERASE_DONE;
27  
28         mtd_erase_callback(instr);
29 +
30 +done:
31 +       read_unlock(&dev->bdev_mutex);
32 +
33         return err;
34  }
35  
36 @@ -102,7 +114,13 @@ static int block2mtd_read(struct mtd_inf
37         struct page *page;
38         int index = from >> PAGE_SHIFT;
39         int offset = from & (PAGE_SIZE-1);
40 -       int cpylen;
41 +       int cpylen, err = 0;
42 +
43 +       read_lock(&dev->bdev_mutex);
44 +       if (!dev->blkdev || (from > mtd->size)) {
45 +               err = -EINVAL;
46 +               goto done;
47 +       }
48  
49         while (len) {
50                 if ((offset + len) > PAGE_SIZE)
51 @@ -112,8 +130,10 @@ static int block2mtd_read(struct mtd_inf
52                 len = len - cpylen;
53  
54                 page = page_read(dev->blkdev->bd_inode->i_mapping, index);
55 -               if (IS_ERR(page))
56 -                       return PTR_ERR(page);
57 +               if (IS_ERR(page)) {
58 +                       err = PTR_ERR(page);
59 +                       goto done;
60 +               }
61  
62                 memcpy(buf, page_address(page) + offset, cpylen);
63                 page_cache_release(page);
64 @@ -124,7 +144,10 @@ static int block2mtd_read(struct mtd_inf
65                 offset = 0;
66                 index++;
67         }
68 -       return 0;
69 +
70 +done:
71 +       read_unlock(&dev->bdev_mutex);
72 +       return err;
73  }
74  
75  
76 @@ -173,13 +196,22 @@ static int block2mtd_write(struct mtd_in
77                 size_t *retlen, const u_char *buf)
78  {
79         struct block2mtd_dev *dev = mtd->priv;
80 -       int err;
81 +       int err = 0;
82 +
83 +       read_lock(&dev->bdev_mutex);
84 +       if (!dev->blkdev) {
85 +               err = -EINVAL;
86 +               goto done;
87 +       }
88  
89         mutex_lock(&dev->write_mutex);
90         err = _block2mtd_write(dev, buf, to, len, retlen);
91         mutex_unlock(&dev->write_mutex);
92         if (err > 0)
93                 err = 0;
94 +
95 +done:
96 +       read_unlock(&dev->bdev_mutex);
97         return err;
98  }
99  
100 @@ -188,33 +220,110 @@ static int block2mtd_write(struct mtd_in
101  static void block2mtd_sync(struct mtd_info *mtd)
102  {
103         struct block2mtd_dev *dev = mtd->priv;
104 +       read_lock(&dev->bdev_mutex);
105 +       if (dev->blkdev)
106         sync_blockdev(dev->blkdev);
107 +       read_unlock(&dev->bdev_mutex);
108 +
109         return;
110  }
111  
112  
113 +static int _open_bdev(struct block2mtd_dev *dev)
114 +{
115 +       const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
116 +       struct block_device *bdev;
117 +
118 +       /* Get a handle on the device */
119 +       bdev = blkdev_get_by_path(dev->devname, mode, dev);
120 +#ifndef MODULE
121 +       if (IS_ERR(bdev)) {
122 +               dev_t devt;
123 +
124 +               /* We might not have rootfs mounted at this point. Try
125 +                  to resolve the device name by other means. */
126 +
127 +               devt = name_to_dev_t(dev->devname);
128 +               if (devt)
129 +                       bdev = blkdev_get_by_dev(devt, mode, dev);
130 +       }
131 +#endif
132 +
133 +       if (IS_ERR(bdev)) {
134 +               ERROR("error: cannot open device %s", dev->devname);
135 +               return 1;
136 +       }
137 +       dev->blkdev = bdev;
138 +
139 +       if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
140 +               ERROR("attempting to use an MTD device as a block device");
141 +               return 1;
142 +       }
143 +
144 +       return 0;
145 +}
146 +
147 +static void _close_bdev(struct block2mtd_dev *dev)
148 +{
149 +       struct block_device *bdev;
150 +
151 +       if (!dev->blkdev)
152 +               return;
153 +
154 +       bdev = dev->blkdev;
155 +       invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping, 0, -1);
156 +       blkdev_put(dev->blkdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
157 +       dev->blkdev = NULL;
158 +}
159 +
160  static void block2mtd_free_device(struct block2mtd_dev *dev)
161  {
162         if (!dev)
163                 return;
164  
165         kfree(dev->mtd.name);
166 -
167 -       if (dev->blkdev) {
168 -               invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping,
169 -                                       0, -1);
170 -               blkdev_put(dev->blkdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
171 -       }
172 -
173 +       _close_bdev(dev);
174         kfree(dev);
175  }
176  
177  
178 -/* FIXME: ensure that mtd->size % erase_size == 0 */
179 -static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname)
180 +static int block2mtd_refresh(struct mtd_info *mtd)
181  {
182 -       const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
183 +       struct block2mtd_dev *dev = mtd->priv;
184         struct block_device *bdev;
185 +       dev_t devt;
186 +       int err = 0;
187 +
188 +       /* no other mtd function can run at this point */
189 +       write_lock(&dev->bdev_mutex);
190 +
191 +       /* get the device number for the whole disk */
192 +       devt = MKDEV(MAJOR(dev->blkdev->bd_dev), 0);
193 +
194 +       /* close the old block device */
195 +       _close_bdev(dev);
196 +
197 +       /* open the whole disk, issue a partition rescan, then */
198 +       bdev = blkdev_get_by_dev(devt, FMODE_WRITE | FMODE_READ, mtd);
199 +       if (!bdev || !bdev->bd_disk)
200 +               err = -EINVAL;
201 +#ifndef CONFIG_MTD_BLOCK2MTD_MODULE
202 +       else
203 +               err = rescan_partitions(bdev->bd_disk, bdev);
204 +#endif
205 +       if (bdev)
206 +               blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
207 +
208 +       /* try to open the partition block device again */
209 +       _open_bdev(dev);
210 +       write_unlock(&dev->bdev_mutex);
211 +
212 +       return err;
213 +}
214 +
215 +/* FIXME: ensure that mtd->size % erase_size == 0 */
216 +static struct block2mtd_dev *add_device(char *devname, int erase_size, char *mtdname)
217 +{
218         struct block2mtd_dev *dev;
219         struct mtd_partition *part;
220         char *name;
221 @@ -222,36 +331,17 @@ static struct block2mtd_dev *add_device(
222         if (!devname)
223                 return NULL;
224  
225 -       dev = kzalloc(sizeof(struct block2mtd_dev), GFP_KERNEL);
226 +       dev = kzalloc(sizeof(struct block2mtd_dev) + strlen(devname) + 1, GFP_KERNEL);
227         if (!dev)
228                 return NULL;
229  
230 -       /* Get a handle on the device */
231 -       bdev = blkdev_get_by_path(devname, mode, dev);
232 -#ifndef MODULE
233 -       if (IS_ERR(bdev)) {
234 -
235 -               /* We might not have rootfs mounted at this point. Try
236 -                  to resolve the device name by other means. */
237 -
238 -               dev_t devt = name_to_dev_t(devname);
239 -               if (devt)
240 -                       bdev = blkdev_get_by_dev(devt, mode, dev);
241 -       }
242 -#endif
243 -
244 -       if (IS_ERR(bdev)) {
245 -               ERROR("error: cannot open device %s", devname);
246 -               goto devinit_err;
247 -       }
248 -       dev->blkdev = bdev;
249 +       strcpy(dev->devname, devname);
250  
251 -       if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
252 -               ERROR("attempting to use an MTD device as a block device");
253 +       if (_open_bdev(dev))
254                 goto devinit_err;
255 -       }
256  
257         mutex_init(&dev->write_mutex);
258 +       rwlock_init(&dev->bdev_mutex);
259  
260         /* Setup the MTD structure */
261         /* make the name contain the block device in */
262 @@ -276,6 +366,7 @@ static struct block2mtd_dev *add_device(
263         dev->mtd._read = block2mtd_read;
264         dev->mtd.priv = dev;
265         dev->mtd.owner = THIS_MODULE;
266 +       dev->mtd.refresh_device = block2mtd_refresh;
267  
268         part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL);
269         part->name = name;