![Tejun Heo](/assets/img/avatar_default.png)
percpu.h is included by sched.h and module.h and thus ends up being included when building most .c files. percpu.h includes slab.h which in turn includes gfp.h making everything defined by the two files universally available and complicating inclusion dependencies. percpu.h -> slab.h dependency is about to be removed. Prepare for this change by updating users of gfp and slab facilities include those headers directly instead of assuming availability. As this conversion needs to touch large number of source files, the following script is used as the basis of conversion. http://userweb.kernel.org/~tj/misc/slabh-sweep.py The script does the followings. * Scan files for gfp and slab usages and update includes such that only the necessary includes are there. ie. if only gfp is used, gfp.h, if slab is used, slab.h. * When the script inserts a new include, it looks at the include blocks and try to put the new include such that its order conforms to its surrounding. It's put in the include block which contains core kernel includes, in the same order that the rest are ordered - alphabetical, Christmas tree, rev-Xmas-tree or at the end if there doesn't seem to be any matching order. * If the script can't find a place to put a new include (mostly because the file doesn't have fitting include block), it prints out an error message indicating which .h file needs to be added to the file. The conversion was done in the following steps. 1. The initial automatic conversion of all .c files updated slightly over 4000 files, deleting around 700 includes and adding ~480 gfp.h and ~3000 slab.h inclusions. The script emitted errors for ~400 files. 2. Each error was manually checked. Some didn't need the inclusion, some needed manual addition while adding it to implementation .h or embedding .c file was more appropriate for others. This step added inclusions to around 150 files. 3. The script was run again and the output was compared to the edits from #2 to make sure no file was left behind. 4. Several build tests were done and a couple of problems were fixed. e.g. lib/decompress_*.c used malloc/free() wrappers around slab APIs requiring slab.h to be added manually. 5. The script was run on all .h files but without automatically editing them as sprinkling gfp.h and slab.h inclusions around .h files could easily lead to inclusion dependency hell. Most gfp.h inclusion directives were ignored as stuff from gfp.h was usually wildly available and often used in preprocessor macros. Each slab.h inclusion directive was examined and added manually as necessary. 6. percpu.h was updated not to include slab.h. 7. Build test were done on the following configurations and failures were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my distributed build env didn't work with gcov compiles) and a few more options had to be turned off depending on archs to make things build (like ipr on powerpc/64 which failed due to missing writeq). * x86 and x86_64 UP and SMP allmodconfig and a custom test config. * powerpc and powerpc64 SMP allmodconfig * sparc and sparc64 SMP allmodconfig * ia64 SMP allmodconfig * s390 SMP allmodconfig * alpha SMP allmodconfig * um on x86_64 SMP allmodconfig 8. percpu.h modifications were reverted so that it could be applied as a separate patch and serve as bisection point. Given the fact that I had only a couple of failures from tests on step 6, I'm fairly confident about the coverage of this conversion patch. If there is a breakage, it's likely to be something in one of the arch headers which should be easily discoverable easily on most builds of the specific arch. Signed-off-by: Tejun Heo <tj@kernel.org> Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
444 lines
11 KiB
C
444 lines
11 KiB
C
/*
|
|
* File...........: linux/drivers/s390/block/dasd_ioctl.c
|
|
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
|
|
* Horst Hummel <Horst.Hummel@de.ibm.com>
|
|
* Carsten Otte <Cotte@de.ibm.com>
|
|
* Martin Schwidefsky <schwidefsky@de.ibm.com>
|
|
* Bugreports.to..: <Linux390@de.ibm.com>
|
|
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
|
|
*
|
|
* i/o controls for the dasd driver.
|
|
*/
|
|
|
|
#define KMSG_COMPONENT "dasd"
|
|
|
|
#include <linux/interrupt.h>
|
|
#include <linux/major.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/blkpg.h>
|
|
#include <linux/smp_lock.h>
|
|
#include <linux/slab.h>
|
|
#include <asm/compat.h>
|
|
#include <asm/ccwdev.h>
|
|
#include <asm/cmb.h>
|
|
#include <asm/uaccess.h>
|
|
|
|
/* This is ugly... */
|
|
#define PRINTK_HEADER "dasd_ioctl:"
|
|
|
|
#include "dasd_int.h"
|
|
|
|
|
|
static int
|
|
dasd_ioctl_api_version(void __user *argp)
|
|
{
|
|
int ver = DASD_API_VERSION;
|
|
return put_user(ver, (int __user *)argp);
|
|
}
|
|
|
|
/*
|
|
* Enable device.
|
|
* used by dasdfmt after BIODASDDISABLE to retrigger blocksize detection
|
|
*/
|
|
static int
|
|
dasd_ioctl_enable(struct block_device *bdev)
|
|
{
|
|
struct dasd_block *block = bdev->bd_disk->private_data;
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
return -EACCES;
|
|
|
|
dasd_enable_device(block->base);
|
|
/* Formatting the dasd device can change the capacity. */
|
|
mutex_lock(&bdev->bd_mutex);
|
|
i_size_write(bdev->bd_inode, (loff_t)get_capacity(block->gdp) << 9);
|
|
mutex_unlock(&bdev->bd_mutex);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Disable device.
|
|
* Used by dasdfmt. Disable I/O operations but allow ioctls.
|
|
*/
|
|
static int
|
|
dasd_ioctl_disable(struct block_device *bdev)
|
|
{
|
|
struct dasd_block *block = bdev->bd_disk->private_data;
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
return -EACCES;
|
|
|
|
/*
|
|
* 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(block->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);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Quiesce device.
|
|
*/
|
|
static int dasd_ioctl_quiesce(struct dasd_block *block)
|
|
{
|
|
unsigned long flags;
|
|
struct dasd_device *base;
|
|
|
|
base = block->base;
|
|
if (!capable (CAP_SYS_ADMIN))
|
|
return -EACCES;
|
|
|
|
pr_info("%s: The DASD has been put in the quiesce "
|
|
"state\n", dev_name(&base->cdev->dev));
|
|
spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
|
|
dasd_device_set_stop_bits(base, DASD_STOPPED_QUIESCE);
|
|
spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Resume device.
|
|
*/
|
|
static int dasd_ioctl_resume(struct dasd_block *block)
|
|
{
|
|
unsigned long flags;
|
|
struct dasd_device *base;
|
|
|
|
base = block->base;
|
|
if (!capable (CAP_SYS_ADMIN))
|
|
return -EACCES;
|
|
|
|
pr_info("%s: I/O operations have been resumed "
|
|
"on the DASD\n", dev_name(&base->cdev->dev));
|
|
spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
|
|
dasd_device_remove_stop_bits(base, DASD_STOPPED_QUIESCE);
|
|
spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
|
|
|
|
dasd_schedule_block_bh(block);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* performs formatting of _device_ according to _fdata_
|
|
* Note: The discipline's format_function is assumed to deliver formatting
|
|
* commands to format a single unit of the device. In terms of the ECKD
|
|
* devices this means CCWs are generated to format a single track.
|
|
*/
|
|
static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
|
|
{
|
|
struct dasd_ccw_req *cqr;
|
|
struct dasd_device *base;
|
|
int rc;
|
|
|
|
base = block->base;
|
|
if (base->discipline->format_device == NULL)
|
|
return -EPERM;
|
|
|
|
if (base->state != DASD_STATE_BASIC) {
|
|
pr_warning("%s: The DASD cannot be formatted while it is "
|
|
"enabled\n", dev_name(&base->cdev->dev));
|
|
return -EBUSY;
|
|
}
|
|
|
|
DBF_DEV_EVENT(DBF_NOTICE, base,
|
|
"formatting units %u to %u (%u B blocks) flags %u",
|
|
fdata->start_unit,
|
|
fdata->stop_unit, fdata->blksize, fdata->intensity);
|
|
|
|
/* Since dasdfmt keeps the device open after it was disabled,
|
|
* there still exists an inode for this device.
|
|
* We must update i_blkbits, otherwise we might get errors when
|
|
* enabling the device later.
|
|
*/
|
|
if (fdata->start_unit == 0) {
|
|
struct block_device *bdev = bdget_disk(block->gdp, 0);
|
|
bdev->bd_inode->i_blkbits = blksize_bits(fdata->blksize);
|
|
bdput(bdev);
|
|
}
|
|
|
|
while (fdata->start_unit <= fdata->stop_unit) {
|
|
cqr = base->discipline->format_device(base, fdata);
|
|
if (IS_ERR(cqr))
|
|
return PTR_ERR(cqr);
|
|
rc = dasd_sleep_on_interruptible(cqr);
|
|
dasd_sfree_request(cqr, cqr->memdev);
|
|
if (rc) {
|
|
if (rc != -ERESTARTSYS)
|
|
pr_err("%s: Formatting unit %d failed with "
|
|
"rc=%d\n", dev_name(&base->cdev->dev),
|
|
fdata->start_unit, rc);
|
|
return rc;
|
|
}
|
|
fdata->start_unit++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Format device.
|
|
*/
|
|
static int
|
|
dasd_ioctl_format(struct block_device *bdev, void __user *argp)
|
|
{
|
|
struct dasd_block *block = bdev->bd_disk->private_data;
|
|
struct format_data_t fdata;
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
return -EACCES;
|
|
if (!argp)
|
|
return -EINVAL;
|
|
|
|
if (block->base->features & DASD_FEATURE_READONLY ||
|
|
test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags))
|
|
return -EROFS;
|
|
if (copy_from_user(&fdata, argp, sizeof(struct format_data_t)))
|
|
return -EFAULT;
|
|
if (bdev != bdev->bd_contains) {
|
|
pr_warning("%s: The specified DASD is a partition and cannot "
|
|
"be formatted\n",
|
|
dev_name(&block->base->cdev->dev));
|
|
return -EINVAL;
|
|
}
|
|
return dasd_format(block, &fdata);
|
|
}
|
|
|
|
#ifdef CONFIG_DASD_PROFILE
|
|
/*
|
|
* Reset device profile information
|
|
*/
|
|
static int dasd_ioctl_reset_profile(struct dasd_block *block)
|
|
{
|
|
memset(&block->profile, 0, sizeof(struct dasd_profile_info_t));
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Return device profile information
|
|
*/
|
|
static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
|
|
{
|
|
if (dasd_profile_level == DASD_PROFILE_OFF)
|
|
return -EIO;
|
|
if (copy_to_user(argp, &block->profile,
|
|
sizeof(struct dasd_profile_info_t)))
|
|
return -EFAULT;
|
|
return 0;
|
|
}
|
|
#else
|
|
static int dasd_ioctl_reset_profile(struct dasd_block *block)
|
|
{
|
|
return -ENOSYS;
|
|
}
|
|
|
|
static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
|
|
{
|
|
return -ENOSYS;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Return dasd information. Used for BIODASDINFO and BIODASDINFO2.
|
|
*/
|
|
static int dasd_ioctl_information(struct dasd_block *block,
|
|
unsigned int cmd, void __user *argp)
|
|
{
|
|
struct dasd_information2_t *dasd_info;
|
|
unsigned long flags;
|
|
int rc;
|
|
struct dasd_device *base;
|
|
struct ccw_device *cdev;
|
|
struct ccw_dev_id dev_id;
|
|
|
|
base = block->base;
|
|
if (!base->discipline || !base->discipline->fill_info)
|
|
return -EINVAL;
|
|
|
|
dasd_info = kzalloc(sizeof(struct dasd_information2_t), GFP_KERNEL);
|
|
if (dasd_info == NULL)
|
|
return -ENOMEM;
|
|
|
|
rc = base->discipline->fill_info(base, dasd_info);
|
|
if (rc) {
|
|
kfree(dasd_info);
|
|
return rc;
|
|
}
|
|
|
|
cdev = base->cdev;
|
|
ccw_device_get_id(cdev, &dev_id);
|
|
|
|
dasd_info->devno = dev_id.devno;
|
|
dasd_info->schid = _ccw_device_get_subchannel_number(base->cdev);
|
|
dasd_info->cu_type = cdev->id.cu_type;
|
|
dasd_info->cu_model = cdev->id.cu_model;
|
|
dasd_info->dev_type = cdev->id.dev_type;
|
|
dasd_info->dev_model = cdev->id.dev_model;
|
|
dasd_info->status = base->state;
|
|
/*
|
|
* The open_count is increased for every opener, that includes
|
|
* the blkdev_get in dasd_scan_partitions.
|
|
* This must be hidden from user-space.
|
|
*/
|
|
dasd_info->open_count = atomic_read(&block->open_count);
|
|
if (!block->bdev)
|
|
dasd_info->open_count++;
|
|
|
|
/*
|
|
* check if device is really formatted
|
|
* LDL / CDL was returned by 'fill_info'
|
|
*/
|
|
if ((base->state < DASD_STATE_READY) ||
|
|
(dasd_check_blocksize(block->bp_block)))
|
|
dasd_info->format = DASD_FORMAT_NONE;
|
|
|
|
dasd_info->features |=
|
|
((base->features & DASD_FEATURE_READONLY) != 0);
|
|
|
|
memcpy(dasd_info->type, base->discipline->name, 4);
|
|
|
|
if (block->request_queue->request_fn) {
|
|
struct list_head *l;
|
|
#ifdef DASD_EXTENDED_PROFILING
|
|
{
|
|
struct list_head *l;
|
|
spin_lock_irqsave(&block->lock, flags);
|
|
list_for_each(l, &block->request_queue->queue_head)
|
|
dasd_info->req_queue_len++;
|
|
spin_unlock_irqrestore(&block->lock, flags);
|
|
}
|
|
#endif /* DASD_EXTENDED_PROFILING */
|
|
spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
|
|
list_for_each(l, &base->ccw_queue)
|
|
dasd_info->chanq_len++;
|
|
spin_unlock_irqrestore(get_ccwdev_lock(base->cdev),
|
|
flags);
|
|
}
|
|
|
|
rc = 0;
|
|
if (copy_to_user(argp, dasd_info,
|
|
((cmd == (unsigned int) BIODASDINFO2) ?
|
|
sizeof(struct dasd_information2_t) :
|
|
sizeof(struct dasd_information_t))))
|
|
rc = -EFAULT;
|
|
kfree(dasd_info);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags))
|
|
return -EROFS;
|
|
set_disk_ro(bdev->bd_disk, intval);
|
|
return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval);
|
|
}
|
|
|
|
static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd,
|
|
struct cmbdata __user *argp)
|
|
{
|
|
size_t size = _IOC_SIZE(cmd);
|
|
struct cmbdata data;
|
|
int ret;
|
|
|
|
ret = cmf_readall(block->base->cdev, &data);
|
|
if (!ret && copy_to_user(argp, &data, min(size, sizeof(*argp))))
|
|
return -EFAULT;
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
dasd_do_ioctl(struct block_device *bdev, fmode_t mode,
|
|
unsigned int cmd, unsigned long arg)
|
|
{
|
|
struct dasd_block *block = bdev->bd_disk->private_data;
|
|
void __user *argp;
|
|
|
|
if (is_compat_task())
|
|
argp = compat_ptr(arg);
|
|
else
|
|
argp = (void __user *)arg;
|
|
|
|
if (!block)
|
|
return -ENODEV;
|
|
|
|
if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) {
|
|
PRINT_DEBUG("empty data ptr");
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (cmd) {
|
|
case BIODASDDISABLE:
|
|
return dasd_ioctl_disable(bdev);
|
|
case BIODASDENABLE:
|
|
return dasd_ioctl_enable(bdev);
|
|
case BIODASDQUIESCE:
|
|
return dasd_ioctl_quiesce(block);
|
|
case BIODASDRESUME:
|
|
return dasd_ioctl_resume(block);
|
|
case BIODASDFMT:
|
|
return dasd_ioctl_format(bdev, argp);
|
|
case BIODASDINFO:
|
|
return dasd_ioctl_information(block, cmd, argp);
|
|
case BIODASDINFO2:
|
|
return dasd_ioctl_information(block, cmd, argp);
|
|
case BIODASDPRRD:
|
|
return dasd_ioctl_read_profile(block, argp);
|
|
case BIODASDPRRST:
|
|
return dasd_ioctl_reset_profile(block);
|
|
case BLKROSET:
|
|
return dasd_ioctl_set_ro(bdev, argp);
|
|
case DASDAPIVER:
|
|
return dasd_ioctl_api_version(argp);
|
|
case BIODASDCMFENABLE:
|
|
return enable_cmf(block->base->cdev);
|
|
case BIODASDCMFDISABLE:
|
|
return disable_cmf(block->base->cdev);
|
|
case BIODASDREADALLCMB:
|
|
return dasd_ioctl_readall_cmb(block, cmd, argp);
|
|
default:
|
|
/* if the discipline has an ioctl method try it. */
|
|
if (block->base->discipline->ioctl) {
|
|
int rval = block->base->discipline->ioctl(block, cmd, argp);
|
|
if (rval != -ENOIOCTLCMD)
|
|
return rval;
|
|
}
|
|
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
int dasd_ioctl(struct block_device *bdev, fmode_t mode,
|
|
unsigned int cmd, unsigned long arg)
|
|
{
|
|
int rc;
|
|
|
|
lock_kernel();
|
|
rc = dasd_do_ioctl(bdev, mode, cmd, arg);
|
|
unlock_kernel();
|
|
return rc;
|
|
}
|