aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/osd/osd_uld.c
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
commitada47b5fe13d89735805b566185f4885f5a3f750 (patch)
tree644b88f8a71896307d71438e9b3af49126ffb22b /drivers/scsi/osd/osd_uld.c
parent43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff)
parent3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff)
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/scsi/osd/osd_uld.c')
-rw-r--r--drivers/scsi/osd/osd_uld.c261
1 files changed, 178 insertions, 83 deletions
diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c
index 0bdef3390902..ffdd9fdb9995 100644
--- a/drivers/scsi/osd/osd_uld.c
+++ b/drivers/scsi/osd/osd_uld.c
@@ -50,6 +50,7 @@
50#include <linux/idr.h> 50#include <linux/idr.h>
51#include <linux/major.h> 51#include <linux/major.h>
52#include <linux/file.h> 52#include <linux/file.h>
53#include <linux/slab.h>
53 54
54#include <scsi/scsi.h> 55#include <scsi/scsi.h>
55#include <scsi/scsi_driver.h> 56#include <scsi/scsi_driver.h>
@@ -71,8 +72,7 @@
71#define SCSI_OSD_MAX_MINOR 64 72#define SCSI_OSD_MAX_MINOR 64
72 73
73static const char osd_name[] = "osd"; 74static const char osd_name[] = "osd";
74static const char *osd_version_string = "open-osd 0.1.0"; 75static const char *osd_version_string = "open-osd 0.2.0";
75const char osd_symlink[] = "scsi_osd";
76 76
77MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>"); 77MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>");
78MODULE_DESCRIPTION("open-osd Upper-Layer-Driver osd.ko"); 78MODULE_DESCRIPTION("open-osd Upper-Layer-Driver osd.ko");
@@ -82,15 +82,25 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_OSD);
82 82
83struct osd_uld_device { 83struct osd_uld_device {
84 int minor; 84 int minor;
85 struct kref kref; 85 struct device class_dev;
86 struct cdev cdev; 86 struct cdev cdev;
87 struct osd_dev od; 87 struct osd_dev od;
88 struct osd_dev_info odi;
88 struct gendisk *disk; 89 struct gendisk *disk;
89 struct device *class_member;
90}; 90};
91 91
92static void __uld_get(struct osd_uld_device *oud); 92struct osd_dev_handle {
93static void __uld_put(struct osd_uld_device *oud); 93 struct osd_dev od;
94 struct file *file;
95 struct osd_uld_device *oud;
96} ;
97
98static DEFINE_IDA(osd_minor_ida);
99
100static struct class osd_uld_class = {
101 .owner = THIS_MODULE,
102 .name = "scsi_osd",
103};
94 104
95/* 105/*
96 * Char Device operations 106 * Char Device operations
@@ -101,7 +111,7 @@ static int osd_uld_open(struct inode *inode, struct file *file)
101 struct osd_uld_device *oud = container_of(inode->i_cdev, 111 struct osd_uld_device *oud = container_of(inode->i_cdev,
102 struct osd_uld_device, cdev); 112 struct osd_uld_device, cdev);
103 113
104 __uld_get(oud); 114 get_device(&oud->class_dev);
105 /* cache osd_uld_device on file handle */ 115 /* cache osd_uld_device on file handle */
106 file->private_data = oud; 116 file->private_data = oud;
107 OSD_DEBUG("osd_uld_open %p\n", oud); 117 OSD_DEBUG("osd_uld_open %p\n", oud);
@@ -114,7 +124,7 @@ static int osd_uld_release(struct inode *inode, struct file *file)
114 124
115 OSD_DEBUG("osd_uld_release %p\n", file->private_data); 125 OSD_DEBUG("osd_uld_release %p\n", file->private_data);
116 file->private_data = NULL; 126 file->private_data = NULL;
117 __uld_put(oud); 127 put_device(&oud->class_dev);
118 return 0; 128 return 0;
119} 129}
120 130
@@ -177,7 +187,7 @@ static const struct file_operations osd_fops = {
177struct osd_dev *osduld_path_lookup(const char *name) 187struct osd_dev *osduld_path_lookup(const char *name)
178{ 188{
179 struct osd_uld_device *oud; 189 struct osd_uld_device *oud;
180 struct osd_dev *od; 190 struct osd_dev_handle *odh;
181 struct file *file; 191 struct file *file;
182 int error; 192 int error;
183 193
@@ -186,8 +196,8 @@ struct osd_dev *osduld_path_lookup(const char *name)
186 return ERR_PTR(-EINVAL); 196 return ERR_PTR(-EINVAL);
187 } 197 }
188 198
189 od = kzalloc(sizeof(*od), GFP_KERNEL); 199 odh = kzalloc(sizeof(*odh), GFP_KERNEL);
190 if (!od) 200 if (unlikely(!odh))
191 return ERR_PTR(-ENOMEM); 201 return ERR_PTR(-ENOMEM);
192 202
193 file = filp_open(name, O_RDWR, 0); 203 file = filp_open(name, O_RDWR, 0);
@@ -203,33 +213,134 @@ struct osd_dev *osduld_path_lookup(const char *name)
203 213
204 oud = file->private_data; 214 oud = file->private_data;
205 215
206 *od = oud->od; 216 odh->od = oud->od;
207 od->file = file; 217 odh->file = file;
218 odh->oud = oud;
208 219
209 return od; 220 return &odh->od;
210 221
211close_file: 222close_file:
212 fput(file); 223 fput(file);
213free_od: 224free_od:
214 kfree(od); 225 kfree(odh);
215 return ERR_PTR(error); 226 return ERR_PTR(error);
216} 227}
217EXPORT_SYMBOL(osduld_path_lookup); 228EXPORT_SYMBOL(osduld_path_lookup);
218 229
219void osduld_put_device(struct osd_dev *od) 230static inline bool _the_same_or_null(const u8 *a1, unsigned a1_len,
231 const u8 *a2, unsigned a2_len)
220{ 232{
233 if (!a2_len) /* User string is Empty means don't care */
234 return true;
235
236 if (a1_len != a2_len)
237 return false;
238
239 return 0 == memcmp(a1, a2, a1_len);
240}
241
242struct find_oud_t {
243 const struct osd_dev_info *odi;
244 struct device *dev;
245 struct osd_uld_device *oud;
246} ;
247
248int _mach_odi(struct device *dev, void *find_data)
249{
250 struct osd_uld_device *oud = container_of(dev, struct osd_uld_device,
251 class_dev);
252 struct find_oud_t *fot = find_data;
253 const struct osd_dev_info *odi = fot->odi;
254
255 if (_the_same_or_null(oud->odi.systemid, oud->odi.systemid_len,
256 odi->systemid, odi->systemid_len) &&
257 _the_same_or_null(oud->odi.osdname, oud->odi.osdname_len,
258 odi->osdname, odi->osdname_len)) {
259 OSD_DEBUG("found device sysid_len=%d osdname=%d\n",
260 odi->systemid_len, odi->osdname_len);
261 fot->oud = oud;
262 return 1;
263 } else {
264 return 0;
265 }
266}
267
268/* osduld_info_lookup - Loop through all devices, return the requested osd_dev.
269 *
270 * if @odi->systemid_len and/or @odi->osdname_len are zero, they act as a don't
271 * care. .e.g if they're both zero /dev/osd0 is returned.
272 */
273struct osd_dev *osduld_info_lookup(const struct osd_dev_info *odi)
274{
275 struct find_oud_t find = {.odi = odi};
276
277 find.dev = class_find_device(&osd_uld_class, NULL, &find, _mach_odi);
278 if (likely(find.dev)) {
279 struct osd_dev_handle *odh = kzalloc(sizeof(*odh), GFP_KERNEL);
280
281 if (unlikely(!odh)) {
282 put_device(find.dev);
283 return ERR_PTR(-ENOMEM);
284 }
221 285
286 odh->od = find.oud->od;
287 odh->oud = find.oud;
288
289 return &odh->od;
290 }
291
292 return ERR_PTR(-ENODEV);
293}
294EXPORT_SYMBOL(osduld_info_lookup);
295
296void osduld_put_device(struct osd_dev *od)
297{
222 if (od && !IS_ERR(od)) { 298 if (od && !IS_ERR(od)) {
223 struct osd_uld_device *oud = od->file->private_data; 299 struct osd_dev_handle *odh =
300 container_of(od, struct osd_dev_handle, od);
301 struct osd_uld_device *oud = odh->oud;
224 302
225 BUG_ON(od->scsi_device != oud->od.scsi_device); 303 BUG_ON(od->scsi_device != oud->od.scsi_device);
226 304
227 fput(od->file); 305 /* If scsi has released the device (logout), and exofs has last
228 kfree(od); 306 * reference on oud it will be freed by above osd_uld_release
307 * within fput below. But this will oops in cdev_release which
308 * is called after the fops->release. A get_/put_ pair makes
309 * sure we have a cdev for the duration of fput
310 */
311 if (odh->file) {
312 get_device(&oud->class_dev);
313 fput(odh->file);
314 }
315 put_device(&oud->class_dev);
316 kfree(odh);
229 } 317 }
230} 318}
231EXPORT_SYMBOL(osduld_put_device); 319EXPORT_SYMBOL(osduld_put_device);
232 320
321const struct osd_dev_info *osduld_device_info(struct osd_dev *od)
322{
323 struct osd_dev_handle *odh =
324 container_of(od, struct osd_dev_handle, od);
325 return &odh->oud->odi;
326}
327EXPORT_SYMBOL(osduld_device_info);
328
329bool osduld_device_same(struct osd_dev *od, const struct osd_dev_info *odi)
330{
331 struct osd_dev_handle *odh =
332 container_of(od, struct osd_dev_handle, od);
333 struct osd_uld_device *oud = odh->oud;
334
335 return (oud->odi.systemid_len == odi->systemid_len) &&
336 _the_same_or_null(oud->odi.systemid, oud->odi.systemid_len,
337 odi->systemid, odi->systemid_len) &&
338 (oud->odi.osdname_len == odi->osdname_len) &&
339 _the_same_or_null(oud->odi.osdname, oud->odi.osdname_len,
340 odi->osdname, odi->osdname_len);
341}
342EXPORT_SYMBOL(osduld_device_same);
343
233/* 344/*
234 * Scsi Device operations 345 * Scsi Device operations
235 */ 346 */
@@ -250,14 +361,35 @@ static int __detect_osd(struct osd_uld_device *oud)
250 OSD_ERR("warning: scsi_test_unit_ready failed\n"); 361 OSD_ERR("warning: scsi_test_unit_ready failed\n");
251 362
252 osd_sec_init_nosec_doall_caps(caps, &osd_root_object, false, true); 363 osd_sec_init_nosec_doall_caps(caps, &osd_root_object, false, true);
253 if (osd_auto_detect_ver(&oud->od, caps)) 364 if (osd_auto_detect_ver(&oud->od, caps, &oud->odi))
254 return -ENODEV; 365 return -ENODEV;
255 366
256 return 0; 367 return 0;
257} 368}
258 369
259static struct class *osd_sysfs_class; 370static void __remove(struct device *dev)
260static DEFINE_IDA(osd_minor_ida); 371{
372 struct osd_uld_device *oud = container_of(dev, struct osd_uld_device,
373 class_dev);
374 struct scsi_device *scsi_device = oud->od.scsi_device;
375
376 kfree(oud->odi.osdname);
377
378 if (oud->cdev.owner)
379 cdev_del(&oud->cdev);
380
381 osd_dev_fini(&oud->od);
382 scsi_device_put(scsi_device);
383
384 OSD_INFO("osd_remove %s\n",
385 oud->disk ? oud->disk->disk_name : NULL);
386
387 if (oud->disk)
388 put_disk(oud->disk);
389 ida_remove(&osd_minor_ida, oud->minor);
390
391 kfree(oud);
392}
261 393
262static int osd_probe(struct device *dev) 394static int osd_probe(struct device *dev)
263{ 395{
@@ -289,7 +421,6 @@ static int osd_probe(struct device *dev)
289 if (NULL == oud) 421 if (NULL == oud)
290 goto err_retract_minor; 422 goto err_retract_minor;
291 423
292 kref_init(&oud->kref);
293 dev_set_drvdata(dev, oud); 424 dev_set_drvdata(dev, oud);
294 oud->minor = minor; 425 oud->minor = minor;
295 426
@@ -327,18 +458,25 @@ static int osd_probe(struct device *dev)
327 OSD_ERR("cdev_add failed\n"); 458 OSD_ERR("cdev_add failed\n");
328 goto err_put_disk; 459 goto err_put_disk;
329 } 460 }
330 kobject_get(&oud->cdev.kobj); /* 2nd ref see osd_remove() */ 461
331 462 /* class device member */
332 /* class_member */ 463 oud->class_dev.devt = oud->cdev.dev;
333 oud->class_member = device_create(osd_sysfs_class, dev, 464 oud->class_dev.class = &osd_uld_class;
334 MKDEV(SCSI_OSD_MAJOR, oud->minor), "%s", disk->disk_name); 465 oud->class_dev.parent = dev;
335 if (IS_ERR(oud->class_member)) { 466 oud->class_dev.release = __remove;
336 OSD_ERR("class_device_create failed\n"); 467 error = dev_set_name(&oud->class_dev, disk->disk_name);
337 error = PTR_ERR(oud->class_member); 468 if (error) {
469 OSD_ERR("dev_set_name failed => %d\n", error);
470 goto err_put_cdev;
471 }
472
473 error = device_register(&oud->class_dev);
474 if (error) {
475 OSD_ERR("device_register failed => %d\n", error);
338 goto err_put_cdev; 476 goto err_put_cdev;
339 } 477 }
340 478
341 dev_set_drvdata(oud->class_member, oud); 479 get_device(&oud->class_dev);
342 480
343 OSD_INFO("osd_probe %s\n", disk->disk_name); 481 OSD_INFO("osd_probe %s\n", disk->disk_name);
344 return 0; 482 return 0;
@@ -367,54 +505,12 @@ static int osd_remove(struct device *dev)
367 scsi_device); 505 scsi_device);
368 } 506 }
369 507
370 if (oud->class_member) 508 device_unregister(&oud->class_dev);
371 device_destroy(osd_sysfs_class,
372 MKDEV(SCSI_OSD_MAJOR, oud->minor));
373 509
374 /* We have 2 references to the cdev. One is released here 510 put_device(&oud->class_dev);
375 * and also takes down the /dev/osdX mapping. The second
376 * Will be released in __remove() after all users have released
377 * the osd_uld_device.
378 */
379 if (oud->cdev.owner)
380 cdev_del(&oud->cdev);
381
382 __uld_put(oud);
383 return 0; 511 return 0;
384} 512}
385 513
386static void __remove(struct kref *kref)
387{
388 struct osd_uld_device *oud = container_of(kref,
389 struct osd_uld_device, kref);
390 struct scsi_device *scsi_device = oud->od.scsi_device;
391
392 /* now let delete the char_dev */
393 kobject_put(&oud->cdev.kobj);
394
395 osd_dev_fini(&oud->od);
396 scsi_device_put(scsi_device);
397
398 OSD_INFO("osd_remove %s\n",
399 oud->disk ? oud->disk->disk_name : NULL);
400
401 if (oud->disk)
402 put_disk(oud->disk);
403
404 ida_remove(&osd_minor_ida, oud->minor);
405 kfree(oud);
406}
407
408static void __uld_get(struct osd_uld_device *oud)
409{
410 kref_get(&oud->kref);
411}
412
413static void __uld_put(struct osd_uld_device *oud)
414{
415 kref_put(&oud->kref, __remove);
416}
417
418/* 514/*
419 * Global driver and scsi registration 515 * Global driver and scsi registration
420 */ 516 */
@@ -432,11 +528,10 @@ static int __init osd_uld_init(void)
432{ 528{
433 int err; 529 int err;
434 530
435 osd_sysfs_class = class_create(THIS_MODULE, osd_symlink); 531 err = class_register(&osd_uld_class);
436 if (IS_ERR(osd_sysfs_class)) { 532 if (err) {
437 OSD_ERR("Unable to register sysfs class => %ld\n", 533 OSD_ERR("Unable to register sysfs class => %d\n", err);
438 PTR_ERR(osd_sysfs_class)); 534 return err;
439 return PTR_ERR(osd_sysfs_class);
440 } 535 }
441 536
442 err = register_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), 537 err = register_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0),
@@ -459,7 +554,7 @@ static int __init osd_uld_init(void)
459err_out_chrdev: 554err_out_chrdev:
460 unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR); 555 unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR);
461err_out: 556err_out:
462 class_destroy(osd_sysfs_class); 557 class_unregister(&osd_uld_class);
463 return err; 558 return err;
464} 559}
465 560
@@ -467,7 +562,7 @@ static void __exit osd_uld_exit(void)
467{ 562{
468 scsi_unregister_driver(&osd_driver.gendrv); 563 scsi_unregister_driver(&osd_driver.gendrv);
469 unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR); 564 unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR);
470 class_destroy(osd_sysfs_class); 565 class_unregister(&osd_uld_class);
471 OSD_INFO("UNLOADED %s\n", osd_version_string); 566 OSD_INFO("UNLOADED %s\n", osd_version_string);
472} 567}
473 568