Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 127731
b: refs/heads/master
c: d337482
h: refs/heads/master
i:
  127729: 733f843
  127727: 25c2310
v: v3
  • Loading branch information
NeilBrown committed Jan 8, 2009
1 parent 660686f commit 7284bea
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 13 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a21d15042d8cd736caf82c2bac564f3f93f3d017
refs/heads/master: d3374825ce57ba2214d375023979f6197ccc1385
61 changes: 49 additions & 12 deletions trunk/drivers/md/md.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,16 +214,33 @@ static inline mddev_t *mddev_get(mddev_t *mddev)
return mddev;
}

static void mddev_delayed_delete(struct work_struct *ws)
{
mddev_t *mddev = container_of(ws, mddev_t, del_work);
kobject_del(&mddev->kobj);
kobject_put(&mddev->kobj);
}

static void mddev_put(mddev_t *mddev)
{
if (!atomic_dec_and_lock(&mddev->active, &all_mddevs_lock))
return;
if (!mddev->raid_disks && list_empty(&mddev->disks)) {
if (!mddev->raid_disks && list_empty(&mddev->disks) &&
!mddev->hold_active) {
list_del(&mddev->all_mddevs);
spin_unlock(&all_mddevs_lock);
kobject_put(&mddev->kobj);
} else
spin_unlock(&all_mddevs_lock);
if (mddev->gendisk) {
/* we did a probe so need to clean up.
* Call schedule_work inside the spinlock
* so that flush_scheduled_work() after
* mddev_find will succeed in waiting for the
* work to be done.
*/
INIT_WORK(&mddev->del_work, mddev_delayed_delete);
schedule_work(&mddev->del_work);
} else
kfree(mddev);
}
spin_unlock(&all_mddevs_lock);
}

static mddev_t * mddev_find(dev_t unit)
Expand All @@ -242,6 +259,7 @@ static mddev_t * mddev_find(dev_t unit)

if (new) {
list_add(&new->all_mddevs, &all_mddevs);
mddev->hold_active = UNTIL_IOCTL;
spin_unlock(&all_mddevs_lock);
return new;
}
Expand Down Expand Up @@ -3435,6 +3453,8 @@ md_attr_store(struct kobject *kobj, struct attribute *attr,
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
rv = mddev_lock(mddev);
if (mddev->hold_active == UNTIL_IOCTL)
mddev->hold_active = 0;
if (!rv) {
rv = entry->store(mddev, page, length);
mddev_unlock(mddev);
Expand Down Expand Up @@ -3484,6 +3504,11 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
if (!mddev)
return NULL;

/* wait for any previous instance if this device
* to be completed removed (mddev_delayed_delete).
*/
flush_scheduled_work();

mutex_lock(&disks_mutex);
if (mddev->gendisk) {
mutex_unlock(&disks_mutex);
Expand Down Expand Up @@ -3520,7 +3545,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
disk->private_data = mddev;
disk->queue = mddev->queue;
/* Allow extended partitions. This makes the
* 'mdp' device redundant, but we can really
* 'mdp' device redundant, but we can't really
* remove it now.
*/
disk->flags |= GENHD_FL_EXT_DEVT;
Expand All @@ -3536,6 +3561,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
kobject_uevent(&mddev->kobj, KOBJ_ADD);
mddev->sysfs_state = sysfs_get_dirent(mddev->kobj.sd, "array_state");
}
mddev_put(mddev);
return NULL;
}

Expand Down Expand Up @@ -5054,6 +5080,9 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,

done_unlock:
abort_unlock:
if (mddev->hold_active == UNTIL_IOCTL &&
err != -EINVAL)
mddev->hold_active = 0;
mddev_unlock(mddev);

return err;
Expand All @@ -5070,14 +5099,25 @@ static int md_open(struct block_device *bdev, fmode_t mode)
* Succeed if we can lock the mddev, which confirms that
* it isn't being stopped right now.
*/
mddev_t *mddev = bdev->bd_disk->private_data;
mddev_t *mddev = mddev_find(bdev->bd_dev);
int err;

if (mddev->gendisk != bdev->bd_disk) {
/* we are racing with mddev_put which is discarding this
* bd_disk.
*/
mddev_put(mddev);
/* Wait until bdev->bd_disk is definitely gone */
flush_scheduled_work();
/* Then retry the open from the top */
return -ERESTARTSYS;
}
BUG_ON(mddev != bdev->bd_disk->private_data);

if ((err = mutex_lock_interruptible_nested(&mddev->reconfig_mutex, 1)))
goto out;

err = 0;
mddev_get(mddev);
atomic_inc(&mddev->openers);
mddev_unlock(mddev);

Expand Down Expand Up @@ -6436,11 +6476,8 @@ static __exit void md_exit(void)
unregister_sysctl_table(raid_table_header);
remove_proc_entry("mdstat", NULL);
for_each_mddev(mddev, tmp) {
struct gendisk *disk = mddev->gendisk;
if (!disk)
continue;
export_array(mddev);
mddev_put(mddev);
mddev->hold_active = 0;
}
}

Expand Down
14 changes: 14 additions & 0 deletions trunk/fs/block_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
}

lock_kernel();
restart:

ret = -ENXIO;
disk = get_gendisk(bdev->bd_dev, &partno);
Expand All @@ -1025,6 +1026,19 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)

if (disk->fops->open) {
ret = disk->fops->open(bdev, mode);
if (ret == -ERESTARTSYS) {
/* Lost a race with 'disk' being
* deleted, try again.
* See md.c
*/
disk_put_part(bdev->bd_part);
bdev->bd_part = NULL;
module_put(disk->fops->owner);
put_disk(disk);
bdev->bd_disk = NULL;
mutex_unlock(&bdev->bd_mutex);
goto restart;
}
if (ret)
goto out_clear;
}
Expand Down
4 changes: 4 additions & 0 deletions trunk/include/linux/raid/md_k.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ struct mddev_s
struct gendisk *gendisk;

struct kobject kobj;
int hold_active;
#define UNTIL_IOCTL 1

/* Superblock information */
int major_version,
Expand Down Expand Up @@ -246,6 +248,8 @@ struct mddev_s
*/
struct sysfs_dirent *sysfs_action; /* handle for 'sync_action' */

struct work_struct del_work; /* used for delayed sysfs removal */

spinlock_t write_lock;
wait_queue_head_t sb_wait; /* for waiting on superblock updates */
atomic_t pending_writes; /* number of active superblock writes */
Expand Down

0 comments on commit 7284bea

Please sign in to comment.