]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] partition handling locking cleanups
authorAlexander Viro <viro@math.psu.edu>
Sun, 21 Jul 2002 03:48:09 +0000 (20:48 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Sun, 21 Jul 2002 03:48:09 +0000 (20:48 -0700)
Horrors with open/reread_partition exclusion are starting to get fixed.

It's not the final variant, but at least we are getting the logics into
one place; switch to final variant will happen once we get per-disk
analog of gendisks.  New fields - ->bd_part_sem and ->bd_part_count.

The latter counts the amount of opened partitions.  The former protects
said count _and_ is held while we are rereading partition tables.
Helpers - dev_part_lock()/dev_part_unlock() (currently taking kdev_t; that
will change pretty soon).  No more ->open() and ->release() for partitions,
all that logics went to generic code.  Lock hierachy is currently messy:

  ->bd_sem for partitions -> ->bd_part_sem -> ->bd_sem for entire disks

Ugly, but that'll go away and to get the final variant of locking right
now would take _really_ big patch - with a lot of steps glued together.
The damn thing is large as it is...

18 files changed:
drivers/acorn/block/mfmhd.c
drivers/block/acsi.c
drivers/block/cciss.c
drivers/block/cpqarray.c
drivers/block/paride/pd.c
drivers/block/ps2esdi.c
drivers/block/umem.c
drivers/block/xd.c
drivers/block/xd.h
drivers/ide/hd.c
drivers/ide/ide.c
drivers/ide/main.c
drivers/mtd/ftl.c
drivers/mtd/nftlcore.c
drivers/scsi/sd.c
fs/block_dev.c
fs/partitions/check.c
include/linux/fs.h

index 18a646b13141df17281013d13867e84b2a04634e..5a209981436c4e299e7dacca86270a63807ba7db 100644 (file)
@@ -184,8 +184,6 @@ struct mfm_info {
 #define NEED_1_RECAL -2
 #define NEED_2_RECAL -3
                 int cylinder;
-       unsigned int access_count;
-       unsigned int busy;
        struct {
                char recal;
                char report;
@@ -197,7 +195,6 @@ struct mfm_info {
 
 static struct hd_struct mfm[MFM_MAXDRIVES << 6];
 static int mfm_sizes[MFM_MAXDRIVES << 6];
-static DECLARE_WAIT_QUEUE_HEAD(mfm_wait_open);
 
 /* Stuff from the assembly routines */
 extern unsigned int hdc63463_baseaddress;      /* Controller base address */
@@ -1219,24 +1216,8 @@ static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long a
 static int mfm_open(struct inode *inode, struct file *file)
 {
        int dev = DEVICE_NR(minor(inode->i_rdev));
-
        if (dev >= mfm_drives)
                return -ENODEV;
-
-       while (mfm_info[dev].busy)
-               sleep_on (&mfm_wait_open);
-
-       mfm_info[dev].access_count++;
-       return 0;
-}
-
-/*
- * Releasing a block device means we sync() it, so that it can safely
- * be forgotten about...
- */
-static int mfm_release(struct inode *inode, struct file *file)
-{
-       mfm_info[DEVICE_NR(minor(inode->i_rdev))].access_count--;
        return 0;
 }
 
@@ -1296,7 +1277,6 @@ static struct block_device_operations mfm_fops =
 {
        owner:          THIS_MODULE,
        open:           mfm_open,
-       release:        mfm_release,
        ioctl:          mfm_ioctl,
 };
 
@@ -1425,33 +1405,19 @@ int mfm_init (void)
 /*
  * This routine is called to flush all partitions and partition tables
  * for a changed MFM disk, and then re-read the new partition table.
- * If we are revalidating due to an ioctl, we have USAGE == 1.
  */
 static int mfm_reread_partitions(kdev_t dev)
 {
-       unsigned int start, i, maxp, target = DEVICE_NR(minor(dev));
-       unsigned long flags;
-
-       local_irq_save(flags);
-       if (mfm_info[target].busy || mfm_info[target].access_count > 1) {
-               local_irq_restore (flags);
-               return -EBUSY;
-       }
-       mfm_info[target].busy = 1;
-       local_irq_restore (flags);
-
-       maxp = 1 << mfm_gendisk.minor_shift;
-       start = target << mfm_gendisk.minor_shift;
-
-       wipe_partitions(mk_kdev(MAJOR_NR, start));
-
+       unsigned int unit = DEVICE_NR(minor(dev));
+       kdev_t device = mk_kdev(MAJOR_NR, unit << mfm_gendisk.minor_shift);
+       int err = dev_lock_part(device);
+       if (err)
+               return err;
+       wipe_partitions(device);
        /* Divide by 2, since sectors are 2 times smaller than usual ;-) */
-
-       grok_partitions(&mfm_gendisk, target, 1<<6, mfm_info[target].heads *
-                   mfm_info[target].cylinders * mfm_info[target].sectors / 2);
-
-       mfm_info[target].busy = 0;
-       wake_up (&mfm_wait_open);
+       grok_partitions(device, mfm_info[unit].heads *
+                   mfm_info[unit].cylinders * mfm_info[unit].sectors / 2);
+       dev_unlock_part(device);
        return 0;
 }
 
index c35ef7f77e40a040af3ea8d8948f3823c5ea8801..7ca3722d8ce97cea5ec55fcc09a66877527b0b27 100644 (file)
@@ -248,8 +248,6 @@ static int                          NDevices = 0;
 static int                             acsi_sizes[MAX_DEV<<4] = { 0, };
 static struct hd_struct        acsi_part[MAX_DEV<<4] = { {0,0}, };
 static int                             access_count[MAX_DEV] = { 0, };
-static char                    busy[MAX_DEV] = { 0, };
-static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
 
 static int                             CurrentNReq;
 static int                             CurrentNSect;
@@ -1161,8 +1159,6 @@ static int acsi_open( struct inode * inode, struct file * filp )
        if (device >= NDevices)
                return -ENXIO;
        aip = &acsi_info[device];
-       while (busy[device])
-               sleep_on(&busy_wait);
 
        if (access_count[device] == 0 && aip->removable) {
 #if 0
@@ -1803,10 +1799,6 @@ void cleanup_module(void)
 }
 #endif
 
-#define DEVICE_BUSY busy[device]
-#define USAGE access_count[device]
-#define GENDISK_STRUCT acsi_gendisk
-
 /*
  * This routine is called to flush all partitions and partition tables
  * for a changed scsi disk, and then re-read the new partition table.
@@ -1828,24 +1820,15 @@ void cleanup_module(void)
 
 static int revalidate_acsidisk( int dev, int maxusage )
 {
-       int device;
-       struct gendisk * gdev;
-       int res;
-       struct acsi_info_struct *aip;
-       
-       device = DEVICE_NR(minor(dev));
-       aip = &acsi_info[device];
-       gdev = &GENDISK_STRUCT;
+       int unit = DEVICE_NR(minor(dev));
+       struct acsi_info_struct *aip = &acsi_info[unit];
+       kdev_t device = mk_kdev(MAJOR_NR, unit<<4);
+       int res = dev_lock_part(device);
 
-       cli();
-       if (DEVICE_BUSY || USAGE > maxusage) {
-               sti();
-               return -EBUSY;
-       };
-       DEVICE_BUSY = 1;
-       sti();
+       if (res < 0)
+               return res;
 
-       res = wipe_partitions(dev);
+       res = wipe_partitions(device);
 
        stdma_lock( NULL, NULL );
 
@@ -1862,10 +1845,9 @@ static int revalidate_acsidisk( int dev, int maxusage )
        stdma_release();
 
        if (!res)
-               grok_partitions(dev, aip->size);
+               grok_partitions(device, aip->size);
 
-       DEVICE_BUSY = 0;
-       wake_up(&busy_wait);
+       dev_unlock_part(device);
        return res;
 }
 
index 5f288efeab7e5d4eab94c8771d9dbacd6cd81023..8c7033f3220be7a0be45104b0d918e41b8a9db4b 100644 (file)
@@ -735,6 +735,10 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
 }
 
 /* Borrowed and adapted from sd.c */
+/*
+ * FIXME: we are missing the exclusion with ->open() here - it can happen
+ * just as we are rereading partition tables.
+ */
 static int revalidate_logvol(kdev_t dev, int maxusage)
 {
         int ctlr, target;
@@ -1304,13 +1308,12 @@ static int register_new_disk(kdev_t dev, int ctlr)
        hba[ctlr]->drv[logvol].usage_count = 0;
        max_p = 1 << gdev->minor_shift;
         start = logvol<< gdev->minor_shift;
+       kdev = mk_kdev(MAJOR_NR + ctlr, logvol<< gdev->minor_shift);
 
-       wipe_partitions(MAJOR_NR + ctlr, start);
-
+       wipe_partitions(kdev);
        ++hba[ctlr]->num_luns;
        gdev->nr_real = hba[ctlr]->highest_lun + 1;
        /* setup partitions per disk */
-       kdev = mk_kdev(MAJOR_NR + ctlr, logvol<< gdev->minor_shift);
        grok_partitions(kdev, hba[ctlr]->drv[logvol].nr_blocks);
        
        kfree(ld_buff);
index fccef1bb792c36a2f0c423893435832b30c8db5a..124cbf046ce3596d075ec8504cc1505171040ffb 100644 (file)
@@ -1533,6 +1533,9 @@ static int revalidate_allvol(kdev_t dev)
 }
 
 /* Borrowed and adapted from sd.c */
+/*
+ * FIXME: exclusion with ->open()
+ */
 static int revalidate_logvol(kdev_t dev, int maxusage)
 {
        int ctlr, target;
index cb10da16d13685f69d61d77be7a4bf892fdebae6..6e661e064da0bd5fe07df1077e0437445c195cab 100644 (file)
@@ -414,12 +414,11 @@ int pd_init (void)
 }
 
 static int pd_open (struct inode *inode, struct file *file)
+{
+       int unit = DEVICE_NR(inode->i_rdev);
 
-{       int unit = DEVICE_NR(inode->i_rdev);
-
-        if ((unit >= PD_UNITS) || (!PD.present)) return -ENODEV;
-
-       wait_event (pd_wait_open, pd_valid);
+        if ((unit >= PD_UNITS) || (!PD.present))
+               return -ENODEV;
 
         PD.access++;
 
@@ -480,12 +479,8 @@ static int pd_ioctl(struct inode *inode,struct file *file,
 }
 
 static int pd_release (struct inode *inode, struct file *file)
-
-{       kdev_t devp;
-       int     unit;
-
-        devp = inode->i_rdev;
-       unit = DEVICE_NR(devp);
+{
+       int     unit = DEVICE_NR(inode->i_rdev);
 
        if ((unit >= PD_UNITS) || (PD.access <= 0)) 
                return -EINVAL;
@@ -513,29 +508,22 @@ static int pd_check_media( kdev_t dev)
 
 static int pd_revalidate(kdev_t dev)
 {
-       int unit, res;
-       long flags;
+       int unit = DEVICE_NR(dev);
+       kdev_t device = mk_kdev(MAJOR_NR, unit << PD_BITS);
+       int res;
 
-       unit = DEVICE_NR(dev);
        if ((unit >= PD_UNITS) || !PD.present)
                return -ENODEV;
 
-       save_flags(flags);
-       cli(); 
-       if (PD.access > 1) {
-               restore_flags(flags);
-               return -EBUSY;
-       }
-       pd_valid = 0;
-       restore_flags(flags);   
-
-       res = wipe_partitions(dev);
+       res = dev_part_lock(device);
+       if (res < 0)
+               return res;
+       res = wipe_partitions(device);
 
        if (res == 0 && pd_identify(unit))
-               grok_partitions(dev, PD.capacity);
+               grok_partitions(device, PD.capacity);
 
-       pd_valid = 1;
-       wake_up(&pd_wait_open);
+       dev_unlock_part(device);
  
         return res;
 }
index bd604cee4663b031aaae53552527df5db2a2db4a..65b7d9999e6ce173ce2b832aba89580eb613d38a 100644 (file)
@@ -93,8 +93,6 @@ static void ps2esdi_geometry_int_handler(u_int);
 
 static int ps2esdi_open(struct inode *inode, struct file *file);
 
-static int ps2esdi_release(struct inode *inode, struct file *file);
-
 static int ps2esdi_ioctl(struct inode *inode, struct file *file,
                         u_int cmd, u_long arg);
 
@@ -111,11 +109,8 @@ static void ps2esdi_reset_timer(unsigned long unused);
 static u_int dma_arb_level;            /* DMA arbitration level */
 
 static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_int);
-static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_wait_open);
 
 static int no_int_yet;
-static int access_count[MAX_HD];
-static char ps2esdi_valid[MAX_HD];
 static int ps2esdi_sizes[MAX_HD << 6];
 static int ps2esdi_drives;
 static struct hd_struct ps2esdi[MAX_HD << 6];
@@ -152,7 +147,6 @@ static struct block_device_operations ps2esdi_fops =
 {
        owner:          THIS_MODULE,
        open:           ps2esdi_open,
-       release:        ps2esdi_release,
        ioctl:          ps2esdi_ioctl,
 };
 
@@ -441,13 +435,11 @@ static int __init ps2esdi_geninit(void)
        }
        blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), 128);
 
-       for (i = 0; i < ps2esdi_drives; i++) {
+       for (i = 0; i < ps2esdi_drives; i++)
                register_disk(&ps2esdi_gendisk,mk_kdev(MAJOR_NR,i<<6),1<<6,
                                &ps2esdi_fops,
                                ps2esdi_info[i].head * ps2esdi_info[i].sect *
                                ps2esdi_info[i].cyl);
-               ps2esdi_valid[i] = 1;
-       }
        return 0;
 
 err_out3:
@@ -1083,32 +1075,11 @@ static void dump_cmd_complete_status(u_int int_ret_code)
 static int ps2esdi_open(struct inode *inode, struct file *file)
 {
        int dev = DEVICE_NR(inode->i_rdev);
-
-       if (dev < ps2esdi_drives) {
-               while (!ps2esdi_valid[dev])
-                       sleep_on(&ps2esdi_wait_open);
-
-               access_count[dev]++;
-
-               return (0);
-       } else
-               return (-ENODEV);
-}
-
-
-
-static int ps2esdi_release(struct inode *inode, struct file *file)
-{
-       int dev = DEVICE_NR(inode->i_rdev);
-
-       if (dev < ps2esdi_drives) {
-               access_count[dev]--;
-       }
+       if (dev >= ps2esdi_drives)
+               return -ENODEV;
        return 0;
 }
 
-
-
 static int ps2esdi_ioctl(struct inode *inode,
                         struct file *file, u_int cmd, u_long arg)
 {
@@ -1155,24 +1126,20 @@ static int ps2esdi_ioctl(struct inode *inode,
 static int ps2esdi_reread_partitions(kdev_t dev)
 {
        int target = DEVICE_NR(dev);
-       int res;
+       kdev_t device = mk_kdev(MAJOR_NR, target << 6);
+       int res = dev_lock_part(device);
 
-       cli();
-       ps2esdi_valid[target] = (access_count[target] != 1);
-       sti();
-       if (ps2esdi_valid[target])
-               return (-EBUSY);
+       if (res < 0)
+               return res;
 
-       res = wipe_partitions(dev);
+       res = wipe_partitions(device);
        if (res == 0)
-               grok_partitions(dev, ps2esdi_info[target].head
+               grok_partitions(device, ps2esdi_info[target].head
                                * ps2esdi_info[target].cyl
                                * ps2esdi_info[target].sect);
  
-       ps2esdi_valid[target] = 1;
-       wake_up(&ps2esdi_wait_open);
-
-       return (res);
+       dev_unlock_part(device);
+       return res;
 }
 
 static void ps2esdi_reset_timer(unsigned long unused)
index c2953c7afbc914cdbe7695e4e57735e0284ed4cd..719a7a6a6261fd16f3caacac0dafeb45daf303c4 100644 (file)
@@ -812,31 +812,21 @@ static void del_battery_timer(void)
  * Note no locks taken out here.  In a worst case scenario, we could drop
  * a chunk of system memory.  But that should never happen, since validation
  * happens at open or mount time, when locks are held.
+ *
+ *     That's crap, since doing that while some partitions are opened
+ * or mounted will give you really nasty results.
  */
 static int mm_revalidate(kdev_t i_rdev)
 {
-       int i;
-
        int card_number = DEVICE_NR(i_rdev);
-       /* first partition, # of partitions */
-       int part1 = (card_number << MM_SHIFT) + 1;
-       int npart = (1 << MM_SHIFT) -1;
-
-       /* first clear old partition information */
-       for (i=0; i<npart ;i++) {
-               mm_gendisk.sizes[part1+i]=0;
-               mm_gendisk.part[part1+i].start_sect = 0;
-               mm_gendisk.part[part1+i].nr_sects = 0;
-       }
-
-       mm_gendisk.part[card_number << MM_SHIFT].nr_sects =
-               cards[card_number].mm_size << 1;
-
-
-       /* then fill new info */
+       kdev_t device = mk_mdev(MAJOR_NR, card_number << MM_SHIFT);
+       int res = dev_lock_part(device);
+       if (res < 0)
+               return res;
+       wipe_partitions(device);
        printk(KERN_INFO "mm partition check: (%d)\n", card_number);
-       grok_partitions(mk_kdev(major_nr,part1-1),
-                       mm_gendisk.sizes[card_number<<MM_SHIFT]);
+       grok_partitions(device, cards[card_number].mm_size << 1);
+       dev_unlock_part(device);
        return 0;
 }
 /*
@@ -925,22 +915,12 @@ static int mm_open(struct inode *i, struct file *filp)
 }
 /*
 -----------------------------------------------------------------------------------
---                              mm_do_release
------------------------------------------------------------------------------------
-*/
-static int mm_do_release(struct inode *i, struct file *filp)
-{
-       return 0;
-}
-/*
------------------------------------------------------------------------------------
 --                             mm_fops
 -----------------------------------------------------------------------------------
 */
 static struct block_device_operations mm_fops = {
        owner:          THIS_MODULE,
        open:           mm_open,
-       release:        mm_do_release,
        ioctl:          mm_ioctl,
        revalidate:     mm_revalidate,
        check_media_change: mm_check_change,
index bca8cd457e0e0acc75ae42563233eb41e4a8036b..0474a027190c1eaf1c94c431aa49930a07c40a0c 100644 (file)
@@ -122,7 +122,7 @@ static unsigned int xd_bases[] __initdata =
 };
 
 static struct hd_struct xd_struct[XD_MAXDRIVES << 6];
-static int xd_sizes[XD_MAXDRIVES << 6], xd_access[XD_MAXDRIVES];
+static int xd_sizes[XD_MAXDRIVES << 6];
 
 static spinlock_t xd_lock = SPIN_LOCK_UNLOCKED;
 
@@ -140,12 +140,9 @@ static struct gendisk xd_gendisk = {
 static struct block_device_operations xd_fops = {
        owner:          THIS_MODULE,
        open:           xd_open,
-       release:        xd_release,
        ioctl:          xd_ioctl,
 };
 static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int);
-static DECLARE_WAIT_QUEUE_HEAD(xd_wait_open);
-static u_char xd_valid[XD_MAXDRIVES] = { 0,0 };
 static u_char xd_drives, xd_irq = 5, xd_dma = 3, xd_maxsectors;
 static u_char xd_override __initdata = 0, xd_type __initdata = 0;
 static u_short xd_iobase = 0x320;
@@ -244,14 +241,11 @@ static void __init xd_geninit (void)
        /* xd_maxsectors depends on controller - so set after detection */
        blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), xd_maxsectors);
 
-       for (i = 0; i < xd_drives; i++) {
-               xd_valid[i] = 1;
+       for (i = 0; i < xd_drives; i++)
                register_disk(&xd_gendisk, mk_kdev(MAJOR_NR,i<<6), 1<<6,
                                &xd_fops,
                                xd_info[i].heads * xd_info[i].cylinders *
                                xd_info[i].sectors);
-       }
-
        xd_gendisk.nr_real = xd_drives;
 }
 
@@ -259,17 +253,9 @@ static void __init xd_geninit (void)
 static int xd_open (struct inode *inode,struct file *file)
 {
        int dev = DEVICE_NR(inode->i_rdev);
-
-       if (dev < xd_drives) {
-               while (!xd_valid[dev])
-                       sleep_on(&xd_wait_open);
-
-               xd_access[dev]++;
-
-               return (0);
-       }
-
-       return -ENXIO;
+       if (dev >= xd_drives)
+               return -ENXIO;
+       return 0;
 }
 
 /* do_xd_request: handle an incoming request */
@@ -364,37 +350,23 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
        }
 }
 
-/* xd_release: release the device */
-static int xd_release (struct inode *inode, struct file *file)
-{
-       int target = DEVICE_NR(inode->i_rdev);
-       if (target < xd_drives)
-               xd_access[target]--;
-       return 0;
-}
-
 /* xd_reread_partitions: rereads the partition table from a drive */
 static int xd_reread_partitions(kdev_t dev)
 {
-       int target;
-       int res;
+       int target = DEVICE_NR(dev);
+       kdev_t device = mk_kdev(MAJOR_NR, target << 6);
+       int res = dev_lock_part(device);
        
-       target = DEVICE_NR(dev);
-
-       cli();
-       xd_valid[target] = (xd_access[target] != 1);
-        sti();
-       if (xd_valid[target])
-               return -EBUSY;
+       if (res < 0)
+               return 0;
 
-       res = wipe_partitions(dev);
+       res = wipe_partitions(device);
        if (!res)
-               grok_partitions(dev, xd_info[target].heads
+               grok_partitions(device, xd_info[target].heads
                                * xd_info[target].cylinders
                                * xd_info[target].sectors);
 
-       xd_valid[target] = 1;
-       wake_up(&xd_wait_open);
+       dev_unlock_part(device);
 
        return res;
 }
index 7babb59b96d041cd108b18ed9423da98ec898b9b..3df2d4e984102e0d353478ce7fdf3b707c724a29 100644 (file)
@@ -113,7 +113,6 @@ static void xd_geninit (void);
 static int xd_open (struct inode *inode,struct file *file);
 static void do_xd_request (request_queue_t * q);
 static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg);
-static int xd_release (struct inode *inode,struct file *file);
 static int xd_reread_partitions (kdev_t dev);
 static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count);
 static void xd_recalibrate (u_char drive);
