mirror of
https://github.com/torvalds/linux.git
synced 2024-11-16 09:02:00 +00:00
71baba4b92
__GFP_WAIT was used to signal that the caller was in atomic context and could not sleep. Now it is possible to distinguish between true atomic context and callers that are not willing to sleep. The latter should clear __GFP_DIRECT_RECLAIM so kswapd will still wake. As clearing __GFP_WAIT behaves differently, there is a risk that people will clear the wrong flags. This patch renames __GFP_WAIT to __GFP_RECLAIM to clearly indicate what it does -- setting it allows all reclaim activity, clearing them prevents it. [akpm@linux-foundation.org: fix build] [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Mel Gorman <mgorman@techsingularity.net> Acked-by: Michal Hocko <mhocko@suse.com> Acked-by: Vlastimil Babka <vbabka@suse.cz> Acked-by: Johannes Weiner <hannes@cmpxchg.org> Cc: Christoph Lameter <cl@linux.com> Acked-by: David Rientjes <rientjes@google.com> Cc: Vitaly Wool <vitalywool@gmail.com> Cc: Rik van Riel <riel@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
192 lines
3.8 KiB
C
192 lines
3.8 KiB
C
|
|
#include <linux/kernel.h>
|
|
#include <linux/gfp.h>
|
|
#include <linux/ide.h>
|
|
|
|
DEFINE_MUTEX(ide_setting_mtx);
|
|
|
|
ide_devset_get(io_32bit, io_32bit);
|
|
|
|
static int set_io_32bit(ide_drive_t *drive, int arg)
|
|
{
|
|
if (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT)
|
|
return -EPERM;
|
|
|
|
if (arg < 0 || arg > 1 + (SUPPORT_VLB_SYNC << 1))
|
|
return -EINVAL;
|
|
|
|
drive->io_32bit = arg;
|
|
|
|
return 0;
|
|
}
|
|
|
|
ide_devset_get_flag(ksettings, IDE_DFLAG_KEEP_SETTINGS);
|
|
|
|
static int set_ksettings(ide_drive_t *drive, int arg)
|
|
{
|
|
if (arg < 0 || arg > 1)
|
|
return -EINVAL;
|
|
|
|
if (arg)
|
|
drive->dev_flags |= IDE_DFLAG_KEEP_SETTINGS;
|
|
else
|
|
drive->dev_flags &= ~IDE_DFLAG_KEEP_SETTINGS;
|
|
|
|
return 0;
|
|
}
|
|
|
|
ide_devset_get_flag(using_dma, IDE_DFLAG_USING_DMA);
|
|
|
|
static int set_using_dma(ide_drive_t *drive, int arg)
|
|
{
|
|
#ifdef CONFIG_BLK_DEV_IDEDMA
|
|
int err = -EPERM;
|
|
|
|
if (arg < 0 || arg > 1)
|
|
return -EINVAL;
|
|
|
|
if (ata_id_has_dma(drive->id) == 0)
|
|
goto out;
|
|
|
|
if (drive->hwif->dma_ops == NULL)
|
|
goto out;
|
|
|
|
err = 0;
|
|
|
|
if (arg) {
|
|
if (ide_set_dma(drive))
|
|
err = -EIO;
|
|
} else
|
|
ide_dma_off(drive);
|
|
|
|
out:
|
|
return err;
|
|
#else
|
|
if (arg < 0 || arg > 1)
|
|
return -EINVAL;
|
|
|
|
return -EPERM;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away
|
|
*/
|
|
static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio)
|
|
{
|
|
switch (req_pio) {
|
|
case 202:
|
|
case 201:
|
|
case 200:
|
|
case 102:
|
|
case 101:
|
|
case 100:
|
|
return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0;
|
|
case 9:
|
|
case 8:
|
|
return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0;
|
|
case 7:
|
|
case 6:
|
|
return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int set_pio_mode(ide_drive_t *drive, int arg)
|
|
{
|
|
ide_hwif_t *hwif = drive->hwif;
|
|
const struct ide_port_ops *port_ops = hwif->port_ops;
|
|
|
|
if (arg < 0 || arg > 255)
|
|
return -EINVAL;
|
|
|
|
if (port_ops == NULL || port_ops->set_pio_mode == NULL ||
|
|
(hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
|
|
return -ENOSYS;
|
|
|
|
if (set_pio_mode_abuse(drive->hwif, arg)) {
|
|
drive->pio_mode = arg + XFER_PIO_0;
|
|
|
|
if (arg == 8 || arg == 9) {
|
|
unsigned long flags;
|
|
|
|
/* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */
|
|
spin_lock_irqsave(&hwif->lock, flags);
|
|
port_ops->set_pio_mode(hwif, drive);
|
|
spin_unlock_irqrestore(&hwif->lock, flags);
|
|
} else
|
|
port_ops->set_pio_mode(hwif, drive);
|
|
} else {
|
|
int keep_dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
|
|
|
|
ide_set_pio(drive, arg);
|
|
|
|
if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {
|
|
if (keep_dma)
|
|
ide_dma_on(drive);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
ide_devset_get_flag(unmaskirq, IDE_DFLAG_UNMASK);
|
|
|
|
static int set_unmaskirq(ide_drive_t *drive, int arg)
|
|
{
|
|
if (drive->dev_flags & IDE_DFLAG_NO_UNMASK)
|
|
return -EPERM;
|
|
|
|
if (arg < 0 || arg > 1)
|
|
return -EINVAL;
|
|
|
|
if (arg)
|
|
drive->dev_flags |= IDE_DFLAG_UNMASK;
|
|
else
|
|
drive->dev_flags &= ~IDE_DFLAG_UNMASK;
|
|
|
|
return 0;
|
|
}
|
|
|
|
ide_ext_devset_rw_sync(io_32bit, io_32bit);
|
|
ide_ext_devset_rw_sync(keepsettings, ksettings);
|
|
ide_ext_devset_rw_sync(unmaskirq, unmaskirq);
|
|
ide_ext_devset_rw_sync(using_dma, using_dma);
|
|
__IDE_DEVSET(pio_mode, DS_SYNC, NULL, set_pio_mode);
|
|
|
|
int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting,
|
|
int arg)
|
|
{
|
|
struct request_queue *q = drive->queue;
|
|
struct request *rq;
|
|
int ret = 0;
|
|
|
|
if (!(setting->flags & DS_SYNC))
|
|
return setting->set(drive, arg);
|
|
|
|
rq = blk_get_request(q, READ, __GFP_RECLAIM);
|
|
rq->cmd_type = REQ_TYPE_DRV_PRIV;
|
|
rq->cmd_len = 5;
|
|
rq->cmd[0] = REQ_DEVSET_EXEC;
|
|
*(int *)&rq->cmd[1] = arg;
|
|
rq->special = setting->set;
|
|
|
|
if (blk_execute_rq(q, NULL, rq, 0))
|
|
ret = rq->errors;
|
|
blk_put_request(rq);
|
|
|
|
return ret;
|
|
}
|
|
|
|
ide_startstop_t ide_do_devset(ide_drive_t *drive, struct request *rq)
|
|
{
|
|
int err, (*setfunc)(ide_drive_t *, int) = rq->special;
|
|
|
|
err = setfunc(drive, *(int *)&rq->cmd[1]);
|
|
if (err)
|
|
rq->errors = err;
|
|
ide_complete_rq(drive, err, blk_rq_bytes(rq));
|
|
return ide_stopped;
|
|
}
|