aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/ubi/build.c
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/build.c
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/build.c')
-rw-r--r--drivers/mtd/ubi/build.c142
1 files changed, 127 insertions, 15 deletions
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 3f37b16f8774..a4faf71ee3f2 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);