read_lock(&gendisk_lock);
if (gendisks[major].get) {
disk = gendisks[major].get(minor);
+ if (disk)
+ get_disk(disk);
read_unlock(&gendisk_lock);
return disk;
}
continue;
if (disk->first_minor + disk->minors <= minor)
continue;
+ get_disk(disk);
read_unlock(&gendisk_lock);
*part = minor - disk->first_minor;
return disk;
return disk;
}
+struct gendisk *get_disk(struct gendisk *disk)
+{
+ atomic_inc(&disk->disk_dev.refcount);
+ return disk;
+}
+
void put_disk(struct gendisk *disk)
{
if (disk)
}
EXPORT_SYMBOL(alloc_disk);
+EXPORT_SYMBOL(get_disk);
EXPORT_SYMBOL(put_disk);
disk = get_gendisk(bdev->bd_dev, &part);
if (!disk)
return -ENXIO;
- if (bdev != bdev->bd_contains)
+ if (bdev != bdev->bd_contains) {
+ put_disk(disk);
return -EINVAL;
+ }
if (part)
BUG();
part = p.pno;
- if (part <= 0 || part >= disk->minors)
+ if (part <= 0 || part >= disk->minors) {
+ put_disk(disk);
return -EINVAL;
+ }
switch (a.op) {
case BLKPG_ADD_PARTITION:
sizeof(long long) > sizeof(long)) {
long pstart = start, plength = length;
if (pstart != start || plength != length
- || pstart < 0 || plength < 0)
+ || pstart < 0 || plength < 0) {
+ put_disk(disk);
return -EINVAL;
+ }
}
/* partition number in use? */
- if (disk->part[part - 1].nr_sects != 0)
+ if (disk->part[part - 1].nr_sects != 0) {
+ put_disk(disk);
return -EBUSY;
+ }
/* overlap? */
for (i = 0; i < disk->minors - 1; i++) {
struct hd_struct *s = &disk->part[i];
if (!(start+length <= s->start_sect ||
- start >= s->start_sect + s->nr_sects))
+ start >= s->start_sect + s->nr_sects)) {
+ put_disk(disk);
return -EBUSY;
+ }
}
/* all seems OK */
add_partition(disk, part, start, length);
+ put_disk(disk);
return 0;
case BLKPG_DEL_PARTITION:
- if (disk->part[part - 1].nr_sects == 0)
+ if (disk->part[part - 1].nr_sects == 0) {
+ put_disk(disk);
return -ENXIO;
+ }
/* partition in use? Incomplete check for now. */
bdevp = bdget(MKDEV(disk->major, disk->first_minor) + part);
- if (!bdevp)
+ if (!bdevp) {
+ put_disk(disk);
return -ENOMEM;
+ }
if (bd_claim(bdevp, &holder) < 0) {
bdput(bdevp);
+ put_disk(disk);
return -EBUSY;
}
delete_partition(disk, part);
bd_release(bdevp);
bdput(bdevp);
+ put_disk(disk);
return 0;
default:
+ put_disk(disk);
return -EINVAL;
}
}
struct gendisk *disk = get_gendisk(bdev->bd_dev, &part);
int res = 0;
- if (!disk || disk->minors == 1 || bdev != bdev->bd_contains)
+ if (!disk)
return -EINVAL;
+ if (disk->minors == 1 || bdev != bdev->bd_contains) {
+ put_disk(disk);
+ return -EINVAL;
+ }
if (part)
BUG();
- if (!capable(CAP_SYS_ADMIN))
+ if (!capable(CAP_SYS_ADMIN)) {
+ put_disk(disk);
return -EACCES;
- if (down_trylock(&bdev->bd_sem))
+ }
+ if (down_trylock(&bdev->bd_sem)) {
+ put_disk(disk);
return -EBUSY;
+ }
res = rescan_partitions(disk, bdev);
up(&bdev->bd_sem);
+ put_disk(disk);
return res;
}
bdops->revalidate(dev);
if (disk && disk->minors > 1)
bdev->bd_invalidated = 1;
+ put_disk(disk);
return 1;
}
BUG();
down(&bdev->bd_sem);
if (check_disk_change(bdev)) {
- rescan_partitions(get_gendisk(bdev->bd_dev, &n), bdev);
+ struct gendisk *disk = get_gendisk(bdev->bd_dev, &n);
+ rescan_partitions(disk, bdev);
+ put_disk(disk);
res = 1;
}
up(&bdev->bd_sem);
struct block_device *disk;
disk = bdget(MKDEV(g->major, g->first_minor));
ret = -ENOMEM;
- if (!disk)
+ if (!disk) {
+ put_disk(g);
goto out1;
+ }
ret = blkdev_get(disk, file->f_mode, file->f_flags, BDEV_RAW);
- if (ret)
+ if (ret) {
+ put_disk(g);
goto out1;
+ }
bdev->bd_contains = disk;
}
+ put_disk(g);
}
if (bdev->bd_contains == bdev) {
int part;
if (bdev->bd_op->open) {
ret = bdev->bd_op->open(inode, file);
- if (ret)
+ if (ret) {
+ put_disk(g);
goto out2;
+ }
}
if (!bdev->bd_openers) {
struct backing_dev_info *bdi;
}
if (bdev->bd_invalidated)
rescan_partitions(g, bdev);
+ put_disk(g);
} else {
down(&bdev->bd_contains->bd_sem);
bdev->bd_contains->bd_part_count++;
inode->i_data.backing_dev_info =
bdev->bd_inode->i_data.backing_dev_info =
bdev->bd_contains->bd_inode->i_data.backing_dev_info;
- if (!p->nr_sects) {
+ if (!(g->flags & GENHD_FL_UP) || !p->nr_sects) {
bdev->bd_contains->bd_part_count--;
up(&bdev->bd_contains->bd_sem);
+ put_disk(g);
ret = -ENXIO;
goto out2;
}
bdev->bd_queue = bdev->bd_contains->bd_queue;
bdev->bd_offset = p->start_sect;
bd_set_size(bdev, (loff_t) p->nr_sects << 9);
+ put_disk(g);
}
up(&bdev->bd_contains->bd_sem);
}
dname->name = NULL;
if (hd)
dname->name = disk_name(hd, part, dname->namebuf);
+ put_disk(hd);
if (!dname->name) {
sprintf(dname->namebuf, "[dev %s]", kdevname(to_kdev_t(dev)));
dname->name = dname->namebuf;
extern void delete_partition(struct gendisk *, int);
extern struct gendisk *alloc_disk(int minors);
+extern struct gendisk *get_disk(struct gendisk *disk);
extern void put_disk(struct gendisk *disk);
/* will go away */
static inline unsigned int disk_index (kdev_t dev)
{
- int part;
+ int part, res;
struct gendisk *g = get_gendisk(kdev_t_to_nr(dev), &part);
- return g ? (minor(dev) >> g->minor_shift) : 0;
+ res = g ? (minor(dev) >> g->minor_shift) : 0;
+ put_disk(g);
+ return res;
}
#endif