kernel: add preliminary support for linux 3.3
[openwrt/svn-archive/archive.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 @@ -297,6 +391,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;