index a34945a2382fee9c12079bd46580827c284f79ac..689933665d171a88d2a6d86750f58ab159b9c10e 100644 (file)
@@ -83,9 +83,6 @@ static void bad_rw_intr(void);
 
 static char recalibrate[MAX_HD];
 static char special_op[MAX_HD];
-static int access_count[MAX_HD];
-static char busy[MAX_HD];
-static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
 
 static int reset;
 static int hd_error;
@@ -668,14 +665,9 @@ static int hd_ioctl(struct inode * inode, struct file * file,
 
 static int hd_open(struct inode * inode, struct file * filp)
 {
-       int target;
-       target =  DEVICE_NR(inode->i_rdev);
-
+       int target =  DEVICE_NR(inode->i_rdev);
        if (target >= NR_HD)
                return -ENODEV;
-       while (busy[target])
-               sleep_on(&busy_wait);
-       access_count[target]++;
        return 0;
 }
 
@@ -683,12 +675,6 @@ static int hd_open(struct inode * inode, struct file * filp)
  * Releasing a block device means we sync() it, so that it can safely
  * be forgotten about...
  */
-static int hd_release(struct inode * inode, struct file * file)
-{
-        int target =  DEVICE_NR(inode->i_rdev);
-       access_count[target]--;
-       return 0;
-}
 
 extern struct block_device_operations hd_fops;
 
@@ -715,7 +701,6 @@ static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
 static struct block_device_operations hd_fops = {
        .open =         hd_open,
-       .release =      hd_release,
        .ioctl =        hd_ioctl,
 };
 
@@ -854,13 +839,9 @@ int __init hd_init(void)
        return 0;
 }
 
