diff options
Diffstat (limited to 'fs/char_dev.c')
-rw-r--r-- | fs/char_dev.c | 28 |
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); |