1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
|
From 26d61e8347b27a981d647d3ea4ec8c7f462c1fcf Mon Sep 17 00:00:00 2001
From: Alan Stern <stern@rowland.harvard.edu>
Date: Mon, 3 Aug 2015 11:57:21 -0400
Subject: [PATCH 1/2] SCSI: refactor device-matching code in scsi_devinfo.c
In drivers/scsi/scsi_devinfo.c, the scsi_dev_info_list_del_keyed() and
scsi_get_device_flags_keyed() routines contain a large amount of
duplicate code for finding vendor/product matches in a
scsi_dev_info_list. This patch factors out the duplicate code and
puts it in a separate function, scsi_dev_info_list_find().
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Suggested-by: Giulio Bernardi <ugilio@gmail.com>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
---
drivers/scsi/scsi_devinfo.c | 112 ++++++++++++++++----------------------------
1 file changed, 41 insertions(+), 71 deletions(-)
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index 9f77d23239a2..2f49a224462d 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -390,25 +390,26 @@ int scsi_dev_info_list_add_keyed(int compatible, char *vendor, char *model,
EXPORT_SYMBOL(scsi_dev_info_list_add_keyed);
/**
- * scsi_dev_info_list_del_keyed - remove one dev_info list entry.
+ * scsi_dev_info_list_find - find a matching dev_info list entry.
* @vendor: vendor string
* @model: model (product) string
* @key: specify list to use
*
* Description:
- * Remove and destroy one dev_info entry for @vendor, @model
+ * Finds the first dev_info entry matching @vendor, @model
* in list specified by @key.
*
- * Returns: 0 OK, -error on failure.
+ * Returns: pointer to matching entry, or ERR_PTR on failure.
**/
-int scsi_dev_info_list_del_keyed(char *vendor, char *model, int key)
+static struct scsi_dev_info_list *scsi_dev_info_list_find(const char *vendor,
+ const char *model, int key)
{
- struct scsi_dev_info_list *devinfo, *found = NULL;
+ struct scsi_dev_info_list *devinfo;
struct scsi_dev_info_list_table *devinfo_table =
scsi_devinfo_lookup_by_key(key);
if (IS_ERR(devinfo_table))
- return PTR_ERR(devinfo_table);
+ return (struct scsi_dev_info_list *) devinfo_table;
list_for_each_entry(devinfo, &devinfo_table->scsi_dev_info_list,
dev_info_list) {
@@ -452,25 +453,42 @@ int scsi_dev_info_list_del_keyed(char *vendor, char *model, int key)
if (memcmp(devinfo->model, model,
min(max, strlen(devinfo->model))))
continue;
- found = devinfo;
+ return devinfo;
} else {
if (!memcmp(devinfo->vendor, vendor,
sizeof(devinfo->vendor)) &&
!memcmp(devinfo->model, model,
sizeof(devinfo->model)))
- found = devinfo;
+ return devinfo;
}
- if (found)
- break;
}
- if (found) {
- list_del(&found->dev_info_list);
- kfree(found);
- return 0;
- }
+ return ERR_PTR(-ENOENT);
+}
+
+/**
+ * scsi_dev_info_list_del_keyed - remove one dev_info list entry.
+ * @vendor: vendor string
+ * @model: model (product) string
+ * @key: specify list to use
+ *
+ * Description:
+ * Remove and destroy one dev_info entry for @vendor, @model
+ * in list specified by @key.
+ *
+ * Returns: 0 OK, -error on failure.
+ **/
+int scsi_dev_info_list_del_keyed(char *vendor, char *model, int key)
+{
+ struct scsi_dev_info_list *found;
- return -ENOENT;
+ found = scsi_dev_info_list_find(vendor, model, key);
+ if (IS_ERR(found))
+ return PTR_ERR(found);
+
+ list_del(&found->dev_info_list);
+ kfree(found);
+ return 0;
}
EXPORT_SYMBOL(scsi_dev_info_list_del_keyed);
@@ -565,64 +583,16 @@ int scsi_get_device_flags_keyed(struct scsi_device *sdev,
int key)
{
struct scsi_dev_info_list *devinfo;
- struct scsi_dev_info_list_table *devinfo_table;
+ int err;
- devinfo_table = scsi_devinfo_lookup_by_key(key);
+ devinfo = scsi_dev_info_list_find(vendor, model, key);
+ if (!IS_ERR(devinfo))
+ return devinfo->flags;
- if (IS_ERR(devinfo_table))
- return PTR_ERR(devinfo_table);
+ err = PTR_ERR(devinfo);
+ if (err != -ENOENT)
+ return err;
- list_for_each_entry(devinfo, &devinfo_table->scsi_dev_info_list,
- dev_info_list) {
- if (devinfo->compatible) {
- /*
- * Behave like the older version of get_device_flags.
- */
- size_t max;
- /*
- * XXX why skip leading spaces? If an odd INQUIRY
- * value, that should have been part of the
- * scsi_static_device_list[] entry, such as " FOO"
- * rather than "FOO". Since this code is already
- * here, and we don't know what device it is
- * trying to work with, leave it as-is.
- */
- max = 8; /* max length of vendor */
- while ((max > 0) && *vendor == ' ') {
- max--;
- vendor++;
- }
- /*
- * XXX removing the following strlen() would be
- * good, using it means that for a an entry not in
- * the list, we scan every byte of every vendor
- * listed in scsi_static_device_list[], and never match
- * a single one (and still have to compare at
- * least the first byte of each vendor).
- */
- if (memcmp(devinfo->vendor, vendor,
- min(max, strlen(devinfo->vendor))))
- continue;
- /*
- * Skip spaces again.
- */
- max = 16; /* max length of model */
- while ((max > 0) && *model == ' ') {
- max--;
- model++;
- }
- if (memcmp(devinfo->model, model,
- min(max, strlen(devinfo->model))))
- continue;
- return devinfo->flags;
- } else {
- if (!memcmp(devinfo->vendor, vendor,
- sizeof(devinfo->vendor)) &&
- !memcmp(devinfo->model, model,
- sizeof(devinfo->model)))
- return devinfo->flags;
- }
- }
/* nothing found, return nothing */
if (key != SCSI_DEVINFO_GLOBAL)
return 0;
--
2.5.0
|