-#define DEVICE_BUSY busy[target]
-#define USAGE access_count[target]
 #define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl)
 /* We assume that the BIOS parameters do not change, so the disk capacity
    will not change */
-#undef MAYBE_REINIT
-#define GENDISK_STRUCT hd_gendisk
 
 /*
  * This routine is called to flush all partitions and partition tables
@@ -872,36 +853,15 @@ int __init hd_init(void)
  */
 static int revalidate_hddisk(kdev_t dev, int maxusage)
 {
-       int target;
-       struct gendisk * gdev;
-       int res;
-       long flags;
-
-       target = DEVICE_NR(dev);
-       gdev = &GENDISK_STRUCT;
-
-       save_flags(flags);
-       cli();
-       if (DEVICE_BUSY || USAGE > maxusage) {
-               restore_flags(flags);
-               return -EBUSY;
-       }
-       DEVICE_BUSY = 1;
-       restore_flags(flags);
-
-       res = wipe_partitions(dev);
-       if (res)
-               goto leave;
-
-#ifdef MAYBE_REINIT
-       MAYBE_REINIT;
-#endif
-
-       grok_partitions(dev, CAPACITY);
-
-leave:
-       DEVICE_BUSY = 0;
-       wake_up(&busy_wait);
+       int target = DEVICE_NR(dev);
+       kdev_t device = mk_kdev(MAJOR_NR, target << 6);
+       int res = dev_lock_part(device);
+       if (res < 0)
+               return res;
+       res = wipe_partitions(device);
+       if (!res)
+               grok_partitions(device, CAPACITY);
+       dev_unlock_part(device);
        return res;
 }
 
index a83f8e7ee6d62aff29036049a2938b8092ef5152..ce566e1b064578bc0b376190035377510a6edef4 100644 (file)
@@ -1105,9 +1105,6 @@ static int ide_open(struct inode * inode, struct file * filp)
        if (drive->driver == NULL)
                ide_driver_module();
 
-       while (drive->busy)
-               sleep_on(&drive->wqueue);
-
        ++drive->usage;
        if (ata_ops(drive) && ata_ops(drive)->open)
                return ata_ops(drive)->open(inode, filp, drive);
index 24cc8bc9a75ec6598bf5dc00c3885bf6e374bf66..2f5f3495326392ea8f95a714ed2ce4c16d7e565c 100644 (file)
@@ -249,28 +249,22 @@ struct ata_device *get_info_ptr(kdev_t i_rdev)
  */
 int ata_revalidate(kdev_t i_rdev)
 {
+       kdev_t device = mk_kdev(major(i_rdev), minor(i_rdev) & ~PARTN_MASK);
        struct ata_device *drive;
-       unsigned long flags;
        int res;
 
-       if ((drive = get_info_ptr(i_rdev)) == NULL)
+       if ((drive = get_info_ptr(device)) == NULL)
                return -ENODEV;
 
-       /* FIXME: The locking here doesn't make the slightest sense! */
-       spin_lock_irqsave(&ide_lock, flags);
-
-       if (drive->busy || (drive->usage > 1)) {
-               spin_unlock_irqrestore(&ide_lock, flags);
-
-               return -EBUSY;
-       }
-
-       drive->busy = 1;
        MOD_INC_USE_COUNT;
 
-       spin_unlock_irqrestore(&ide_lock, flags);
+       res = dev_lock_part(device);
+       if (res < 0) {
+               MOD_DEC_USE_COUNT;
+               return res;
+       }
 
-       res = wipe_partitions(i_rdev);
+       res = wipe_partitions(device);
        if (!res) {
                if (ata_ops(drive) && ata_ops(drive)->revalidate) {
                        ata_get(ata_ops(drive));
@@ -281,14 +275,11 @@ int ata_revalidate(kdev_t i_rdev)
                        ata_ops(drive)->revalidate(drive);
                        ata_put(ata_ops(drive));
                } else
-                       grok_partitions(i_rdev, ata_capacity(drive));
+                       grok_partitions(device, ata_capacity(drive));
        }
 
-       drive->busy = 0;
-       wake_up(&drive->wqueue);
-
+       dev_unlock_part(device);
        MOD_DEC_USE_COUNT;
-
        return res;
 }
 
