Commit b548867b authored by Andrew Morton's avatar Andrew Morton Committed by David S. Miller

[PATCH] register_blkdev() fixes

- It was racy, if two threads try to register a blockdev with major=0 they
  could both choose the same major for different devices.

  Fix that by extending the coverage of the rwsem.

- kmalloced local variable `p' was leaking on an error path.
parent 17817dc3
...@@ -102,25 +102,30 @@ int register_blkdev(unsigned int major, const char *name) ...@@ -102,25 +102,30 @@ int register_blkdev(unsigned int major, const char *name)
int index, ret = 0; int index, ret = 0;
unsigned long flags; unsigned long flags;
down_write(&block_subsys.rwsem);
/* temporary */ /* temporary */
if (major == 0) { if (major == 0) {
down_read(&block_subsys.rwsem); for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) {
for (index = ARRAY_SIZE(major_names)-1; index > 0; index--)
if (major_names[index] == NULL) if (major_names[index] == NULL)
break; break;
up_read(&block_subsys.rwsem); }
if (index == 0) { if (index == 0) {
printk("register_blkdev: failed to get major for %s\n", printk("register_blkdev: failed to get major for %s\n",
name); name);
return -EBUSY; ret = -EBUSY;
goto out;
} }
ret = major = index; major = index;
ret = major;
} }
p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL); p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL);
if (p == NULL) if (p == NULL) {
return -ENOMEM; ret = -ENOMEM;
goto out;
}
p->major = major; p->major = major;
strncpy(p->name, name, sizeof(p->name)-1); strncpy(p->name, name, sizeof(p->name)-1);
...@@ -128,22 +133,24 @@ int register_blkdev(unsigned int major, const char *name) ...@@ -128,22 +133,24 @@ int register_blkdev(unsigned int major, const char *name)
p->next = 0; p->next = 0;
index = major_to_index(major); index = major_to_index(major);
down_write(&block_subsys.rwsem);
spin_lock_irqsave(&major_names_lock, flags); spin_lock_irqsave(&major_names_lock, flags);
for (n = &major_names[index]; *n; n = &(*n)->next) for (n = &major_names[index]; *n; n = &(*n)->next) {
if ((*n)->major == major) if ((*n)->major == major)
break; break;
}
if (!*n) if (!*n)
*n = p; *n = p;
else else
ret = -EBUSY; ret = -EBUSY;
spin_unlock_irqrestore(&major_names_lock, flags); spin_unlock_irqrestore(&major_names_lock, flags);
up_write(&block_subsys.rwsem);
if (ret < 0) if (ret < 0) {
printk("register_blkdev: cannot get major %d for %s\n", printk("register_blkdev: cannot get major %d for %s\n",
major, name); major, name);
kfree(p);
}
out:
up_write(&block_subsys.rwsem);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment