hc
2023-12-08 01573e231f18eb2d99162747186f59511f56b64d
kernel/fs/char_dev.c
....@@ -88,21 +88,30 @@
8888 /*
8989 * Register a single major with a specified minor range.
9090 *
91
- * If major == 0 this functions will dynamically allocate a major and return
92
- * its number.
91
+ * If major == 0 this function will dynamically allocate an unused major.
92
+ * If major > 0 this function will attempt to reserve the range of minors
93
+ * with given major.
9394 *
94
- * If major > 0 this function will attempt to reserve the passed range of
95
- * minors and will return zero on success.
96
- *
97
- * Returns a -ve errno on failure.
9895 */
9996 static struct char_device_struct *
10097 __register_chrdev_region(unsigned int major, unsigned int baseminor,
10198 int minorct, const char *name)
10299 {
103
- struct char_device_struct *cd, **cp;
104
- int ret = 0;
100
+ struct char_device_struct *cd, *curr, *prev = NULL;
101
+ int ret;
105102 int i;
103
+
104
+ if (major >= CHRDEV_MAJOR_MAX) {
105
+ pr_err("CHRDEV \"%s\" major requested (%u) is greater than the maximum (%u)\n",
106
+ name, major, CHRDEV_MAJOR_MAX-1);
107
+ return ERR_PTR(-EINVAL);
108
+ }
109
+
110
+ if (minorct > MINORMASK + 1 - baseminor) {
111
+ pr_err("CHRDEV \"%s\" minor range requested (%u-%u) is out of range of maximum range (%u-%u) for a single major\n",
112
+ name, baseminor, baseminor + minorct - 1, 0, MINORMASK);
113
+ return ERR_PTR(-EINVAL);
114
+ }
106115
107116 cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);
108117 if (cd == NULL)
....@@ -120,10 +129,21 @@
120129 major = ret;
121130 }
122131
123
- if (major >= CHRDEV_MAJOR_MAX) {
124
- pr_err("CHRDEV \"%s\" major requested (%u) is greater than the maximum (%u)\n",
125
- name, major, CHRDEV_MAJOR_MAX-1);
126
- ret = -EINVAL;
132
+ ret = -EBUSY;
133
+ i = major_to_index(major);
134
+ for (curr = chrdevs[i]; curr; prev = curr, curr = curr->next) {
135
+ if (curr->major < major)
136
+ continue;
137
+
138
+ if (curr->major > major)
139
+ break;
140
+
141
+ if (curr->baseminor + curr->minorct <= baseminor)
142
+ continue;
143
+
144
+ if (curr->baseminor >= baseminor + minorct)
145
+ break;
146
+
127147 goto out;
128148 }
129149
....@@ -132,43 +152,14 @@
132152 cd->minorct = minorct;
133153 strlcpy(cd->name, name, sizeof(cd->name));
134154
135
- i = major_to_index(major);
136
-
137
- for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
138
- if ((*cp)->major > major ||
139
- ((*cp)->major == major &&
140
- (((*cp)->baseminor >= baseminor) ||
141
- ((*cp)->baseminor + (*cp)->minorct > baseminor))))
142
- break;
143
-
144
- /* Check for overlapping minor ranges. */
145
- if (*cp && (*cp)->major == major) {
146
- int old_min = (*cp)->baseminor;
147
- int old_max = (*cp)->baseminor + (*cp)->minorct - 1;
148
- int new_min = baseminor;
149
- int new_max = baseminor + minorct - 1;
150
-
151
- /* New driver overlaps from the left. */
152
- if (new_max >= old_min && new_max <= old_max) {
153
- ret = -EBUSY;
154
- goto out;
155
- }
156
-
157
- /* New driver overlaps from the right. */
158
- if (new_min <= old_max && new_min >= old_min) {
159
- ret = -EBUSY;
160
- goto out;
161
- }
162
-
163
- if (new_min < old_min && new_max > old_max) {
164
- ret = -EBUSY;
165
- goto out;
166
- }
167
-
155
+ if (!prev) {
156
+ cd->next = curr;
157
+ chrdevs[i] = cd;
158
+ } else {
159
+ cd->next = prev->next;
160
+ prev->next = cd;
168161 }
169162
170
- cd->next = *cp;
171
- *cp = cd;
172163 mutex_unlock(&chrdevs_lock);
173164 return cd;
174165 out:
....@@ -492,6 +483,9 @@
492483 p->dev = dev;
493484 p->count = count;
494485
486
+ if (WARN_ON(dev == WHITEOUT_DEV))
487
+ return -EBUSY;
488
+
495489 error = kobj_map(cdev_map, dev, count, NULL,
496490 exact_match, exact_lock, p);
497491 if (error)