index bd4684dd648e38164e5ebad05f8212168d8897d5..34ecf2f82ccb59c21fb702ed715af9605aa9c13e 100644 (file)
@@ -1154,25 +1154,20 @@ static int ftl_ioctl(struct inode *inode, struct file *file,
 
 static int ftl_reread_partitions(kdev_t dev)
 {
-    int minor = minor(dev);
-    partition_t *part = myparts[minor >> 4];
-    int res;
-
-    DEBUG(0, "ftl_cs: ftl_reread_partition(%d)\n", minor);
-    if ((atomic_read(&part->open) > 1)) {
-           return -EBUSY;
-    }
-
-    res = wipe_partitions(dev);
-    if (res)
-       goto leave;
-
-    scan_header(part);
-
-    register_disk(&ftl_gendisk, whole >> PART_BITS, MAX_PART,
-                 &ftl_blk_fops, le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE);
-
-    return res;
+       int minor = minor(dev);
+       partition_t *part = myparts[minor >> 4];
+       kdev_t device = mk_kdev(MAJOR_NR, minor & ~15);
+       int res = dev_lock_part(device);
+       if (rec < 0)
+               return res;
+       res = wipe_partitions(device);
+       if (!res) {
+               scan_header(part);
+               grok_partitions(device,
+                       le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE);
+       }
+       dev_unlock_part(device);
+       return res;
 }
 
 /*======================================================================
@@ -1282,13 +1277,13 @@ static void ftl_notify_add(struct mtd_info *mtd)
 
        partition->mtd = mtd;
 
-       if ((scan_header(partition) == 0) && 
-           (build_maps(partition) == 0)) {
-               
+       if ((scan_header(partition) == 0) && (build_maps(partition) == 0)) {
                partition->state = FTL_FORMATTED;
                atomic_set(&partition->open, 0);
                myparts[device] = partition;
-               ftl_reread_partitions(device << 4);
+               register_disk(&ftl_gendisk, mk_kdev(MAJOR_NR, device << 4),
+                             MAX_PART, &ftl_blk_fops,
+                             le32_to_cpu(partition->header.FormattedSize)/SECTOR_SIZE);
 #ifdef PCMCIA_DEBUG
                printk(KERN_INFO "ftl_cs: opening %d kb FTL partition\n",
                       le32_to_cpu(partition->header.FormattedSize) >> 10);
index 18607155f84ada71a0784e1a69deb75474ba24cf..9560e5a30faa144a942ae6632d1bb08a465ffb57 100644 (file)
@@ -115,7 +115,6 @@ static void NFTL_setup(struct mtd_info *mtd)
 #endif
 
         /* linux stuff */
-       nftl->usecount = 0;
        nftl->cylinders = 1024;
        nftl->heads = 16;
 
@@ -153,8 +152,9 @@ static void NFTL_setup(struct mtd_info *mtd)
 #if LINUX_VERSION_CODE < 0x20328
        resetup_one_dev(&nftl_gendisk, firstfree);
 #else
-       grok_partitions(mk_kdev(MAJOR_NR,firstfree<<NFTL_PARTN_BITS),
-                       nftl->nr_sects);
+       register_disk(&nftl_gendisk,
+                     mk_kdev(MAJOR_NR,firstfree<<NFTL_PARTN_BITS),
+                     1<<NFTL_PARTN_BITS, &nftl_fops, nftl->nr_sects);
 #endif
 }
 
