/* * 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; }
/* * Format device. */ static int dasd_ioctl_format(struct block_device *bdev, void __user *argp) { struct dasd_device *base; struct format_data_t fdata; int rc; if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (!argp) return -EINVAL; base = dasd_device_from_gendisk(bdev->bd_disk); if (!base) return -ENODEV; if (base->features & DASD_FEATURE_READONLY || test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) { dasd_put_device(base); return -EROFS; } if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) { dasd_put_device(base); return -EFAULT; } if (bdev != bdev->bd_contains) { pr_warning("%s: The specified DASD is a partition and cannot " "be formatted\n", dev_name(&base->cdev->dev)); dasd_put_device(base); return -EINVAL; } rc = dasd_format(base->block, &fdata); dasd_put_device(base); return rc; }
/* * Disable device. * Used by dasdfmt. Disable I/O operations but allow ioctls. */ static int dasd_ioctl_disable(struct block_device *bdev) { struct dasd_device *base; if (!capable(CAP_SYS_ADMIN)) return -EACCES; base = dasd_device_from_gendisk(bdev->bd_disk); if (!base) return -ENODEV; /* * Man this is sick. We don't do a real disable but only downgrade * the device to DASD_STATE_BASIC. The reason is that dasdfmt uses * BIODASDDISABLE to disable accesses to the device via the block * device layer but it still wants to do i/o on the device by * using the BIODASDFMT ioctl. Therefore the correct state for the * device is DASD_STATE_BASIC that allows to do basic i/o. */ dasd_set_target_state(base, DASD_STATE_BASIC); /* * Set i_size to zero, since read, write, etc. check against this * value. */ mutex_lock(&bdev->bd_mutex); i_size_write(bdev->bd_inode, 0); mutex_unlock(&bdev->bd_mutex); dasd_put_device(base); return 0; }
static void dasd_stats_all_block_reset(void) { int i; struct dasd_device *device; for (i = 0; i < dasd_max_devindex; ++i) { device = dasd_device_from_devindex(i); if (IS_ERR(device)) continue; if (device->block) dasd_profile_reset(&device->block->profile); dasd_put_device(device); } }
static int dasd_stats_all_block_on(void) { int i, rc; struct dasd_device *device; rc = 0; for (i = 0; i < dasd_max_devindex; ++i) { device = dasd_device_from_devindex(i); if (IS_ERR(device)) continue; if (device->block) rc = dasd_profile_on(&device->block->profile); dasd_put_device(device); if (rc) return rc; } return 0; }
/* * Enable device. * used by dasdfmt after BIODASDDISABLE to retrigger blocksize detection */ static int dasd_ioctl_enable(struct block_device *bdev) { struct dasd_device *base; if (!capable(CAP_SYS_ADMIN)) return -EACCES; base = dasd_device_from_gendisk(bdev->bd_disk); if (!base) return -ENODEV; dasd_enable_device(base); /* Formatting the dasd device can change the capacity. */ mutex_lock(&bdev->bd_mutex); i_size_write(bdev->bd_inode, (loff_t)get_capacity(base->block->gdp) << 9); mutex_unlock(&bdev->bd_mutex); dasd_put_device(base); return 0; }
static int dasd_devices_show(struct seq_file *m, void *v) { struct dasd_device *device; struct dasd_block *block; char *substr; device = dasd_device_from_devindex((unsigned long) v - 1); if (IS_ERR(device)) return 0; if (device->block) block = device->block; else { dasd_put_device(device); return 0; } /* Print device number. */ seq_printf(m, "%s", dev_name(&device->cdev->dev)); /* Print discipline string. */ if (device != NULL && device->discipline != NULL) seq_printf(m, "(%s)", device->discipline->name); else seq_printf(m, "(none)"); /* Print kdev. */ if (block->gdp) seq_printf(m, " at (%3d:%6d)", MAJOR(disk_devt(block->gdp)), MINOR(disk_devt(block->gdp))); else seq_printf(m, " at (???:??????)"); /* Print device name. */ if (block->gdp) seq_printf(m, " is %-8s", block->gdp->disk_name); else seq_printf(m, " is ????????"); /* Print devices features. */ substr = (device->features & DASD_FEATURE_READONLY) ? "(ro)" : " "; seq_printf(m, "%4s: ", substr); /* Print device status information. */ switch ((device != NULL) ? device->state : -1) { case -1: seq_printf(m, "unknown"); break; case DASD_STATE_NEW: seq_printf(m, "new"); break; case DASD_STATE_KNOWN: seq_printf(m, "detected"); break; case DASD_STATE_BASIC: seq_printf(m, "basic"); break; case DASD_STATE_UNFMT: seq_printf(m, "unformatted"); break; case DASD_STATE_READY: case DASD_STATE_ONLINE: seq_printf(m, "active "); if (dasd_check_blocksize(block->bp_block)) seq_printf(m, "n/f "); else seq_printf(m, "at blocksize: %d, %ld blocks, %ld MB", block->bp_block, block->blocks, ((block->bp_block >> 9) * block->blocks) >> 11); break; default: seq_printf(m, "no stat"); break; } dasd_put_device(device); if (dasd_probeonly) seq_printf(m, "(probeonly)"); seq_printf(m, "\n"); return 0; }
int dasd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { struct dasd_block *block; struct dasd_device *base; void __user *argp; int rc; if (is_compat_task()) argp = compat_ptr(arg); else argp = (void __user *)arg; if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) { PRINT_DEBUG("empty data ptr"); return -EINVAL; } base = dasd_device_from_gendisk(bdev->bd_disk); if (!base) return -ENODEV; block = base->block; rc = 0; switch (cmd) { case BIODASDDISABLE: rc = dasd_ioctl_disable(bdev); break; case BIODASDENABLE: rc = dasd_ioctl_enable(bdev); break; case BIODASDQUIESCE: rc = dasd_ioctl_quiesce(block); break; case BIODASDRESUME: rc = dasd_ioctl_resume(block); break; case BIODASDFMT: rc = dasd_ioctl_format(bdev, argp); break; case BIODASDINFO: rc = dasd_ioctl_information(block, cmd, argp); break; case BIODASDINFO2: rc = dasd_ioctl_information(block, cmd, argp); break; case BIODASDPRRD: rc = dasd_ioctl_read_profile(block, argp); break; case BIODASDPRRST: rc = dasd_ioctl_reset_profile(block); break; case BLKROSET: rc = dasd_ioctl_set_ro(bdev, argp); break; case DASDAPIVER: rc = dasd_ioctl_api_version(argp); break; case BIODASDCMFENABLE: rc = enable_cmf(base->cdev); break; case BIODASDCMFDISABLE: rc = disable_cmf(base->cdev); break; case BIODASDREADALLCMB: rc = dasd_ioctl_readall_cmb(block, cmd, argp); break; default: /* if the discipline has an ioctl method try it. */ if (base->discipline->ioctl) { rc = base->discipline->ioctl(block, cmd, argp); if (rc == -ENOIOCTLCMD) rc = -EINVAL; } else rc = -EINVAL; } dasd_put_device(base); return rc; }
static int dasd_devices_show(struct seq_file *m, void *v) { struct dasd_device *device; char *substr; device = dasd_device_from_devindex((unsigned long) v - 1); if (IS_ERR(device)) return 0; /* Print device number. */ seq_printf(m, "%s", device->cdev->dev.bus_id); /* Print discipline string. */ if (device != NULL && device->discipline != NULL) seq_printf(m, "(%s)", device->discipline->name); else seq_printf(m, "(none)"); /* Print kdev. */ if (device->gdp) seq_printf(m, " at (%3d:%6d)", device->gdp->major, device->gdp->first_minor); else seq_printf(m, " at (???:??????)"); /* Print device name. */ if (device->gdp) seq_printf(m, " is %-8s", device->gdp->disk_name); else seq_printf(m, " is ????????"); /* Print devices features. */ substr = test_bit(DASD_FLAG_RO, &device->flags) ? "(ro)" : " "; seq_printf(m, "%4s: ", substr); /* Print device status information. */ switch ((device != NULL) ? device->state : -1) { case -1: seq_printf(m, "unknown"); break; case DASD_STATE_NEW: seq_printf(m, "new"); break; case DASD_STATE_KNOWN: seq_printf(m, "detected"); break; case DASD_STATE_BASIC: seq_printf(m, "basic"); break; case DASD_STATE_READY: case DASD_STATE_ONLINE: seq_printf(m, "active "); if (dasd_check_blocksize(device->bp_block)) seq_printf(m, "n/f "); else seq_printf(m, "at blocksize: %d, %ld blocks, %ld MB", device->bp_block, device->blocks, ((device->bp_block >> 9) * device->blocks) >> 11); break; default: seq_printf(m, "no stat"); break; } dasd_put_device(device); if (dasd_probeonly) seq_printf(m, "(probeonly)"); seq_printf(m, "\n"); return 0; }