aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/char_dev.c28
1 files changed, 23 insertions, 5 deletions
diff --git a/fs/char_dev.c b/fs/char_dev.c
index 0009346d827f..33b95af89da4 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -128,13 +128,31 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
128 128
129 for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) 129 for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
130 if ((*cp)->major > major || 130 if ((*cp)->major > major ||
131 ((*cp)->major == major && (*cp)->baseminor >= baseminor)) 131 ((*cp)->major == major &&
132 (((*cp)->baseminor >= baseminor) ||
133 ((*cp)->baseminor + (*cp)->minorct > baseminor))))
132 break; 134 break;
133 if (*cp && (*cp)->major == major && 135
134 (*cp)->baseminor < baseminor + minorct) { 136 /* Check for overlapping minor ranges. */
135 ret = -EBUSY; 137 if (*cp && (*cp)->major == major) {
136 goto out; 138 int old_min = (*cp)->baseminor;
139 int old_max = (*cp)->baseminor + (*cp)->minorct - 1;
140 int new_min = baseminor;
141 int new_max = baseminor + minorct - 1;
142
143 /* New driver overlaps from the left. */
144 if (new_max >= old_min && new_max <= old_max) {
145 ret = -EBUSY;
146 goto out;
147 }
148
149 /* New driver overlaps from the right. */
150 if (new_min <= old_max && new_min >= old_min) {
151 ret = -EBUSY;
152 goto out;
153 }
137 } 154 }
155
138 cd->next = *cp; 156 cd->next = *cp;
139 *cp = cd; 157 *cp = cd;
140 mutex_unlock(&chrdevs_lock); 158 mutex_unlock(&chrdevs_lock);