@@ -800,16 +800,17 @@ static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd
 
        case BLKRRPART:
                if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-               if (nftl->usecount > 1) return -EBUSY;
-               /* 
-                * We have to flush all buffers and invalidate caches,
-                * or we won't be able to re-use the partitions,
-                * if there was a change and we don't want to reboot
-                */
-               res = wipe_partitions(inode->i_rdev);
+               {
+               kdev_t device = mk_kdev(MAJOR_NR,
+                       minor(inode->i_rdev) & -(1<<NFTL_PARTN_BITS));
+               res = dev_lock_part(device);
+               if (res < 0)
+                       return res;
+               res = wipe_partitions(device);
                if (!res)
-                       grok_partitions(inode->i_rdev, nftl->nr_sects);
-
+                       grok_partitions(device, nftl->nr_sects);
+               dev_unlock_part(device);
+               }
                return res;
 
 #if (LINUX_VERSION_CODE < 0x20303)             
@@ -955,7 +956,6 @@ static int nftl_open(struct inode *ip, struct file *fp)
                return -EROFS;
 #endif /* !CONFIG_NFTL_RW */
 
-       thisNFTL->usecount++;
        if (!get_mtd_device(thisNFTL->mtd, -1))
                return /* -E'SBUGGEREDOFF */ -ENXIO;
 
