static int zvol_first_open(zvol_state_t *zv) { objset_t *os; uint64_t volsize; int error; uint64_t ro; /* lie and say we're read-only */ error = dmu_objset_own(zv->zv_name, DMU_OST_ZVOL, 1, zvol_tag, &os); if (error) return (SET_ERROR(-error)); zv->zv_objset = os; error = dsl_prop_get_integer(zv->zv_name, "readonly", &ro, NULL); if (error) goto out_owned; error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize); if (error) goto out_owned; error = dmu_bonus_hold(os, ZVOL_OBJ, zvol_tag, &zv->zv_dbuf); if (error) goto out_owned; set_capacity(zv->zv_disk, volsize >> 9); zv->zv_volsize = volsize; zv->zv_zilog = zil_open(os, zvol_get_data); if (ro || dmu_objset_is_snapshot(os) || !spa_writeable(dmu_objset_spa(os))) { set_disk_ro(zv->zv_disk, 1); zv->zv_flags |= ZVOL_RDONLY; } else { set_disk_ro(zv->zv_disk, 0); zv->zv_flags &= ~ZVOL_RDONLY; } out_owned: if (error) { dmu_objset_disown(os, zvol_tag); zv->zv_objset = NULL; } return (SET_ERROR(-error)); }
/* * Set read only */ static int dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) { struct dasd_device *base; int intval, rc; if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (bdev != bdev->bd_contains) // ro setting is not allowed for partitions return -EINVAL; if (get_user(intval, (int __user *)argp)) return -EFAULT; base = dasd_device_from_gendisk(bdev->bd_disk); if (!base) return -ENODEV; if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) { dasd_put_device(base); return -EROFS; } set_disk_ro(bdev->bd_disk, intval); rc = dasd_set_feature(base->cdev, DASD_FEATURE_READONLY, intval); dasd_put_device(base); return rc; }
static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive, struct ide_atapi_pc *pc) { struct ide_disk_obj *floppy = drive->driver_data; struct gendisk *disk = floppy->disk; u8 *page, buf[40]; int capacity, lba_capacity; u16 transfer_rate, sector_size, cyls, rpm; u8 heads, sectors; ide_floppy_create_mode_sense_cmd(pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE); if (ide_queue_pc_tail(drive, disk, pc, buf, pc->req_xfer)) { printk(KERN_ERR PFX "Can't get flexible disk page params\n"); return 1; } if (buf[3] & 0x80) drive->dev_flags |= IDE_DFLAG_WP; else drive->dev_flags &= ~IDE_DFLAG_WP; set_disk_ro(disk, !!(drive->dev_flags & IDE_DFLAG_WP)); page = &buf[8]; transfer_rate = be16_to_cpup((__be16 *)&buf[8 + 2]); sector_size = be16_to_cpup((__be16 *)&buf[8 + 6]); cyls = be16_to_cpup((__be16 *)&buf[8 + 8]); rpm = be16_to_cpup((__be16 *)&buf[8 + 28]); heads = buf[8 + 4]; sectors = buf[8 + 5]; capacity = cyls * heads * sectors * sector_size; if (memcmp(page, &floppy->flexible_disk_page, 32)) printk(KERN_INFO PFX "%s: %dkB, %d/%d/%d CHS, %d kBps, " "%d sector size, %d rpm\n", drive->name, capacity / 1024, cyls, heads, sectors, transfer_rate / 8, sector_size, rpm); memcpy(&floppy->flexible_disk_page, page, 32); drive->bios_cyl = cyls; drive->bios_head = heads; drive->bios_sect = sectors; lba_capacity = floppy->blocks * floppy->block_size; if (capacity < lba_capacity) { printk(KERN_NOTICE PFX "%s: The disk reports a capacity of %d " "bytes, but the drive only handles %d\n", drive->name, lba_capacity, capacity); floppy->blocks = floppy->block_size ? capacity / floppy->block_size : 0; drive->capacity64 = floppy->blocks * floppy->bs_factor; } return 0; }
/* * Rename a block device minor mode for the specified volume. */ static void zvol_rename_minor(zvol_state_t *zv, const char *newname) { int readonly = get_disk_ro(zv->zv_disk); ASSERT(MUTEX_HELD(&zvol_state_lock)); strlcpy(zv->zv_name, newname, sizeof (zv->zv_name)); /* * The block device's read-only state is briefly changed causing * a KOBJ_CHANGE uevent to be issued. This ensures udev detects * the name change and fixes the symlinks. This does not change * ZVOL_RDONLY in zv->zv_flags so the actual read-only state never * changes. This would normally be done using kobject_uevent() but * that is a GPL-only symbol which is why we need this workaround. */ set_disk_ro(zv->zv_disk, !readonly); set_disk_ro(zv->zv_disk, readonly); }
/* * Allocate and register gendisk structure for device. */ int dasd_gendisk_alloc(struct dasd_block *block) { struct gendisk *gdp; struct dasd_device *base; int len; /* Make sure the minor for this device exists. */ base = block->base; if (base->devindex >= DASD_PER_MAJOR) return -EBUSY; gdp = alloc_disk(1 << DASD_PARTN_BITS); if (!gdp) return -ENOMEM; /* Initialize gendisk structure. */ gdp->major = DASD_MAJOR; gdp->first_minor = base->devindex << DASD_PARTN_BITS; gdp->fops = &dasd_device_operations; gdp->driverfs_dev = &base->cdev->dev; /* * Set device name. * dasda - dasdz : 26 devices * dasdaa - dasdzz : 676 devices, added up = 702 * dasdaaa - dasdzzz : 17576 devices, added up = 18278 * dasdaaaa - dasdzzzz : 456976 devices, added up = 475252 */ len = sprintf(gdp->disk_name, "dasd"); if (base->devindex > 25) { if (base->devindex > 701) { if (base->devindex > 18277) len += sprintf(gdp->disk_name + len, "%c", 'a'+(((base->devindex-18278) /17576)%26)); len += sprintf(gdp->disk_name + len, "%c", 'a'+(((base->devindex-702)/676)%26)); } len += sprintf(gdp->disk_name + len, "%c", 'a'+(((base->devindex-26)/26)%26)); } len += sprintf(gdp->disk_name + len, "%c", 'a'+(base->devindex%26)); if (base->features & DASD_FEATURE_READONLY || test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) set_disk_ro(gdp, 1); gdp->private_data = block; gdp->queue = block->request_queue; block->gdp = gdp; set_capacity(block->gdp, 0); add_disk(block->gdp); return 0; }
/* * Allocate and register gendisk structure for device. */ int dasd_gendisk_alloc(struct dasd_device *device) { struct gendisk *gdp; int len; /* Make sure the minor for this device exists. */ if (device->devindex >= DASD_PER_MAJOR) return -EBUSY; gdp = alloc_disk(1 << DASD_PARTN_BITS); if (!gdp) return -ENOMEM; /* Initialize gendisk structure. */ gdp->major = DASD_MAJOR; gdp->first_minor = device->devindex << DASD_PARTN_BITS; gdp->fops = &dasd_device_operations; gdp->driverfs_dev = &device->cdev->dev; /* * Set device name. * dasda - dasdz : 26 devices * dasdaa - dasdzz : 676 devices, added up = 702 * dasdaaa - dasdzzz : 17576 devices, added up = 18278 * dasdaaaa - dasdzzzz : 456976 devices, added up = 475252 */ len = sprintf(gdp->disk_name, "dasd"); if (device->devindex > 25) { if (device->devindex > 701) { if (device->devindex > 18277) len += sprintf(gdp->disk_name + len, "%c", 'a'+(((device->devindex-18278) /17576)%26)); len += sprintf(gdp->disk_name + len, "%c", 'a'+(((device->devindex-702)/676)%26)); } len += sprintf(gdp->disk_name + len, "%c", 'a'+(((device->devindex-26)/26)%26)); } len += sprintf(gdp->disk_name + len, "%c", 'a'+(device->devindex%26)); sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id); if (test_bit(DASD_FLAG_RO, &device->flags)) set_disk_ro(gdp, 1); gdp->private_data = device; gdp->queue = device->request_queue; device->gdp = gdp; set_capacity(device->gdp, 0); add_disk(device->gdp); return 0; }
/* * Set read only */ static int dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) { struct dasd_block *block = bdev->bd_disk->private_data; int intval; if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (bdev != bdev->bd_contains) // ro setting is not allowed for partitions return -EINVAL; if (get_user(intval, (int __user *)argp)) return -EFAULT; set_disk_ro(bdev->bd_disk, intval); return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval); }
static int zvol_first_open(zvol_state_t *zv) { objset_t *os; uint64_t volsize; int locked = 0; int error; uint64_t ro; /* * In all other cases the spa_namespace_lock is taken before the * bdev->bd_mutex lock. But in this case the Linux __blkdev_get() * function calls fops->open() with the bdev->bd_mutex lock held. * * To avoid a potential lock inversion deadlock we preemptively * try to take the spa_namespace_lock(). Normally it will not * be contended and this is safe because spa_open_common() handles * the case where the caller already holds the spa_namespace_lock. * * When it is contended we risk a lock inversion if we were to * block waiting for the lock. Luckily, the __blkdev_get() * function allows us to return -ERESTARTSYS which will result in * bdev->bd_mutex being dropped, reacquired, and fops->open() being * called again. This process can be repeated safely until both * locks are acquired. */ if (!mutex_owned(&spa_namespace_lock)) { locked = mutex_tryenter(&spa_namespace_lock); if (!locked) return (-ERESTARTSYS); } /* lie and say we're read-only */ error = dmu_objset_own(zv->zv_name, DMU_OST_ZVOL, 1, zvol_tag, &os); if (error) goto out_mutex; error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize); if (error) { dmu_objset_disown(os, zvol_tag); goto out_mutex; } zv->zv_objset = os; error = dmu_bonus_hold(os, ZVOL_OBJ, zvol_tag, &zv->zv_dbuf); if (error) { dmu_objset_disown(os, zvol_tag); goto out_mutex; } set_capacity(zv->zv_disk, volsize >> 9); zv->zv_volsize = volsize; zv->zv_zilog = zil_open(os, zvol_get_data); VERIFY(dsl_prop_get_integer(zv->zv_name, "readonly", &ro, NULL) == 0); if (ro || dmu_objset_is_snapshot(os) || !spa_writeable(dmu_objset_spa(os))) { set_disk_ro(zv->zv_disk, 1); zv->zv_flags |= ZVOL_RDONLY; } else { set_disk_ro(zv->zv_disk, 0); zv->zv_flags &= ~ZVOL_RDONLY; } out_mutex: if (locked) mutex_exit(&spa_namespace_lock); return (-error); }
static void __init dm_setup_drive(void) { struct mapped_device *md = NULL; struct dm_table *table = NULL; struct dm_setup_target *target; char *uuid = dm_setup_args.uuid; fmode_t fmode = FMODE_READ; /* Finish parsing the targets. */ if (dm_setup_parse_targets(dm_setup_args.targets)) goto parse_fail; if (dm_create(dm_setup_args.minor, &md)) { DMDEBUG("failed to create the device"); goto dm_create_fail; } DMDEBUG("created device '%s'", dm_device_name(md)); /* In addition to flagging the table below, the disk must be * set explicitly ro/rw. */ set_disk_ro(dm_disk(md), dm_setup_args.ro); if (!dm_setup_args.ro) fmode |= FMODE_WRITE; if (dm_table_create(&table, fmode, dm_setup_args.target_count, md)) { DMDEBUG("failed to create the table"); goto dm_table_create_fail; } target = dm_setup_args.target; while (target) { DMINFO("adding target '%llu %llu %s %s'", (unsigned long long) target->begin, (unsigned long long) target->length, target->type, target->params); if (dm_table_add_target(table, target->type, target->begin, target->length, target->params)) { DMDEBUG("failed to add the target to the table"); goto add_target_fail; } target = target->next; } if (dm_table_complete(table)) { DMDEBUG("failed to complete the table"); goto table_complete_fail; } /* Suspend the device so that we can bind it to the table. */ if (dm_suspend(md, 0)) { DMDEBUG("failed to suspend the device pre-bind"); goto suspend_fail; } /* Bind the table to the device. This is the only way to associate * md->map with the table and set the disk capacity directly. */ if (dm_swap_table(md, table)) { /* should return NULL. */ DMDEBUG("failed to bind the device to the table"); goto table_bind_fail; } /* Finally, resume and the device should be ready. */ if (dm_resume(md)) { DMDEBUG("failed to resume the device"); goto resume_fail; } /* Export the dm device via the ioctl interface */ if (!strcmp(DM_NO_UUID, dm_setup_args.uuid)) uuid = NULL; if (dm_ioctl_export(md, dm_setup_args.name, uuid)) { DMDEBUG("failed to export device with given name and uuid"); goto export_fail; } printk(KERN_INFO "dm: dm-%d is ready\n", dm_setup_args.minor); dm_setup_cleanup(); return; export_fail: resume_fail: table_bind_fail: suspend_fail: table_complete_fail: add_target_fail: dm_table_put(table); dm_table_create_fail: dm_put(md); dm_create_fail: dm_setup_cleanup(); parse_fail: printk(KERN_WARNING "dm: starting dm-%d (%s) failed\n", dm_setup_args.minor, dm_setup_args.name); }