linux-block.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] block: refactor register_blkdev() to compare major number when allocating unused major number
@ 2019-02-11  3:26 Chengguang Xu
  0 siblings, 0 replies; only message in thread
From: Chengguang Xu @ 2019-02-11  3:26 UTC (permalink / raw)
  To: axboe; +Cc: linux-block, Chengguang Xu

Currently when specifying major number as 0,
register_blkdev() will try to alloc any unused
major number in the range. However, the allocating
logic does not accuretaly compare major number
with existing entries, so even we have plenty of
available major numbers but still might fail with
-EBUSY in extreme case.

Signed-off-by: Chengguang Xu <cgxu519@gmx.com>
---
 block/genhd.c | 103 ++++++++++++++++++++++++++------------------------
 1 file changed, 54 insertions(+), 49 deletions(-)

diff --git a/block/genhd.c b/block/genhd.c
index 1dd8fd6613b8..80b788ed17d1 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -330,6 +330,40 @@ void blkdev_show(struct seq_file *seqf, off_t offset)
 }
 #endif /* CONFIG_PROC_FS */
 
+static int __register_blkdev(unsigned int major, const char *name,
+			     struct blk_major_name *new)
+{
+	struct blk_major_name *n, *p = NULL;
+	int index = major_to_index(major);
+
+	for (n = major_names[index]; n; n = n->next) {
+		if (n->major == major)
+			return -EBUSY;
+		p = n;
+	}
+
+	new->major = major;
+	if (p == NULL)
+		major_names[index] = new;
+	else
+		p->next = new;
+
+	return 0;
+}
+
+static int alloc_blkdev(unsigned int major, const char *name,
+			struct blk_major_name *new)
+{
+	int index;
+
+	for (index = ARRAY_SIZE(major_names) - 1; index; index--) {
+		if (__register_blkdev(index, name, new) == 0)
+			return index;
+	}
+
+	return -EBUSY;
+}
+
 /**
  * register_blkdev - register a new block device
  *
@@ -345,73 +379,44 @@ void blkdev_show(struct seq_file *seqf, off_t offset)
  *    then the function returns zero on success, or a negative error code
  *  - if any unused major number was requested with @major = 0 parameter
  *    then the return value is the allocated major number in range
- *    [1..BLKDEV_MAJOR_MAX-1] or a negative error code otherwise
+ *    [1..BLKDEV_MAJOR_HASH_SIZE-1] or a negative error code otherwise
  *
  * See Documentation/admin-guide/devices.txt for the list of allocated
  * major numbers.
  */
 int register_blkdev(unsigned int major, const char *name)
 {
-	struct blk_major_name **n, *p;
-	int index, ret = 0;
-
-	mutex_lock(&block_class_lock);
-
-	/* temporary */
-	if (major == 0) {
-		for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) {
-			if (major_names[index] == NULL)
-				break;
-		}
-
-		if (index == 0) {
-			printk("register_blkdev: failed to get major for %s\n",
-			       name);
-			ret = -EBUSY;
-			goto out;
-		}
-		major = index;
-		ret = major;
-	}
+	struct blk_major_name *new;
+	int ret;
 
 	if (major >= BLKDEV_MAJOR_MAX) {
-		pr_err("register_blkdev: major requested (%u) is greater than the maximum (%u) for %s\n",
-		       major, BLKDEV_MAJOR_MAX-1, name);
-
-		ret = -EINVAL;
-		goto out;
+		pr_err("%s: major requested (%u) is greater than the maximum (%u) for %s\n",
+			__func__, major, BLKDEV_MAJOR_MAX-1, name);
+		return -EINVAL;
 	}
 
-	p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL);
-	if (p == NULL) {
-		ret = -ENOMEM;
-		goto out;
-	}
+	new = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL);
+	if (new == NULL)
+		return -ENOMEM;
 
-	p->major = major;
-	strlcpy(p->name, name, sizeof(p->name));
-	p->next = NULL;
-	index = major_to_index(major);
+	strlcpy(new->name, name, sizeof(new->name));
+	new->next = NULL;
 
-	for (n = &major_names[index]; *n; n = &(*n)->next) {
-		if ((*n)->major == major)
-			break;
-	}
-	if (!*n)
-		*n = p;
+	mutex_lock(&block_class_lock);
+	if (major == 0)
+		ret = alloc_blkdev(major, name, new);
 	else
-		ret = -EBUSY;
+		ret = __register_blkdev(major, name, new);
+	mutex_unlock(&block_class_lock);
 
 	if (ret < 0) {
-		printk("register_blkdev: cannot get major %u for %s\n",
-		       major, name);
-		kfree(p);
+		kfree(new);
+		pr_err("%s: cannot get major for %s, major requested (%u)\n",
+			__func__, name, major);
 	}
-out:
-	mutex_unlock(&block_class_lock);
+
 	return ret;
 }
-
 EXPORT_SYMBOL(register_blkdev);
 
 void unregister_blkdev(unsigned int major, const char *name)
-- 
2.20.1


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2019-02-11  3:28 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-11  3:26 [PATCH] block: refactor register_blkdev() to compare major number when allocating unused major number Chengguang Xu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).