@@ -972,7 +972,6 @@ static int nftl_release(struct inode *inode, struct file *fp)
 
        if (thisNFTL->mtd->sync)
                thisNFTL->mtd->sync(thisNFTL->mtd);
-       thisNFTL->usecount--;
 
        put_mtd_device(thisNFTL->mtd);
 
index fd92ed1924f100da877deb582912df24ef3c934d..1ca2ac95292f1523447bfc363f3d397e01057ae2 100644 (file)
@@ -506,16 +506,6 @@ static int sd_open(struct inode *inode, struct file *filp)
         */
        if (!scsi_block_when_processing_errors(sdp))
                return -ENXIO;
-       /*
-        * Make sure that only one process can do a check_change_disk at 
-        * one time.  This is also used to lock out further access when 
-        * the partition table is being re-read.
-        */
-
-       while (sdp->busy) {
-               barrier();
-               cpu_relax();
-       }
        /*
         * The following code can sleep.
         * Module unloading must be prevented
@@ -527,9 +517,7 @@ static int sd_open(struct inode *inode, struct file *filp)
        sdp->access_count++;
 
        if (sdp->removable) {
-               sdp->allow_revalidate = 1;
                check_disk_change(inode->i_rdev);
-               sdp->allow_revalidate = 0;
 
                /*
                 * If the drive is empty, just let the open fail.
@@ -1464,9 +1452,10 @@ static int sd_attach(Scsi_Device * sdp)
 int revalidate_scsidisk(kdev_t dev, int maxusage)
 {
        int dsk_nr = DEVICE_NR(dev);
-       int res;
        Scsi_Disk * sdkp;
        Scsi_Device * sdp;
+       kdev_t device = mk_kdev(major(dev), minor(dev) & ~15);
+       int res;
 
        SCSI_LOG_HLQUEUE(3, printk("revalidate_scsidisk: dsk_nr=%d\n", 
                                   DEVICE_NR(dev)));
@@ -1474,24 +1463,20 @@ int revalidate_scsidisk(kdev_t dev, int maxusage)
        if ((NULL == sdkp) || (NULL == (sdp = sdkp->device)))
                return -ENODEV;
 
-       if (sdp->busy || ((sdp->allow_revalidate == 0) && 
-                         (sdp->access_count > maxusage))) {
-               printk(KERN_WARNING "Device busy for revalidation "
-                      "(access_count=%d)\n", sdp->access_count);
-               return -EBUSY;
-       }
-       sdp->busy = 1;
+       res = dev_lock_part(device);
+       if (res < 0)
+               return res;
 
-       res = wipe_partitions(dev);
+       res = wipe_partitions(device);
        if (res)
                goto leave;
 
        sd_init_onedisk(sdkp, dsk_nr);
 
-       grok_partitions(dev, sdkp->capacity);
+       grok_partitions(device, sdkp->capacity);
 
 leave:
-       sdp->busy = 0;
+       dev_unlock_part(device);
        return res;
 }
 
index 90c46b454f3cd2328056b0c96f37f61d62283099..8166aea9be6a8411816b60a38f09b1d3f9f40fe8 100644 (file)
@@ -293,6 +293,8 @@ struct block_device *bdget(dev_t dev)
                        new_bdev->bd_queue = NULL;
                        new_bdev->bd_contains = NULL;
                        new_bdev->bd_inode = inode;
+                       new_bdev->bd_part_count = 0;
+                       sema_init(&new_bdev->bd_part_sem, 1);
                        inode->i_mode = S_IFBLK;
                        inode->i_rdev = kdev;
                        inode->i_bdev = new_bdev;
@@ -415,9 +417,9 @@ int get_blkdev_list(char * p)
        Return the function table of a device.
        Load the driver if needed.
 */
-const struct block_device_operations * get_blkfops(unsigned int major)
+struct block_device_operations * get_blkfops(unsigned int major)
 {
-       const struct block_device_operations *ret = NULL;
+       struct block_device_operations *ret = NULL;
 
        /* major 0 is used for non-device mounts */
        if (major && major < MAX_BLKDEV) {
@@ -479,7 +481,7 @@ int unregister_blkdev(unsigned int major, const char * name)
 int check_disk_change(kdev_t dev)
 {
        int i;
-       const struct block_device_operations * bdops = NULL;
+       struct block_device_operations * bdops = NULL;
 
        i = major(dev);
        if (i < MAX_BLKDEV)
@@ -567,10 +569,16 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
                        }
                }
        }
