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