]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] refcounts for gendisks
authorAlexander Viro <viro@math.psu.edu>
Tue, 15 Oct 2002 11:25:32 +0000 (04:25 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Tue, 15 Oct 2002 11:25:32 +0000 (04:25 -0700)
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.

drivers/block/genhd.c
drivers/block/ioctl.c
fs/block_dev.c
fs/partitions/check.c
include/linux/genhd.h

index ecb2dcdf214d13327bbf0b47a33d056275e1967f..1cc4655c04c99c03cb14571d74985f2afda2332c 100644 (file)
@@ -100,6 +100,8 @@ get_gendisk(dev_t dev, int *part)
        read_lock(&gendisk_lock);
        if (gendisks[major].get) {
                disk = gendisks[major].get(minor);
+               if (disk)
+                       get_disk(disk);
                read_unlock(&gendisk_lock);
                return disk;
        }
@@ -109,6 +111,7 @@ get_gendisk(dev_t dev, int *part)
                        continue;
                if (disk->first_minor + disk->minors <= minor)
                        continue;
+               get_disk(disk);
                read_unlock(&gendisk_lock);
                *part = minor - disk->first_minor;
                return disk;
@@ -244,6 +247,12 @@ struct gendisk *alloc_disk(int minors)
        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)
@@ -251,4 +260,5 @@ void put_disk(struct gendisk *disk)
 }
 
 EXPORT_SYMBOL(alloc_disk);
+EXPORT_SYMBOL(get_disk);
 EXPORT_SYMBOL(put_disk);
index 4af05bc32db2b0040de8c5fc9385adacc00b8b0e..de2da2b44cad94f2ca0bc8cafa37370f206ede50 100644 (file)
@@ -25,13 +25,17 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
        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:
@@ -42,34 +46,46 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
                            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;
                        }
 
@@ -80,8 +96,10 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
                        delete_partition(disk, part);
                        bd_release(bdevp);
                        bdput(bdevp);
+                       put_disk(disk);
                        return 0;
                default:
+                       put_disk(disk);
                        return -EINVAL;
        }
 }
@@ -92,16 +110,25 @@ static int blkdev_reread_part(struct block_device *bdev)
        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;
 }
 
index dff0244e63a6c1564cbbf6828f24b42551bb0613..d029636b07e66f466e530678b74849fba3ec2d97 100644 (file)
@@ -542,6 +542,7 @@ int check_disk_change(struct block_device *bdev)
                bdops->revalidate(dev);
        if (disk && disk->minors > 1)
                bdev->bd_invalidated = 1;
+       put_disk(disk);
        return 1;
 }
 
@@ -553,7 +554,9 @@ int full_check_disk_change(struct block_device *bdev)
                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);
@@ -622,13 +625,18 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
                        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;
@@ -643,8 +651,10 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
 
                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;
@@ -662,6 +672,7 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
                }
                if (bdev->bd_invalidated)
                        rescan_partitions(g, bdev);
+               put_disk(g);
        } else {
                down(&bdev->bd_contains->bd_sem);
                bdev->bd_contains->bd_part_count++;
@@ -673,15 +684,17 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
                        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);
        }
index 5fc23d047567242f4bb3764db662aad9e2f9f72b..e6ed1a44311650d0fc094abcb1469f430091597f 100644 (file)
@@ -616,6 +616,7 @@ char *partition_name(dev_t dev)
        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;
index 6b859fad6a8a5cdd02b2cc84d8f60973fc0ac046..030ee2f87891e7d4683cb595d2380c222c39c7f3 100644 (file)
@@ -266,6 +266,7 @@ extern void add_partition(struct gendisk *, int, sector_t, sector_t);
 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 */
@@ -273,9 +274,11 @@ extern void blk_set_probe(int major, struct gendisk *(p)(int));
 
 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