Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 231246
b: refs/heads/master
c: 49731ba
h: refs/heads/master
v: v3
  • Loading branch information
Tejun Heo authored and Jens Axboe committed Jan 14, 2011
1 parent 50d0e2e commit 20da9ba
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 20 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: c553f8e335c00a7cff3ab3f13e793b13d3f2207f
refs/heads/master: 49731baa41df404c2c3f44555869ab387363af43
1 change: 1 addition & 0 deletions trunk/drivers/md/dm-table.c
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md)
if (!d->dm_dev.bdev)
return;

bd_unlink_disk_holder(d->dm_dev.bdev, dm_disk(md));
blkdev_put(d->dm_dev.bdev, d->dm_dev.mode | FMODE_EXCL);
d->dm_dev.bdev = NULL;
}
Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/md/md.c
Original file line number Diff line number Diff line change
Expand Up @@ -1912,6 +1912,7 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
MD_BUG();
return;
}
bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk);
list_del_rcu(&rdev->same_set);
printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));
rdev->mddev = NULL;
Expand Down
93 changes: 75 additions & 18 deletions trunk/fs/block_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,9 @@ static void init_once(void *foo)
mutex_init(&bdev->bd_mutex);
INIT_LIST_HEAD(&bdev->bd_inodes);
INIT_LIST_HEAD(&bdev->bd_list);
#ifdef CONFIG_SYSFS
INIT_LIST_HEAD(&bdev->bd_holder_disks);
#endif
inode_init_once(&ei->vfs_inode);
/* Initialize mutex for freeze. */
mutex_init(&bdev->bd_fsfreeze_mutex);
Expand Down Expand Up @@ -779,6 +782,23 @@ static struct block_device *bd_start_claiming(struct block_device *bdev,
}

#ifdef CONFIG_SYSFS
struct bd_holder_disk {
struct list_head list;
struct gendisk *disk;
int refcnt;
};

static struct bd_holder_disk *bd_find_holder_disk(struct block_device *bdev,
struct gendisk *disk)
{
struct bd_holder_disk *holder;

list_for_each_entry(holder, &bdev->bd_holder_disks, list)
if (holder->disk == disk)
return holder;
return NULL;
}

static int add_symlink(struct kobject *from, struct kobject *to)
{
return sysfs_create_link(from, to, kobject_name(to));
Expand All @@ -794,6 +814,8 @@ static void del_symlink(struct kobject *from, struct kobject *to)
* @bdev: the claimed slave bdev
* @disk: the holding disk
*
* DON'T USE THIS UNLESS YOU'RE ALREADY USING IT.
*
* This functions creates the following sysfs symlinks.
*
* - from "slaves" directory of the holder @disk to the claimed @bdev
Expand All @@ -817,47 +839,83 @@ static void del_symlink(struct kobject *from, struct kobject *to)
*/
int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk)
{
struct bd_holder_disk *holder;
int ret = 0;

mutex_lock(&bdev->bd_mutex);

WARN_ON_ONCE(!bdev->bd_holder || bdev->bd_holder_disk);
WARN_ON_ONCE(!bdev->bd_holder);

/* FIXME: remove the following once add_disk() handles errors */
if (WARN_ON(!disk->slave_dir || !bdev->bd_part->holder_dir))
goto out_unlock;

ret = add_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
if (ret)
holder = bd_find_holder_disk(bdev, disk);
if (holder) {
holder->refcnt++;
goto out_unlock;
}

ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
if (ret) {
del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
holder = kzalloc(sizeof(*holder), GFP_KERNEL);
if (!holder) {
ret = -ENOMEM;
goto out_unlock;
}

bdev->bd_holder_disk = disk;
INIT_LIST_HEAD(&holder->list);
holder->disk = disk;
holder->refcnt = 1;

ret = add_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
if (ret)
goto out_free;

ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
if (ret)
goto out_del;

list_add(&holder->list, &bdev->bd_holder_disks);
goto out_unlock;

out_del:
del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
out_free:
kfree(holder);
out_unlock:
mutex_unlock(&bdev->bd_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(bd_link_disk_holder);

static void bd_unlink_disk_holder(struct block_device *bdev)
/**
* bd_unlink_disk_holder - destroy symlinks created by bd_link_disk_holder()
* @bdev: the calimed slave bdev
* @disk: the holding disk
*
* DON'T USE THIS UNLESS YOU'RE ALREADY USING IT.
*
* CONTEXT:
* Might sleep.
*/
void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk)
{
struct gendisk *disk = bdev->bd_holder_disk;
struct bd_holder_disk *holder;

bdev->bd_holder_disk = NULL;
if (!disk)
return;
mutex_lock(&bdev->bd_mutex);

del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
del_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
holder = bd_find_holder_disk(bdev, disk);

if (!WARN_ON_ONCE(holder == NULL) && !--holder->refcnt) {
del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
del_symlink(bdev->bd_part->holder_dir,
&disk_to_dev(disk)->kobj);
list_del_init(&holder->list);
kfree(holder);
}

mutex_unlock(&bdev->bd_mutex);
}
#else
static inline void bd_unlink_disk_holder(struct block_device *bdev)
{ }
EXPORT_SYMBOL_GPL(bd_unlink_disk_holder);
#endif

/**
Expand Down Expand Up @@ -1380,7 +1438,6 @@ int blkdev_put(struct block_device *bdev, fmode_t mode)
* unblock evpoll if it was a write holder.
*/
if (bdev_free) {
bd_unlink_disk_holder(bdev);
if (bdev->bd_write_holder) {
disk_unblock_events(bdev->bd_disk);
bdev->bd_write_holder = false;
Expand Down
8 changes: 7 additions & 1 deletion trunk/include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,7 @@ struct block_device {
int bd_holders;
bool bd_write_holder;
#ifdef CONFIG_SYSFS
struct gendisk * bd_holder_disk; /* for sysfs slave linkng */
struct list_head bd_holder_disks;
#endif
struct block_device * bd_contains;
unsigned bd_block_size;
Expand Down Expand Up @@ -2058,12 +2058,18 @@ extern struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode,
extern int blkdev_put(struct block_device *bdev, fmode_t mode);
#ifdef CONFIG_SYSFS
extern int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk);
extern void bd_unlink_disk_holder(struct block_device *bdev,
struct gendisk *disk);
#else
static inline int bd_link_disk_holder(struct block_device *bdev,
struct gendisk *disk)
{
return 0;
}
static inline void bd_unlink_disk_holder(struct block_device *bdev,
struct gendisk *disk)
{
}
#endif
#endif

Expand Down

0 comments on commit 20da9ba

Please sign in to comment.