[SCSI] scsi_dh: create lookup cache

Create a cache of devices that are seen in a system. This will avoid
the unnecessary traversal of the device list in the scsi_dh when there
are multiple luns of a same type.

Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

authored by

Hannes Reinecke and committed by
James Bottomley
7c32c7a2 ae11b1b3

+105 -24
+105 -24
drivers/scsi/device_handler/scsi_dh.c
··· 24 24 #include <scsi/scsi_dh.h> 25 25 #include "../scsi_priv.h" 26 26 27 + struct scsi_dh_devinfo_list { 28 + struct list_head node; 29 + char vendor[9]; 30 + char model[17]; 31 + struct scsi_device_handler *handler; 32 + }; 33 + 27 34 static DEFINE_SPINLOCK(list_lock); 28 35 static LIST_HEAD(scsi_dh_list); 36 + static LIST_HEAD(scsi_dh_dev_list); 29 37 30 38 static struct scsi_device_handler *get_device_handler(const char *name) 31 39 { ··· 50 42 return found; 51 43 } 52 44 53 - static int device_handler_match(struct scsi_device_handler *tmp, 54 - struct scsi_device *sdev) 55 - { 56 - int i; 57 45 58 - for(i = 0; tmp->devlist[i].vendor; i++) { 59 - if (!strncmp(sdev->vendor, tmp->devlist[i].vendor, 60 - strlen(tmp->devlist[i].vendor)) && 61 - !strncmp(sdev->model, tmp->devlist[i].model, 62 - strlen(tmp->devlist[i].model))) { 63 - return 1; 46 + static struct scsi_device_handler * 47 + scsi_dh_cache_lookup(struct scsi_device *sdev) 48 + { 49 + struct scsi_dh_devinfo_list *tmp; 50 + struct scsi_device_handler *found_dh = NULL; 51 + 52 + spin_lock(&list_lock); 53 + list_for_each_entry(tmp, &scsi_dh_dev_list, node) { 54 + if (!strncmp(sdev->vendor, tmp->vendor, strlen(tmp->vendor)) && 55 + !strncmp(sdev->model, tmp->model, strlen(tmp->model))) { 56 + found_dh = tmp->handler; 57 + break; 58 + } 59 + } 60 + spin_unlock(&list_lock); 61 + 62 + return found_dh; 63 + } 64 + 65 + static int scsi_dh_handler_lookup(struct scsi_device_handler *scsi_dh, 66 + struct scsi_device *sdev) 67 + { 68 + int i, found = 0; 69 + 70 + for(i = 0; scsi_dh->devlist[i].vendor; i++) { 71 + if (!strncmp(sdev->vendor, scsi_dh->devlist[i].vendor, 72 + strlen(scsi_dh->devlist[i].vendor)) && 73 + !strncmp(sdev->model, scsi_dh->devlist[i].model, 74 + strlen(scsi_dh->devlist[i].model))) { 75 + found = 1; 76 + break; 77 + } 78 + } 79 + return found; 80 + } 81 + 82 + /* 83 + * device_handler_match - Attach a device handler to a device 84 + * @scsi_dh - The device handler to match against or NULL 85 + * @sdev - SCSI device to be tested against @scsi_dh 86 + * 87 + * Tests @sdev against the device handler @scsi_dh or against 88 + * all registered device_handler if @scsi_dh == NULL. 89 + * Returns the found device handler or NULL if not found. 90 + */ 91 + static struct scsi_device_handler * 92 + device_handler_match(struct scsi_device_handler *scsi_dh, 93 + struct scsi_device *sdev) 94 + { 95 + struct scsi_device_handler *found_dh = NULL; 96 + struct scsi_dh_devinfo_list *tmp; 97 + 98 + found_dh = scsi_dh_cache_lookup(sdev); 99 + if (found_dh) 100 + return found_dh; 101 + 102 + if (scsi_dh) { 103 + if (scsi_dh_handler_lookup(scsi_dh, sdev)) 104 + found_dh = scsi_dh; 105 + } else { 106 + struct scsi_device_handler *tmp_dh; 107 + 108 + spin_lock(&list_lock); 109 + list_for_each_entry(tmp_dh, &scsi_dh_list, list) { 110 + if (scsi_dh_handler_lookup(tmp_dh, sdev)) 111 + found_dh = tmp_dh; 112 + } 113 + spin_unlock(&list_lock); 114 + } 115 + 116 + if (found_dh) { /* If device is found, add it to the cache */ 117 + tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); 118 + if (tmp) { 119 + strncpy(tmp->vendor, sdev->vendor, 8); 120 + strncpy(tmp->model, sdev->model, 16); 121 + tmp->vendor[8] = '\0'; 122 + tmp->model[16] = '\0'; 123 + tmp->handler = found_dh; 124 + spin_lock(&list_lock); 125 + list_add(&tmp->node, &scsi_dh_dev_list); 126 + spin_unlock(&list_lock); 127 + } else { 128 + found_dh = NULL; 64 129 } 65 130 } 66 131 67 - return 0; 132 + return found_dh; 68 133 } 69 134 70 135 /* ··· 284 203 struct device *dev = data; 285 204 struct scsi_device *sdev; 286 205 int err = 0; 287 - struct scsi_device_handler *tmp, *devinfo = NULL; 206 + struct scsi_device_handler *devinfo = NULL; 288 207 289 208 if (!scsi_is_sdev_device(dev)) 290 209 return 0; 291 210 292 211 sdev = to_scsi_device(dev); 293 212 294 - spin_lock(&list_lock); 295 - list_for_each_entry(tmp, &scsi_dh_list, list) { 296 - if (device_handler_match(tmp, sdev)) { 297 - devinfo = tmp; 298 - break; 299 - } 300 - } 301 - spin_unlock(&list_lock); 302 - 303 - if (!devinfo) 304 - goto out; 305 - 306 213 if (action == BUS_NOTIFY_ADD_DEVICE) { 214 + devinfo = device_handler_match(NULL, sdev); 215 + if (!devinfo) 216 + goto out; 217 + 307 218 err = scsi_dh_handler_attach(sdev, devinfo); 308 219 if (!err) 309 220 err = device_create_file(dev, &scsi_dh_state_attr); ··· 385 312 */ 386 313 int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) 387 314 { 315 + struct scsi_dh_devinfo_list *tmp, *pos; 316 + 388 317 if (!get_device_handler(scsi_dh->name)) 389 318 return -ENODEV; 390 319 ··· 395 320 396 321 spin_lock(&list_lock); 397 322 list_del(&scsi_dh->list); 323 + list_for_each_entry_safe(pos, tmp, &scsi_dh_dev_list, node) { 324 + if (pos->handler == scsi_dh) { 325 + list_del(&pos->node); 326 + kfree(pos); 327 + } 328 + } 398 329 spin_unlock(&list_lock); 399 330 printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name); 400 331