-       if (current_ops->open) {
-               ret = current_ops->open(inode, file);
-               if (ret)
-                       goto out2;
+       if (bdev->bd_contains == bdev) {
+               if (current_ops->open) {
+                       ret = current_ops->open(inode, file);
+                       if (ret)
+                               goto out2;
+               }
+       } else {
+               down(&bdev->bd_contains->bd_part_sem);
+               bdev->bd_contains->bd_part_count++;
+               up(&bdev->bd_contains->bd_part_sem);
        }
        if (!bdev->bd_op)
                bdev->bd_op = ops;
@@ -688,8 +696,14 @@ int blkdev_put(struct block_device *bdev, int kind)
        }
        if (!--bdev->bd_openers)
                kill_bdev(bdev);
-       if (bdev->bd_op->release)
-               ret = bdev->bd_op->release(bd_inode, NULL);
+       if (bdev->bd_contains == bdev) {
+               if (bdev->bd_op->release)
+                       ret = bdev->bd_op->release(bd_inode, NULL);
+       } else {
+               down(&bdev->bd_contains->bd_part_sem);
+               bdev->bd_contains->bd_part_count--;
+               up(&bdev->bd_contains->bd_part_sem);
+       }
        if (!bdev->bd_openers) {
                if (bdev->bd_op->owner)
                        __MOD_DEC_USE_COUNT(bdev->bd_op->owner);
index e7009bc3e4211cc999fa7cf7085532b51dd1b9f3..8192096fad163e3c97405f3c859a93c3ac5d0461 100644 (file)
@@ -372,23 +372,8 @@ static void check_partition(struct gendisk *hd, kdev_t dev)
                        sprintf(state->name, "p");
        }
        bdev = bdget(kdev_t_to_nr(dev));
-       bdev->bd_contains = bdev;
-       bdev->bd_inode->i_size = (loff_t)hd->part[minor(dev)].nr_sects << 9;
-       if (!bdev->bd_openers) {
-               struct blk_dev_struct *p = blk_dev + major(dev);
-               unsigned bsize = bdev_hardsect_size(bdev);
-               while (bsize < PAGE_CACHE_SIZE) {
-                       if (bdev->bd_inode->i_size & bsize)
-                               break;
-                       bsize <<= 1;
-               }
-               if (p->queue)
-                       bdev->bd_queue =  p->queue(dev);
-               else
-                       bdev->bd_queue = &p->request_queue;
-               bdev->bd_block_size = bsize;
-               bdev->bd_inode->i_blkbits = blksize_bits(bsize);
-       }
+       if (blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW))
+               goto out;
        state->limit = 1<<hd->minor_shift;
        for (i = 0; check_part[i]; i++) {
                int res, j;
@@ -417,10 +402,8 @@ static void check_partition(struct gendisk *hd, kdev_t dev)
 
        printk(" unknown partition table\n");
 setup_devfs:
-       invalidate_bdev(bdev, 1);
-       truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
-       bdput(bdev);
-
+       blkdev_put(bdev, BDEV_RAW);
+out:
        /* Setup driverfs tree */
        if (hd->sizes)
                driverfs_create_partitions(hd, minor(dev));
index 83f5a21b5d26e2bc8596bf8be10a64121ab267a2..b58c1b43f734c8b04a0e1a5571beacb9c7357f3f 100644 (file)
@@ -342,7 +342,7 @@ struct block_device {
        struct inode *          bd_inode;
        dev_t                   bd_dev;  /* not a kdev_t - it's a search key */
        int                     bd_openers;
-       const struct block_device_operations *bd_op;
+       struct block_device_operations *bd_op;
        struct request_queue    *bd_queue;
        struct semaphore        bd_sem; /* open/close mutex */
        struct list_head        bd_inodes;
@@ -351,6 +351,8 @@ struct block_device {
        struct block_device *   bd_contains;
        unsigned                bd_block_size;
        unsigned long           bd_offset;
+       struct semaphore        bd_part_sem;
+       unsigned                bd_part_count;
 };
 
 struct inode {
@@ -1083,7 +1085,7 @@ extern void bd_release(struct block_device *);
 extern void blk_run_queues(void);
 
 /* fs/devices.c */
-extern const struct block_device_operations *get_blkfops(unsigned int);
+extern struct block_device_operations *get_blkfops(unsigned int);
 extern int register_chrdev(unsigned int, const char *, struct file_operations *);
 extern int unregister_chrdev(unsigned int, const char *);
 extern int chrdev_open(struct inode *, struct file *);
@@ -1293,5 +1295,31 @@ static inline ino_t parent_ino(struct dentry *dentry)
        return res;
 }
 
+/* NOTE NOTE NOTE: this interface _will_ change in a couple of patches */
+
+static inline int dev_lock_part(kdev_t dev)
+{
+       struct block_device *bdev = bdget(kdev_t_to_nr(dev));
+       if (!bdev)
+               return -ENOMEM;
+       if (!down_trylock(&bdev->bd_part_sem)) {
+               if (!bdev->bd_part_count)
+                       return 0;
+               up(&bdev->bd_part_sem);
+       }
+       bdput(bdev);
+       return -EBUSY;
+}
+
+static inline void dev_unlock_part(kdev_t dev)
+{
+       struct block_device *bdev = bdget(kdev_t_to_nr(dev));
+       if (!bdev)
+               BUG();
+       up(&bdev->bd_part_sem);
+       bdput(bdev);
+       bdput(bdev);
+}
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_FS_H */