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