return NULL;
}
+/* return the offset of the super block in 512byte sectors */
static inline sector_t calc_dev_sboffset(struct block_device *bdev)
{
- sector_t size = bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
- return MD_NEW_SIZE_BLOCKS(size);
+ sector_t num_sectors = bdev->bd_inode->i_size / 512;
+ return MD_NEW_SIZE_SECTORS(num_sectors);
}
-static sector_t calc_dev_size(mdk_rdev_t *rdev, unsigned chunk_size)
+static sector_t calc_num_sectors(mdk_rdev_t *rdev, unsigned chunk_size)
{
- sector_t size;
-
- size = rdev->sb_offset;
+ sector_t num_sectors = rdev->sb_offset * 2;
if (chunk_size)
- size &= ~((sector_t)chunk_size/1024 - 1);
- return size;
+ num_sectors &= ~((sector_t)chunk_size/512 - 1);
+ return num_sectors;
}
static int alloc_disk_sb(mdk_rdev_t * rdev)
rdev->sb_page = alloc_page(GFP_KERNEL);
if (!rdev->sb_page) {
printk(KERN_ALERT "md: out of memory.\n");
- return -EINVAL;
+ return -ENOMEM;
}
return 0;
tmp1->nr_disks = 0;
tmp2->nr_disks = 0;
- if (memcmp(tmp1, tmp2, MD_SB_GENERIC_CONSTANT_WORDS * 4))
- ret = 0;
- else
- ret = 1;
-
+ ret = (memcmp(tmp1, tmp2, MD_SB_GENERIC_CONSTANT_WORDS * 4) == 0);
abort:
kfree(tmp1);
kfree(tmp2);
*
* It also happens to be a multiple of 4Kb.
*/
- sb_offset = calc_dev_sboffset(rdev->bdev);
+ sb_offset = calc_dev_sboffset(rdev->bdev) / 2;
rdev->sb_offset = sb_offset;
ret = read_disk_sb(rdev, MD_SB_BYTES);
else
ret = 0;
}
- rdev->size = calc_dev_size(rdev, sb->chunk_size);
+ rdev->size = calc_num_sectors(rdev, sb->chunk_size) / 2;
if (rdev->size < sb->size && sb->level > 1)
/* "this cannot possibly happen" ... */
size *= 2; /* convert to sectors */
if (rdev->mddev->bitmap_offset)
return 0; /* can't move bitmap */
- rdev->sb_offset = calc_dev_sboffset(rdev->bdev);
+ rdev->sb_offset = calc_dev_sboffset(rdev->bdev) / 2;
if (!size || size > rdev->sb_offset*2)
size = rdev->sb_offset*2;
md_super_write(rdev->mddev, rdev, rdev->sb_offset << 1, rdev->sb_size,
return sprintf(page, "%s\n", array_states[st]);
}
-static int do_md_stop(mddev_t * mddev, int ro);
+static int do_md_stop(mddev_t * mddev, int ro, int is_open);
static int do_md_run(mddev_t * mddev);
static int restart_array(mddev_t *mddev);
/* stopping an active array */
if (atomic_read(&mddev->active) > 1)
return -EBUSY;
- err = do_md_stop(mddev, 0);
+ err = do_md_stop(mddev, 0, 0);
break;
case inactive:
/* stopping an active array */
if (mddev->pers) {
if (atomic_read(&mddev->active) > 1)
return -EBUSY;
- err = do_md_stop(mddev, 2);
+ err = do_md_stop(mddev, 2, 0);
} else
err = 0; /* already inactive */
break;
break; /* not supported yet */
case readonly:
if (mddev->pers)
- err = do_md_stop(mddev, 1);
+ err = do_md_stop(mddev, 1, 0);
else {
mddev->ro = 1;
set_disk_ro(mddev->gendisk, 1);
case read_auto:
if (mddev->pers) {
if (mddev->ro != 1)
- err = do_md_stop(mddev, 1);
+ err = do_md_stop(mddev, 1, 0);
else
err = restart_array(mddev);
if (err == 0) {
return sprintf(page, "%llu\n", (unsigned long long)mddev->size);
}
-static int update_size(mddev_t *mddev, unsigned long size);
+static int update_size(mddev_t *mddev, sector_t num_sectors);
static ssize_t
size_store(mddev_t *mddev, const char *buf, size_t len)
return -EINVAL;
if (mddev->pers) {
- err = update_size(mddev, size);
+ err = update_size(mddev, size * 2);
md_update_sb(mddev, 1);
} else {
if (mddev->size == 0 ||
static int restart_array(mddev_t *mddev)
{
struct gendisk *disk = mddev->gendisk;
- int err;
- /*
- * Complain if it has no devices
- */
- err = -ENXIO;
+ /* Complain if it has no devices */
if (list_empty(&mddev->disks))
- goto out;
-
- if (mddev->pers) {
- err = -EBUSY;
- if (!mddev->ro)
- goto out;
-
- mddev->safemode = 0;
- mddev->ro = 0;
- set_disk_ro(disk, 0);
-
- printk(KERN_INFO "md: %s switched to read-write mode.\n",
- mdname(mddev));
- /*
- * Kick recovery or resync if necessary
- */
- set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
- md_wakeup_thread(mddev->thread);
- md_wakeup_thread(mddev->sync_thread);
- err = 0;
- sysfs_notify(&mddev->kobj, NULL, "array_state");
-
- } else
- err = -EINVAL;
-
-out:
- return err;
+ return -ENXIO;
+ if (!mddev->pers)
+ return -EINVAL;
+ if (!mddev->ro)
+ return -EBUSY;
+ mddev->safemode = 0;
+ mddev->ro = 0;
+ set_disk_ro(disk, 0);
+ printk(KERN_INFO "md: %s switched to read-write mode.\n",
+ mdname(mddev));
+ /* Kick recovery or resync if necessary */
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ md_wakeup_thread(mddev->thread);
+ md_wakeup_thread(mddev->sync_thread);
+ sysfs_notify(&mddev->kobj, NULL, "array_state");
+ return 0;
}
/* similar to deny_write_access, but accounts for our holding a reference
* 1 - switch to readonly
* 2 - stop but do not disassemble array
*/
-static int do_md_stop(mddev_t * mddev, int mode)
+static int do_md_stop(mddev_t * mddev, int mode, int is_open)
{
int err = 0;
struct gendisk *disk = mddev->gendisk;
+ if (atomic_read(&mddev->active) > 1 + is_open) {
+ printk("md: %s still in use.\n",mdname(mddev));
+ return -EBUSY;
+ }
+
if (mddev->pers) {
- if (atomic_read(&mddev->active)>2) {
- printk("md: %s still in use.\n",mdname(mddev));
- return -EBUSY;
- }
if (mddev->sync_thread) {
set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
err = do_md_run (mddev);
if (err) {
printk(KERN_WARNING "md: do_md_run() returned %d\n", err);
- do_md_stop (mddev, 0);
+ do_md_stop (mddev, 0, 0);
}
}
static int get_disk_info(mddev_t * mddev, void __user * arg)
{
mdu_disk_info_t info;
- unsigned int nr;
mdk_rdev_t *rdev;
if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT;
- nr = info.number;
-
- rdev = find_rdev_nr(mddev, nr);
+ rdev = find_rdev_nr(mddev, info.number);
if (rdev) {
info.major = MAJOR(rdev->bdev->bd_dev);
info.minor = MINOR(rdev->bdev->bd_dev);
printk(KERN_INFO "md: nonpersistent superblock ...\n");
rdev->sb_offset = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
} else
- rdev->sb_offset = calc_dev_sboffset(rdev->bdev);
- rdev->size = calc_dev_size(rdev, mddev->chunk_size);
+ rdev->sb_offset = calc_dev_sboffset(rdev->bdev) / 2;
+ rdev->size = calc_num_sectors(rdev, mddev->chunk_size) / 2;
err = bind_rdev_to_array(rdev, mddev);
if (err) {
{
char b[BDEVNAME_SIZE];
int err;
- unsigned int size;
mdk_rdev_t *rdev;
if (!mddev->pers)
}
if (mddev->persistent)
- rdev->sb_offset = calc_dev_sboffset(rdev->bdev);
+ rdev->sb_offset = calc_dev_sboffset(rdev->bdev) / 2;
else
rdev->sb_offset =
rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
- size = calc_dev_size(rdev, mddev->chunk_size);
- rdev->size = size;
+ rdev->size = calc_num_sectors(rdev, mddev->chunk_size) / 2;
if (test_bit(Faulty, &rdev->flags)) {
printk(KERN_WARNING
return 0;
}
-static int update_size(mddev_t *mddev, unsigned long size)
+static int update_size(mddev_t *mddev, sector_t num_sectors)
{
mdk_rdev_t * rdev;
int rv;
struct list_head *tmp;
- int fit = (size == 0);
+ int fit = (num_sectors == 0);
if (mddev->pers->resize == NULL)
return -EINVAL;
- /* The "size" is the amount of each device that is used.
- * This can only make sense for arrays with redundancy.
- * linear and raid0 always use whatever space is available
- * We can only consider changing the size if no resync
- * or reconstruction is happening, and if the new size
- * is acceptable. It must fit before the sb_offset or,
- * if that is <data_offset, it must fit before the
- * size of each device.
- * If size is zero, we find the largest size that fits.
+ /* The "num_sectors" is the number of sectors of each device that
+ * is used. This can only make sense for arrays with redundancy.
+ * linear and raid0 always use whatever space is available. We can only
+ * consider changing this number if no resync or reconstruction is
+ * happening, and if the new size is acceptable. It must fit before the
+ * sb_offset or, if that is <data_offset, it must fit before the size
+ * of each device. If num_sectors is zero, we find the largest size
+ * that fits.
+
*/
if (mddev->sync_thread)
return -EBUSY;
sector_t avail;
avail = rdev->size * 2;
- if (fit && (size == 0 || size > avail/2))
- size = avail/2;
- if (avail < ((sector_t)size << 1))
+ if (fit && (num_sectors == 0 || num_sectors > avail))
+ num_sectors = avail;
+ if (avail < num_sectors)
return -ENOSPC;
}
- rv = mddev->pers->resize(mddev, (sector_t)size *2);
+ rv = mddev->pers->resize(mddev, num_sectors);
if (!rv) {
struct block_device *bdev;
return mddev->pers->reconfig(mddev, info->layout, -1);
}
if (info->size >= 0 && mddev->size != info->size)
- rv = update_size(mddev, info->size);
+ rv = update_size(mddev, (sector_t)info->size * 2);
if (mddev->raid_disks != info->raid_disks)
rv = update_raid_disks(mddev, info->raid_disks);
goto done_unlock;
case STOP_ARRAY:
- err = do_md_stop (mddev, 0);
+ err = do_md_stop (mddev, 0, 1);
goto done_unlock;
case STOP_ARRAY_RO:
- err = do_md_stop (mddev, 1);
+ err = do_md_stop (mddev, 1, 1);
goto done_unlock;
}
for_each_mddev(mddev, tmp)
if (mddev_trylock(mddev)) {
- do_md_stop (mddev, 1);
+ do_md_stop (mddev, 1, 0);
mddev_unlock(mddev);
}
/*