Commit 68c16870 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] refcounts for gendisks

Finally.  We use disk->dev.refcount as a gendisk refcount.  New helper -
get_disk(): atomic_inc on refcount.  get_gendisk() does it on return,
callers of get_gendisk() do put_disk() when they are done.
parent b288f6ad
...@@ -100,6 +100,8 @@ get_gendisk(dev_t dev, int *part) ...@@ -100,6 +100,8 @@ get_gendisk(dev_t dev, int *part)
read_lock(&gendisk_lock); read_lock(&gendisk_lock);
if (gendisks[major].get) { if (gendisks[major].get) {
disk = gendisks[major].get(minor); disk = gendisks[major].get(minor);
if (disk)
get_disk(disk);
read_unlock(&gendisk_lock); read_unlock(&gendisk_lock);
return disk; return disk;
} }
...@@ -109,6 +111,7 @@ get_gendisk(dev_t dev, int *part) ...@@ -109,6 +111,7 @@ get_gendisk(dev_t dev, int *part)
continue; continue;
if (disk->first_minor + disk->minors <= minor) if (disk->first_minor + disk->minors <= minor)
continue; continue;
get_disk(disk);
read_unlock(&gendisk_lock); read_unlock(&gendisk_lock);
*part = minor - disk->first_minor; *part = minor - disk->first_minor;
return disk; return disk;
...@@ -244,6 +247,12 @@ struct gendisk *alloc_disk(int minors) ...@@ -244,6 +247,12 @@ struct gendisk *alloc_disk(int minors)
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) void put_disk(struct gendisk *disk)
{ {
if (disk) if (disk)
...@@ -251,4 +260,5 @@ void put_disk(struct gendisk *disk) ...@@ -251,4 +260,5 @@ void put_disk(struct gendisk *disk)
} }
EXPORT_SYMBOL(alloc_disk); EXPORT_SYMBOL(alloc_disk);
EXPORT_SYMBOL(get_disk);
EXPORT_SYMBOL(put_disk); EXPORT_SYMBOL(put_disk);
...@@ -25,13 +25,17 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg) ...@@ -25,13 +25,17 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
disk = get_gendisk(bdev->bd_dev, &part); disk = get_gendisk(bdev->bd_dev, &part);
if (!disk) if (!disk)
return -ENXIO; return -ENXIO;
if (bdev != bdev->bd_contains) if (bdev != bdev->bd_contains) {
put_disk(disk);
return -EINVAL; return -EINVAL;
}
if (part) if (part)
BUG(); BUG();
part = p.pno; part = p.pno;
if (part <= 0 || part >= disk->minors) if (part <= 0 || part >= disk->minors) {
put_disk(disk);
return -EINVAL; return -EINVAL;
}
switch (a.op) { switch (a.op) {
case BLKPG_ADD_PARTITION: case BLKPG_ADD_PARTITION:
...@@ -42,34 +46,46 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg) ...@@ -42,34 +46,46 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
sizeof(long long) > sizeof(long)) { sizeof(long long) > sizeof(long)) {
long pstart = start, plength = length; long pstart = start, plength = length;
if (pstart != start || plength != length if (pstart != start || plength != length
|| pstart < 0 || plength < 0) || pstart < 0 || plength < 0) {
put_disk(disk);
return -EINVAL; return -EINVAL;
} }
}
/* partition number in use? */ /* 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; return -EBUSY;
}
/* overlap? */ /* overlap? */
for (i = 0; i < disk->minors - 1; i++) { for (i = 0; i < disk->minors - 1; i++) {
struct hd_struct *s = &disk->part[i]; struct hd_struct *s = &disk->part[i];
if (!(start+length <= s->start_sect || 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; return -EBUSY;
} }
}
/* all seems OK */ /* all seems OK */
add_partition(disk, part, start, length); add_partition(disk, part, start, length);
put_disk(disk);
return 0; return 0;
case BLKPG_DEL_PARTITION: 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; return -ENXIO;
}
/* partition in use? Incomplete check for now. */ /* partition in use? Incomplete check for now. */
bdevp = bdget(MKDEV(disk->major, disk->first_minor) + part); bdevp = bdget(MKDEV(disk->major, disk->first_minor) + part);
if (!bdevp) if (!bdevp) {
put_disk(disk);
return -ENOMEM; return -ENOMEM;
}
if (bd_claim(bdevp, &holder) < 0) { if (bd_claim(bdevp, &holder) < 0) {
bdput(bdevp); bdput(bdevp);
put_disk(disk);
return -EBUSY; return -EBUSY;
} }
...@@ -80,8 +96,10 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg) ...@@ -80,8 +96,10 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
delete_partition(disk, part); delete_partition(disk, part);
bd_release(bdevp); bd_release(bdevp);
bdput(bdevp); bdput(bdevp);
put_disk(disk);
return 0; return 0;
default: default:
put_disk(disk);
return -EINVAL; return -EINVAL;
} }
} }
...@@ -92,16 +110,25 @@ static int blkdev_reread_part(struct block_device *bdev) ...@@ -92,16 +110,25 @@ static int blkdev_reread_part(struct block_device *bdev)
struct gendisk *disk = get_gendisk(bdev->bd_dev, &part); struct gendisk *disk = get_gendisk(bdev->bd_dev, &part);
int res = 0; 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; return -EINVAL;
}
if (part) if (part)
BUG(); BUG();
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN)) {
put_disk(disk);
return -EACCES; return -EACCES;
if (down_trylock(&bdev->bd_sem)) }
if (down_trylock(&bdev->bd_sem)) {
put_disk(disk);
return -EBUSY; return -EBUSY;
}
res = rescan_partitions(disk, bdev); res = rescan_partitions(disk, bdev);
up(&bdev->bd_sem); up(&bdev->bd_sem);
put_disk(disk);
return res; return res;
} }
......
...@@ -542,6 +542,7 @@ int check_disk_change(struct block_device *bdev) ...@@ -542,6 +542,7 @@ int check_disk_change(struct block_device *bdev)
bdops->revalidate(dev); bdops->revalidate(dev);
if (disk && disk->minors > 1) if (disk && disk->minors > 1)
bdev->bd_invalidated = 1; bdev->bd_invalidated = 1;
put_disk(disk);
return 1; return 1;
} }
...@@ -553,7 +554,9 @@ int full_check_disk_change(struct block_device *bdev) ...@@ -553,7 +554,9 @@ int full_check_disk_change(struct block_device *bdev)
BUG(); BUG();
down(&bdev->bd_sem); down(&bdev->bd_sem);
if (check_disk_change(bdev)) { 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; res = 1;
} }
up(&bdev->bd_sem); up(&bdev->bd_sem);
...@@ -622,13 +625,18 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file * ...@@ -622,13 +625,18 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
struct block_device *disk; struct block_device *disk;
disk = bdget(MKDEV(g->major, g->first_minor)); disk = bdget(MKDEV(g->major, g->first_minor));
ret = -ENOMEM; ret = -ENOMEM;
if (!disk) if (!disk) {
put_disk(g);
goto out1; goto out1;
}
ret = blkdev_get(disk, file->f_mode, file->f_flags, BDEV_RAW); ret = blkdev_get(disk, file->f_mode, file->f_flags, BDEV_RAW);
if (ret) if (ret) {
put_disk(g);
goto out1; goto out1;
}
bdev->bd_contains = disk; bdev->bd_contains = disk;
} }
put_disk(g);
} }
if (bdev->bd_contains == bdev) { if (bdev->bd_contains == bdev) {
int part; int part;
...@@ -643,9 +651,11 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file * ...@@ -643,9 +651,11 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
if (bdev->bd_op->open) { if (bdev->bd_op->open) {
ret = bdev->bd_op->open(inode, file); ret = bdev->bd_op->open(inode, file);
if (ret) if (ret) {
put_disk(g);
goto out2; goto out2;
} }
}
if (!bdev->bd_openers) { if (!bdev->bd_openers) {
struct backing_dev_info *bdi; struct backing_dev_info *bdi;
sector_t sect = 0; sector_t sect = 0;
...@@ -662,6 +672,7 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file * ...@@ -662,6 +672,7 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
} }
if (bdev->bd_invalidated) if (bdev->bd_invalidated)
rescan_partitions(g, bdev); rescan_partitions(g, bdev);
put_disk(g);
} else { } else {
down(&bdev->bd_contains->bd_sem); down(&bdev->bd_contains->bd_sem);
bdev->bd_contains->bd_part_count++; bdev->bd_contains->bd_part_count++;
...@@ -673,15 +684,17 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file * ...@@ -673,15 +684,17 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
inode->i_data.backing_dev_info = inode->i_data.backing_dev_info =
bdev->bd_inode->i_data.backing_dev_info = bdev->bd_inode->i_data.backing_dev_info =
bdev->bd_contains->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--; bdev->bd_contains->bd_part_count--;
up(&bdev->bd_contains->bd_sem); up(&bdev->bd_contains->bd_sem);
put_disk(g);
ret = -ENXIO; ret = -ENXIO;
goto out2; goto out2;
} }
bdev->bd_queue = bdev->bd_contains->bd_queue; bdev->bd_queue = bdev->bd_contains->bd_queue;
bdev->bd_offset = p->start_sect; bdev->bd_offset = p->start_sect;
bd_set_size(bdev, (loff_t) p->nr_sects << 9); bd_set_size(bdev, (loff_t) p->nr_sects << 9);
put_disk(g);
} }
up(&bdev->bd_contains->bd_sem); up(&bdev->bd_contains->bd_sem);
} }
......
...@@ -616,6 +616,7 @@ char *partition_name(dev_t dev) ...@@ -616,6 +616,7 @@ char *partition_name(dev_t dev)
dname->name = NULL; dname->name = NULL;
if (hd) if (hd)
dname->name = disk_name(hd, part, dname->namebuf); dname->name = disk_name(hd, part, dname->namebuf);
put_disk(hd);
if (!dname->name) { if (!dname->name) {
sprintf(dname->namebuf, "[dev %s]", kdevname(to_kdev_t(dev))); sprintf(dname->namebuf, "[dev %s]", kdevname(to_kdev_t(dev)));
dname->name = dname->namebuf; dname->name = dname->namebuf;
......
...@@ -266,6 +266,7 @@ extern void add_partition(struct gendisk *, int, sector_t, sector_t); ...@@ -266,6 +266,7 @@ extern void add_partition(struct gendisk *, int, sector_t, sector_t);
extern void delete_partition(struct gendisk *, int); extern void delete_partition(struct gendisk *, int);
extern struct gendisk *alloc_disk(int minors); extern struct gendisk *alloc_disk(int minors);
extern struct gendisk *get_disk(struct gendisk *disk);
extern void put_disk(struct gendisk *disk); extern void put_disk(struct gendisk *disk);
/* will go away */ /* will go away */
...@@ -273,9 +274,11 @@ extern void blk_set_probe(int major, struct gendisk *(p)(int)); ...@@ -273,9 +274,11 @@ extern void blk_set_probe(int major, struct gendisk *(p)(int));
static inline unsigned int disk_index (kdev_t dev) 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); 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 #endif
......
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