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