kernel: reorganize 2.6.37 patches
[openwrt.git] / target / linux / generic / patches-2.6.37 / 441-block2mtd_refresh.patch
1 --- a/drivers/mtd/devices/block2mtd.c
2 +++ b/drivers/mtd/devices/block2mtd.c
3 @@ -30,6 +30,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 @@ -82,6 +84,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 @@ -93,6 +101,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 @@ -104,10 +116,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 @@ -122,10 +138,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 @@ -136,7 +156,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 @@ -188,12 +211,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 @@ -202,6 +235,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 @@ -210,52 +246,29 @@ 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 -       sync_blockdev(dev->blkdev);
127 -       return;
128 -}
129 -
130 -
131 -static void block2mtd_free_device(struct block2mtd_dev *dev)
132 -{
133 -       if (!dev)
134 -               return;
135 -
136 -       kfree(dev->mtd.name);
137  
138 -       if (dev->blkdev) {
139 -               invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping,
140 -                                       0, -1);
141 -               close_bdev_exclusive(dev->blkdev, FMODE_READ|FMODE_WRITE);
142 -       }
143 +       read_lock(&dev->bdev_mutex);
144 +       if (dev->blkdev)
145 +               sync_blockdev(dev->blkdev);
146 +       read_unlock(&dev->bdev_mutex);
147  
148 -       kfree(dev);
149 +       return;
150  }
151  
152  
153 -/* FIXME: ensure that mtd->size % erase_size == 0 */
154 -static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname)
155 +static int _open_bdev(struct block2mtd_dev *dev)
156  {
157         struct block_device *bdev;
158 -       struct block2mtd_dev *dev;
159 -       struct mtd_partition *part;
160 -       char *name;
161 -
162 -       if (!devname)
163 -               return NULL;
164 -
165 -       dev = kzalloc(sizeof(struct block2mtd_dev), GFP_KERNEL);
166 -       if (!dev)
167 -               return NULL;
168  
169         /* Get a handle on the device */
170 -       bdev = open_bdev_exclusive(devname, FMODE_READ|FMODE_WRITE, NULL);
171 +       bdev = open_bdev_exclusive(dev->devname, FMODE_READ|FMODE_WRITE, NULL);
172  #ifndef MODULE
173         if (IS_ERR(bdev)) {
174  
175                 /* We might not have rootfs mounted at this point. Try
176                    to resolve the device name by other means. */
177  
178 -               dev_t devt = name_to_dev_t(devname);
179 +               dev_t devt = name_to_dev_t(dev->devname);
180                 if (devt) {
181                         bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ);
182                 }
183 @@ -263,17 +276,98 @@ static struct block2mtd_dev *add_device(
184  #endif
185  
186         if (IS_ERR(bdev)) {
187 -               ERROR("error: cannot open device %s", devname);
188 -               goto devinit_err;
189 +               ERROR("error: cannot open device %s", dev->devname);
190 +               return 1;
191         }
192         dev->blkdev = bdev;
193  
194         if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
195                 ERROR("attempting to use an MTD device as a block device");
196 -               goto devinit_err;
197 +               return 1;
198         }
199  
200 +       return 0;
201 +}
202 +
203 +static void _close_bdev(struct block2mtd_dev *dev)
204 +{
205 +       struct block_device *bdev;
206 +
207 +       if (!dev->blkdev)
208 +               return;
209 +
210 +       bdev = dev->blkdev;
211 +       invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping, 0, -1);
212 +       close_bdev_exclusive(dev->blkdev, FMODE_READ|FMODE_WRITE);
213 +       dev->blkdev = NULL;
214 +}
215 +
216 +static void block2mtd_free_device(struct block2mtd_dev *dev)
217 +{
218 +       if (!dev)
219 +               return;
220 +
221 +       kfree(dev->mtd.name);
222 +       _close_bdev(dev);
223 +       kfree(dev);
224 +}
225 +
226 +
227 +static int block2mtd_refresh(struct mtd_info *mtd)
228 +{
229 +       struct block2mtd_dev *dev = mtd->priv;
230 +       struct block_device *bdev;
231 +       dev_t devt;
232 +       int err = 0;
233 +
234 +       /* no other mtd function can run at this point */
235 +       write_lock(&dev->bdev_mutex);
236 +
237 +       /* get the device number for the whole disk */
238 +       devt = MKDEV(MAJOR(dev->blkdev->bd_dev), 0);
239 +
240 +       /* close the old block device */
241 +       _close_bdev(dev);
242 +
243 +       /* open the whole disk, issue a partition rescan, then */
244 +       bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ);
245 +       if (!bdev || !bdev->bd_disk)
246 +               err = -EINVAL;
247 +#ifndef CONFIG_MTD_BLOCK2MTD_MODULE
248 +       else
249 +               err = rescan_partitions(bdev->bd_disk, bdev);
250 +#endif
251 +       if (bdev)
252 +               close_bdev_exclusive(bdev, FMODE_READ|FMODE_WRITE);
253 +
254 +       /* try to open the partition block device again */
255 +       _open_bdev(dev);
256 +       write_unlock(&dev->bdev_mutex);
257 +
258 +       return err;
259 +}
260 +
261 +/* FIXME: ensure that mtd->size % erase_size == 0 */
262 +static struct block2mtd_dev *add_device(char *devname, int erase_size, char *mtdname)
263 +{
264 +       struct block2mtd_dev *dev;
265 +       struct mtd_partition *part;
266 +       char *name;
267 +
268 +       if (!devname)
269 +               return NULL;
270 +
271 +       dev = kzalloc(sizeof(struct block2mtd_dev) + strlen(devname) + 1, GFP_KERNEL);
272 +       if (!dev)
273 +               return NULL;
274 +
275 +       strcpy(dev->devname, devname);
276 +
277 +       if (_open_bdev(dev))
278 +               goto devinit_err;
279 +
280         mutex_init(&dev->write_mutex);
281 +       rwlock_init(&dev->bdev_mutex);
282  
283         /* Setup the MTD structure */
284         /* make the name contain the block device in */
285 @@ -298,6 +392,7 @@ static struct block2mtd_dev *add_device(
286         dev->mtd.read = block2mtd_read;
287         dev->mtd.priv = dev;
288         dev->mtd.owner = THIS_MODULE;
289 +       dev->mtd.refresh_device = block2mtd_refresh;
290  
291         part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL);
292         part->name = dev->mtd.name;