aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/ubi
diff options
context:
space:
mode:
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2007-12-17 10:37:26 -0500
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2007-12-26 12:15:17 -0500
commite73f4459d969bb266f03dd4cbe21bdba8cb2732c (patch)
tree5af7655da65f2c33f6ea4efdfaa8b0e0670d6aea /drivers/mtd/ubi
parent9f961b57568960a150cc9781c52824c9093a0514 (diff)
UBI: add UBI devices reference counting
This is one more step on the way to "removable" UBI devices. It adds reference counting for UBI devices. Every time a volume on this device is opened - the device's refcount is increased. It is also increased if someone is reading any sysfs file of this UBI device or of one of its volumes. Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'drivers/mtd/ubi')
-rw-r--r--drivers/mtd/ubi/build.c142
-rw-r--r--drivers/mtd/ubi/cdev.c34
-rw-r--r--drivers/mtd/ubi/eba.c5
-rw-r--r--drivers/mtd/ubi/kapi.c59
-rw-r--r--drivers/mtd/ubi/ubi.h9
-rw-r--r--drivers/mtd/ubi/vmt.c14
-rw-r--r--drivers/mtd/ubi/wl.c1
7 files changed, 201 insertions, 63 deletions
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 3f37b16f877..a4faf71ee3f 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -64,9 +64,6 @@ static int mtd_devs = 0;
64/* MTD devices specification parameters */ 64/* MTD devices specification parameters */
65static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES]; 65static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES];
66 66
67/* All UBI devices in system */
68struct ubi_device *ubi_devices[UBI_MAX_DEVICES];
69
70/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */ 67/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
71struct class *ubi_class; 68struct class *ubi_class;
72 69
@@ -83,6 +80,12 @@ static struct miscdevice ubi_ctrl_cdev = {
83 .fops = &ubi_ctrl_cdev_operations, 80 .fops = &ubi_ctrl_cdev_operations,
84}; 81};
85 82
83/* All UBI devices in system */
84static struct ubi_device *ubi_devices[UBI_MAX_DEVICES];
85
86/* Protects @ubi_devices and @ubi->ref_count */
87static DEFINE_SPINLOCK(ubi_devices_lock);
88
86/* "Show" method for files in '/<sysfs>/class/ubi/' */ 89/* "Show" method for files in '/<sysfs>/class/ubi/' */
87static ssize_t ubi_version_show(struct class *class, char *buf) 90static ssize_t ubi_version_show(struct class *class, char *buf)
88{ 91{
@@ -118,37 +121,145 @@ static struct device_attribute dev_min_io_size =
118static struct device_attribute dev_bgt_enabled = 121static struct device_attribute dev_bgt_enabled =
119 __ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL); 122 __ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL);
120 123
124/**
125 * ubi_get_device - get UBI device.
126 * @ubi_num: UBI device number
127 *
128 * This function returns UBI device description object for UBI device number
129 * @ubi_num, or %NULL if the device does not exist. This function increases the
130 * device reference count to prevent removal of the device. In other words, the
131 * device cannot be removed if its reference count is not zero.
132 */
133struct ubi_device *ubi_get_device(int ubi_num)
134{
135 struct ubi_device *ubi;
136
137 spin_lock(&ubi_devices_lock);
138 ubi = ubi_devices[ubi_num];
139 if (ubi) {
140 ubi_assert(ubi->ref_count >= 0);
141 ubi->ref_count += 1;
142 get_device(&ubi->dev);
143 }
144 spin_unlock(&ubi_devices_lock);
145
146 return ubi;
147}
148
149/**
150 * ubi_put_device - drop an UBI device reference.
151 * @ubi: UBI device description object
152 */
153void ubi_put_device(struct ubi_device *ubi)
154{
155 spin_lock(&ubi_devices_lock);
156 ubi->ref_count -= 1;
157 put_device(&ubi->dev);
158 spin_unlock(&ubi_devices_lock);
159}
160
161/**
162 * ubi_get_by_major - get UBI device description object by character device
163 * major number.
164 * @major: major number
165 *
166 * This function is similar to 'ubi_get_device()', but it searches the device
167 * by its major number.
168 */
169struct ubi_device *ubi_get_by_major(int major)
170{
171 int i;
172 struct ubi_device *ubi;
173
174 spin_lock(&ubi_devices_lock);
175 for (i = 0; i < UBI_MAX_DEVICES; i++) {
176 ubi = ubi_devices[i];
177 if (ubi && MAJOR(ubi->cdev.dev) == major) {
178 ubi_assert(ubi->ref_count >= 0);
179 ubi->ref_count += 1;
180 get_device(&ubi->dev);
181 spin_unlock(&ubi_devices_lock);
182 return ubi;
183 }
184 }
185 spin_unlock(&ubi_devices_lock);
186
187 return NULL;
188}
189
190/**
191 * ubi_major2num - get UBI device number by character device major number.
192 * @major: major number
193 *
194 * This function searches UBI device number object by its major number. If UBI
195 * device was not found, this function returns -ENODEV, othewise the UBI device
196 * number is returned.
197 */
198int ubi_major2num(int major)
199{
200 int i, ubi_num = -ENODEV;
201
202 spin_lock(&ubi_devices_lock);
203 for (i = 0; i < UBI_MAX_DEVICES; i++) {
204 struct ubi_device *ubi = ubi_devices[i];
205
206 if (ubi && MAJOR(ubi->cdev.dev) == major) {
207 ubi_num = ubi->ubi_num;
208 break;
209 }
210 }
211 spin_unlock(&ubi_devices_lock);
212
213 return ubi_num;
214}
215
121/* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */ 216/* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */
122static ssize_t dev_attribute_show(struct device *dev, 217static ssize_t dev_attribute_show(struct device *dev,
123 struct device_attribute *attr, char *buf) 218 struct device_attribute *attr, char *buf)
124{ 219{
125 const struct ubi_device *ubi; 220 ssize_t ret;
221 struct ubi_device *ubi;
126 222
223 /*
224 * The below code looks weird, but it actually makes sense. We get the
225 * UBI device reference from the contained 'struct ubi_device'. But it
226 * is unclear if the device was removed or not yet. Indeed, if the
227 * device was removed before we increased its reference count,
228 * 'ubi_get_device()' will return -ENODEV and we fail.
229 *
230 * Remember, 'struct ubi_device' is freed in the release function, so
231 * we still can use 'ubi->ubi_num'.
232 */
127 ubi = container_of(dev, struct ubi_device, dev); 233 ubi = container_of(dev, struct ubi_device, dev);
234 ubi = ubi_get_device(ubi->ubi_num);
235 if (!ubi)
236 return -ENODEV;
237
128 if (attr == &dev_eraseblock_size) 238 if (attr == &dev_eraseblock_size)
129 return sprintf(buf, "%d\n", ubi->leb_size); 239 ret = sprintf(buf, "%d\n", ubi->leb_size);
130 else if (attr == &dev_avail_eraseblocks) 240 else if (attr == &dev_avail_eraseblocks)
131 return sprintf(buf, "%d\n", ubi->avail_pebs); 241 ret = sprintf(buf, "%d\n", ubi->avail_pebs);
132 else if (attr == &dev_total_eraseblocks) 242 else if (attr == &dev_total_eraseblocks)
133 return sprintf(buf, "%d\n", ubi->good_peb_count); 243 ret = sprintf(buf, "%d\n", ubi->good_peb_count);
134 else if (attr == &dev_volumes_count) 244 else if (attr == &dev_volumes_count)
135 return sprintf(buf, "%d\n", ubi->vol_count); 245 ret = sprintf(buf, "%d\n", ubi->vol_count);
136 else if (attr == &dev_max_ec) 246 else if (attr == &dev_max_ec)
137 return sprintf(buf, "%d\n", ubi->max_ec); 247 ret = sprintf(buf, "%d\n", ubi->max_ec);
138 else if (attr == &dev_reserved_for_bad) 248 else if (attr == &dev_reserved_for_bad)
139 return sprintf(buf, "%d\n", ubi->beb_rsvd_pebs); 249 ret = sprintf(buf, "%d\n", ubi->beb_rsvd_pebs);
140 else if (attr == &dev_bad_peb_count) 250 else if (attr == &dev_bad_peb_count)
141 return sprintf(buf, "%d\n", ubi->bad_peb_count); 251 ret = sprintf(buf, "%d\n", ubi->bad_peb_count);
142 else if (attr == &dev_max_vol_count) 252 else if (attr == &dev_max_vol_count)
143 return sprintf(buf, "%d\n", ubi->vtbl_slots); 253 ret = sprintf(buf, "%d\n", ubi->vtbl_slots);
144 else if (attr == &dev_min_io_size) 254 else if (attr == &dev_min_io_size)
145 return sprintf(buf, "%d\n", ubi->min_io_size); 255 ret = sprintf(buf, "%d\n", ubi->min_io_size);
146 else if (attr == &dev_bgt_enabled) 256 else if (attr == &dev_bgt_enabled)
147 return sprintf(buf, "%d\n", ubi->thread_enabled); 257 ret = sprintf(buf, "%d\n", ubi->thread_enabled);
148 else 258 else
149 BUG(); 259 BUG();
150 260
151 return 0; 261 ubi_put_device(ubi);
262 return ret;
152} 263}
153 264
154/* Fake "release" method for UBI devices */ 265/* Fake "release" method for UBI devices */
@@ -670,6 +781,7 @@ static void detach_mtd_dev(struct ubi_device *ubi)
670 int ubi_num = ubi->ubi_num, mtd_num = ubi->mtd->index; 781 int ubi_num = ubi->ubi_num, mtd_num = ubi->mtd->index;
671 782
672 dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num); 783 dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num);
784 ubi_assert(ubi->ref_count == 0);
673 uif_close(ubi); 785 uif_close(ubi);
674 ubi_eba_close(ubi); 786 ubi_eba_close(ubi);
675 ubi_wl_close(ubi); 787 ubi_wl_close(ubi);
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index bc900d24cdb..01978b57e9c 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -56,23 +56,6 @@
56#endif 56#endif
57 57
58/** 58/**
59 * major_to_device - get UBI device object by character device major number.
60 * @major: major number
61 *
62 * This function returns a pointer to the UBI device object.
63 */
64static struct ubi_device *major_to_device(int major)
65{
66 int i;
67
68 for (i = 0; i < UBI_MAX_DEVICES; i++)
69 if (ubi_devices[i] && MAJOR(ubi_devices[i]->cdev.dev) == major)
70 return ubi_devices[i];
71 BUG();
72 return NULL;
73}
74
75/**
76 * get_exclusive - get exclusive access to an UBI volume. 59 * get_exclusive - get exclusive access to an UBI volume.
77 * @desc: volume descriptor 60 * @desc: volume descriptor
78 * 61 *
@@ -129,9 +112,11 @@ static void revoke_exclusive(struct ubi_volume_desc *desc, int mode)
129static int vol_cdev_open(struct inode *inode, struct file *file) 112static int vol_cdev_open(struct inode *inode, struct file *file)
130{ 113{
131 struct ubi_volume_desc *desc; 114 struct ubi_volume_desc *desc;
132 const struct ubi_device *ubi = major_to_device(imajor(inode)); 115 int vol_id = iminor(inode) - 1, mode, ubi_num;
133 int vol_id = iminor(inode) - 1; 116
134 int mode; 117 ubi_num = ubi_major2num(imajor(inode));
118 if (ubi_num < 0)
119 return ubi_num;
135 120
136 if (file->f_mode & FMODE_WRITE) 121 if (file->f_mode & FMODE_WRITE)
137 mode = UBI_READWRITE; 122 mode = UBI_READWRITE;
@@ -140,7 +125,7 @@ static int vol_cdev_open(struct inode *inode, struct file *file)
140 125
141 dbg_msg("open volume %d, mode %d", vol_id, mode); 126 dbg_msg("open volume %d, mode %d", vol_id, mode);
142 127
143 desc = ubi_open_volume(ubi->ubi_num, vol_id, mode); 128 desc = ubi_open_volume(ubi_num, vol_id, mode);
144 if (IS_ERR(desc)) 129 if (IS_ERR(desc))
145 return PTR_ERR(desc); 130 return PTR_ERR(desc);
146 131
@@ -586,9 +571,9 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
586 if (!capable(CAP_SYS_RESOURCE)) 571 if (!capable(CAP_SYS_RESOURCE))
587 return -EPERM; 572 return -EPERM;
588 573
589 ubi = major_to_device(imajor(inode)); 574 ubi = ubi_get_by_major(imajor(inode));
590 if (IS_ERR(ubi)) 575 if (!ubi)
591 return PTR_ERR(ubi); 576 return -ENODEV;
592 577
593 switch (cmd) { 578 switch (cmd) {
594 /* Create volume command */ 579 /* Create volume command */
@@ -695,6 +680,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
695 break; 680 break;
696 } 681 }
697 682
683 ubi_put_device(ubi);
698 return err; 684 return err;
699} 685}
700 686
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index c94f475758d..85297cde4ac 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -339,6 +339,7 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
339{ 339{
340 int err, pnum, vol_id = vol->vol_id; 340 int err, pnum, vol_id = vol->vol_id;
341 341
342 ubi_assert(ubi->ref_count > 0);
342 ubi_assert(vol->ref_count > 0); 343 ubi_assert(vol->ref_count > 0);
343 344
344 if (ubi->ro_mode) 345 if (ubi->ro_mode)
@@ -389,6 +390,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
389 struct ubi_vid_hdr *vid_hdr; 390 struct ubi_vid_hdr *vid_hdr;
390 uint32_t uninitialized_var(crc); 391 uint32_t uninitialized_var(crc);
391 392
393 ubi_assert(ubi->ref_count > 0);
392 ubi_assert(vol->ref_count > 0); 394 ubi_assert(vol->ref_count > 0);
393 395
394 err = leb_read_lock(ubi, vol_id, lnum); 396 err = leb_read_lock(ubi, vol_id, lnum);
@@ -614,6 +616,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
614 int err, pnum, tries = 0, vol_id = vol->vol_id; 616 int err, pnum, tries = 0, vol_id = vol->vol_id;
615 struct ubi_vid_hdr *vid_hdr; 617 struct ubi_vid_hdr *vid_hdr;
616 618
619 ubi_assert(ubi->ref_count > 0);
617 ubi_assert(vol->ref_count > 0); 620 ubi_assert(vol->ref_count > 0);
618 621
619 if (ubi->ro_mode) 622 if (ubi->ro_mode)
@@ -749,6 +752,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
749 struct ubi_vid_hdr *vid_hdr; 752 struct ubi_vid_hdr *vid_hdr;
750 uint32_t crc; 753 uint32_t crc;
751 754
755 ubi_assert(ubi->ref_count > 0);
752 ubi_assert(vol->ref_count > 0); 756 ubi_assert(vol->ref_count > 0);
753 757
754 if (ubi->ro_mode) 758 if (ubi->ro_mode)
@@ -865,6 +869,7 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
865 struct ubi_vid_hdr *vid_hdr; 869 struct ubi_vid_hdr *vid_hdr;
866 uint32_t crc; 870 uint32_t crc;
867 871
872 ubi_assert(ubi->ref_count > 0);
868 ubi_assert(vol->ref_count > 0); 873 ubi_assert(vol->ref_count > 0);
869 874
870 if (ubi->ro_mode) 875 if (ubi->ro_mode)
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index 780c273ff45..4ec3a33b257 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -30,23 +30,27 @@
30 * @ubi_num: UBI device number 30 * @ubi_num: UBI device number
31 * @di: the information is stored here 31 * @di: the information is stored here
32 * 32 *
33 * This function returns %0 in case of success and a %-ENODEV if there is no 33 * This function returns %0 in case of success, %-EINVAL if the UBI device
34 * such UBI device. 34 * number is invalid, and %-ENODEV if there is no such UBI device.
35 */ 35 */
36int ubi_get_device_info(int ubi_num, struct ubi_device_info *di) 36int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
37{ 37{
38 const struct ubi_device *ubi; 38 struct ubi_device *ubi;
39 39
40 if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || 40 if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
41 !ubi_devices[ubi_num]) 41 return -EINVAL;
42
43 ubi = ubi_get_device(ubi_num);
44 if (!ubi)
42 return -ENODEV; 45 return -ENODEV;
43 46
44 ubi = ubi_devices[ubi_num];
45 di->ubi_num = ubi->ubi_num; 47 di->ubi_num = ubi->ubi_num;
46 di->leb_size = ubi->leb_size; 48 di->leb_size = ubi->leb_size;
47 di->min_io_size = ubi->min_io_size; 49 di->min_io_size = ubi->min_io_size;
48 di->ro_mode = ubi->ro_mode; 50 di->ro_mode = ubi->ro_mode;
49 di->cdev = ubi->cdev.dev; 51 di->cdev = ubi->cdev.dev;
52
53 ubi_put_device(ubi);
50 return 0; 54 return 0;
51} 55}
52EXPORT_SYMBOL_GPL(ubi_get_device_info); 56EXPORT_SYMBOL_GPL(ubi_get_device_info);
@@ -111,16 +115,23 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
111 mode != UBI_EXCLUSIVE) 115 mode != UBI_EXCLUSIVE)
112 return ERR_PTR(-EINVAL); 116 return ERR_PTR(-EINVAL);
113 117
114 ubi = ubi_devices[ubi_num]; 118 /*
119 * First of all, we have to get the UBI device to prevent its removal.
120 */
121 ubi = ubi_get_device(ubi_num);
115 if (!ubi) 122 if (!ubi)
116 return ERR_PTR(-ENODEV); 123 return ERR_PTR(-ENODEV);
117 124
118 if (vol_id < 0 || vol_id >= ubi->vtbl_slots) 125 if (vol_id < 0 || vol_id >= ubi->vtbl_slots) {
119 return ERR_PTR(-EINVAL); 126 err = -EINVAL;
127 goto out_put_ubi;
128 }
120 129
121 desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL); 130 desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL);
122 if (!desc) 131 if (!desc) {
123 return ERR_PTR(-ENOMEM); 132 err = -ENOMEM;
133 goto out_put_ubi;
134 }
124 135
125 err = -ENODEV; 136 err = -ENODEV;
126 if (!try_module_get(THIS_MODULE)) 137 if (!try_module_get(THIS_MODULE))
@@ -188,6 +199,8 @@ out_unlock:
188 module_put(THIS_MODULE); 199 module_put(THIS_MODULE);
189out_free: 200out_free:
190 kfree(desc); 201 kfree(desc);
202out_put_ubi:
203 ubi_put_device(ubi);
191 return ERR_PTR(err); 204 return ERR_PTR(err);
192} 205}
193EXPORT_SYMBOL_GPL(ubi_open_volume); 206EXPORT_SYMBOL_GPL(ubi_open_volume);
@@ -205,6 +218,7 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
205{ 218{
206 int i, vol_id = -1, len; 219 int i, vol_id = -1, len;
207 struct ubi_device *ubi; 220 struct ubi_device *ubi;
221 struct ubi_volume_desc *ret;
208 222
209 dbg_msg("open volume %s, mode %d", name, mode); 223 dbg_msg("open volume %s, mode %d", name, mode);
210 224
@@ -218,7 +232,7 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
218 if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) 232 if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
219 return ERR_PTR(-EINVAL); 233 return ERR_PTR(-EINVAL);
220 234
221 ubi = ubi_devices[ubi_num]; 235 ubi = ubi_get_device(ubi_num);
222 if (!ubi) 236 if (!ubi)
223 return ERR_PTR(-ENODEV); 237 return ERR_PTR(-ENODEV);
224 238
@@ -234,10 +248,17 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
234 } 248 }
235 spin_unlock(&ubi->volumes_lock); 249 spin_unlock(&ubi->volumes_lock);
236 250
237 if (vol_id < 0) 251 if (vol_id >= 0)
238 return ERR_PTR(-ENODEV); 252 ret = ubi_open_volume(ubi_num, vol_id, mode);
253 else
254 ret = ERR_PTR(-ENODEV);
239 255
240 return ubi_open_volume(ubi_num, vol_id, mode); 256 /*
257 * We should put the UBI device even in case of success, because
258 * 'ubi_open_volume()' took a reference as well.
259 */
260 ubi_put_device(ubi);
261 return ret;
241} 262}
242EXPORT_SYMBOL_GPL(ubi_open_volume_nm); 263EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
243 264
@@ -248,10 +269,11 @@ EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
248void ubi_close_volume(struct ubi_volume_desc *desc) 269void ubi_close_volume(struct ubi_volume_desc *desc)
249{ 270{
250 struct ubi_volume *vol = desc->vol; 271 struct ubi_volume *vol = desc->vol;
272 struct ubi_device *ubi = vol->ubi;
251 273
252 dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode); 274 dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode);
253 275
254 spin_lock(&vol->ubi->volumes_lock); 276 spin_lock(&ubi->volumes_lock);
255 switch (desc->mode) { 277 switch (desc->mode) {
256 case UBI_READONLY: 278 case UBI_READONLY:
257 vol->readers -= 1; 279 vol->readers -= 1;
@@ -263,10 +285,11 @@ void ubi_close_volume(struct ubi_volume_desc *desc)
263 vol->exclusive = 0; 285 vol->exclusive = 0;
264 } 286 }
265 vol->ref_count -= 1; 287 vol->ref_count -= 1;
266 spin_unlock(&vol->ubi->volumes_lock); 288 spin_unlock(&ubi->volumes_lock);
267 289
268 put_device(&vol->dev);
269 kfree(desc); 290 kfree(desc);
291 put_device(&vol->dev);
292 ubi_put_device(ubi);
270 module_put(THIS_MODULE); 293 module_put(THIS_MODULE);
271} 294}
272EXPORT_SYMBOL_GPL(ubi_close_volume); 295EXPORT_SYMBOL_GPL(ubi_close_volume);
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 21c028366fd..91fde0e8ff5 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -245,6 +245,7 @@ struct ubi_wl_entry;
245 * @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count, 245 * @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count,
246 * @vol->readers, @vol->writers, @vol->exclusive, 246 * @vol->readers, @vol->writers, @vol->exclusive,
247 * @vol->ref_count, @vol->mapping and @vol->eba_tbl. 247 * @vol->ref_count, @vol->mapping and @vol->eba_tbl.
248 * @ref_count: count of references on the UBI device
248 * 249 *
249 * @rsvd_pebs: count of reserved physical eraseblocks 250 * @rsvd_pebs: count of reserved physical eraseblocks
250 * @avail_pebs: count of available physical eraseblocks 251 * @avail_pebs: count of available physical eraseblocks
@@ -325,6 +326,7 @@ struct ubi_device {
325 int vol_count; 326 int vol_count;
326 struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT]; 327 struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT];
327 spinlock_t volumes_lock; 328 spinlock_t volumes_lock;
329 int ref_count;
328 330
329 int rsvd_pebs; 331 int rsvd_pebs;
330 int avail_pebs; 332 int avail_pebs;
@@ -401,7 +403,6 @@ extern struct kmem_cache *ubi_wl_entry_slab;
401extern struct file_operations ubi_ctrl_cdev_operations; 403extern struct file_operations ubi_ctrl_cdev_operations;
402extern struct file_operations ubi_cdev_operations; 404extern struct file_operations ubi_cdev_operations;
403extern struct file_operations ubi_vol_cdev_operations; 405extern struct file_operations ubi_vol_cdev_operations;
404extern struct ubi_device *ubi_devices[];
405extern struct class *ubi_class; 406extern struct class *ubi_class;
406 407
407/* vtbl.c */ 408/* vtbl.c */
@@ -479,6 +480,12 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
479int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, 480int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
480 struct ubi_vid_hdr *vid_hdr); 481 struct ubi_vid_hdr *vid_hdr);
481 482
483/* build.c */
484struct ubi_device *ubi_get_device(int ubi_num);
485void ubi_put_device(struct ubi_device *ubi);
486struct ubi_device *ubi_get_by_major(int major);
487int ubi_major2num(int major);
488
482/* 489/*
483 * ubi_rb_for_each_entry - walk an RB-tree. 490 * ubi_rb_for_each_entry - walk an RB-tree.
484 * @rb: a pointer to type 'struct rb_node' to to use as a loop counter 491 * @rb: a pointer to type 'struct rb_node' to to use as a loop counter
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index 3ed63dc3738..42d3dd70f2d 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -71,11 +71,16 @@ static ssize_t vol_attribute_show(struct device *dev,
71{ 71{
72 int ret; 72 int ret;
73 struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); 73 struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);
74 struct ubi_device *ubi = vol->ubi; 74 struct ubi_device *ubi;
75
76 ubi = ubi_get_device(vol->ubi->ubi_num);
77 if (!ubi)
78 return -ENODEV;
75 79
76 spin_lock(&ubi->volumes_lock); 80 spin_lock(&ubi->volumes_lock);
77 if (!ubi->volumes[vol->vol_id]) { 81 if (!ubi->volumes[vol->vol_id]) {
78 spin_unlock(&ubi->volumes_lock); 82 spin_unlock(&ubi->volumes_lock);
83 ubi_put_device(ubi);
79 return -ENODEV; 84 return -ENODEV;
80 } 85 }
81 /* Take a reference to prevent volume removal */ 86 /* Take a reference to prevent volume removal */
@@ -108,10 +113,12 @@ static ssize_t vol_attribute_show(struct device *dev,
108 /* This must be a bug */ 113 /* This must be a bug */
109 ret = -EINVAL; 114 ret = -EINVAL;
110 115
116 /* We've done the operation, drop volume and UBI device references */
111 spin_lock(&ubi->volumes_lock); 117 spin_lock(&ubi->volumes_lock);
112 vol->ref_count -= 1; 118 vol->ref_count -= 1;
113 ubi_assert(vol->ref_count >= 0); 119 ubi_assert(vol->ref_count >= 0);
114 spin_unlock(&ubi->volumes_lock); 120 spin_unlock(&ubi->volumes_lock);
121 ubi_put_device(ubi);
115 return ret; 122 return ret;
116} 123}
117 124
@@ -260,6 +267,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
260 } 267 }
261 ubi->avail_pebs -= vol->reserved_pebs; 268 ubi->avail_pebs -= vol->reserved_pebs;
262 ubi->rsvd_pebs += vol->reserved_pebs; 269 ubi->rsvd_pebs += vol->reserved_pebs;
270 spin_unlock(&ubi->volumes_lock);
263 271
264 vol->vol_id = vol_id; 272 vol->vol_id = vol_id;
265 vol->alignment = req->alignment; 273 vol->alignment = req->alignment;
@@ -267,9 +275,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
267 vol->vol_type = req->vol_type; 275 vol->vol_type = req->vol_type;
268 vol->name_len = req->name_len; 276 vol->name_len = req->name_len;
269 memcpy(vol->name, req->name, vol->name_len + 1); 277 memcpy(vol->name, req->name, vol->name_len + 1);
270 vol->exclusive = 1;
271 vol->ubi = ubi; 278 vol->ubi = ubi;
272 spin_unlock(&ubi->volumes_lock);
273 279
274 /* 280 /*
275 * Finish all pending erases because there may be some LEBs belonging 281 * Finish all pending erases because there may be some LEBs belonging
@@ -350,8 +356,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
350 goto out_sysfs; 356 goto out_sysfs;
351 357
352 spin_lock(&ubi->volumes_lock); 358 spin_lock(&ubi->volumes_lock);
353 ubi->vol_count += 1;
354 vol->exclusive = 0;
355 ubi->volumes[vol_id] = vol; 359 ubi->volumes[vol_id] = vol;
356 spin_unlock(&ubi->volumes_lock); 360 spin_unlock(&ubi->volumes_lock);
357 361
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 7d32f71d6f1..bfc64c82416 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -1303,6 +1303,7 @@ int ubi_wl_flush(struct ubi_device *ubi)
1303 * Make sure all the works which have been done in parallel are 1303 * Make sure all the works which have been done in parallel are
1304 * finished. 1304 * finished.
1305 */ 1305 */
1306 ubi_assert(ubi->ref_count > 0);
1306 down_write(&ubi->work_sem); 1307 down_write(&ubi->work_sem);
1307 up_write(&ubi->work_sem); 1308 up_write(&ubi->work_sem);
1308 1309