Commit 81d4c00c authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] partition handling locking cleanups

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