Commit a3da2c69 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.dk/linux-block

Pull block bits from Jens Axboe:
 "As vacation is coming up, thought I'd better get rid of my pending
  changes in my for-linus branch for this iteration.  It contains:

   - Two patches for mtip32xx.  Killing a non-compliant sysfs interface
     and moving it to debugfs, where it belongs.

   - A few patches from Asias.  Two legit bug fixes, and one killing an
     interface that is no longer in use.

   - A patch from Jan, making the annoying partition ioctl warning a bit
     less annoying, by restricting it to !CAP_SYS_RAWIO only.

   - Three bug fixes for drbd from Lars Ellenberg.

   - A fix for an old regression for umem, it hasn't really worked since
     the plugging scheme was changed in 3.0.

   - A few fixes from Tejun.

   - A splice fix from Eric Dumazet, fixing an issue with pipe
     resizing."

* 'for-linus' of git://git.kernel.dk/linux-block:
  scsi: Silence unnecessary warnings about ioctl to partition
  block: Drop dead function blk_abort_queue()
  block: Mitigate lock unbalance caused by lock switching
  block: Avoid missed wakeup in request waitqueue
  umem: fix up unplugging
  splice: fix racy pipe->buffers uses
  drbd: fix null pointer dereference with on-congestion policy when diskless
  drbd: fix list corruption by failing but already aborted reads
  drbd: fix access of unallocated pages and kernel panic
  xen/blkfront: Add WARN to deal with misbehaving backends.
  blkcg: drop local variable @q from blkg_destroy()
  mtip32xx: Create debugfs entries for troubleshooting
  mtip32xx: Remove 'registers' and 'flags' from sysfs
  blkcg: fix blkg_alloc() failure path
  block: blkcg_policy_cfq shouldn't be used if !CONFIG_CFQ_GROUP_IOSCHED
  block: fix return value on cfq_init() failure
  mtip32xx: Remove version.h header file inclusion
  xen/blkback: Copy id field when doing BLKIF_DISCARD.
parents ff826b2b 6d935928
What: /sys/block/rssd*/registers
Date: March 2012
KernelVersion: 3.3
Contact: Asai Thambi S P <asamymuthupa@micron.com>
Description: This is a read-only file. Dumps below driver information and
hardware registers.
- S ACTive
- Command Issue
- Completed
- PORT IRQ STAT
- HOST IRQ STAT
- Allocated
- Commands in Q
What: /sys/block/rssd*/status What: /sys/block/rssd*/status
Date: April 2012 Date: April 2012
KernelVersion: 3.4 KernelVersion: 3.4
Contact: Asai Thambi S P <asamymuthupa@micron.com> Contact: Asai Thambi S P <asamymuthupa@micron.com>
Description: This is a read-only file. Indicates the status of the device. Description: This is a read-only file. Indicates the status of the device.
What: /sys/block/rssd*/flags
Date: May 2012
KernelVersion: 3.5
Contact: Asai Thambi S P <asamymuthupa@micron.com>
Description: This is a read-only file. Dumps the flags in port and driver
data structure
...@@ -125,12 +125,8 @@ static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct request_queue *q) ...@@ -125,12 +125,8 @@ static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct request_queue *q)
blkg->pd[i] = pd; blkg->pd[i] = pd;
pd->blkg = blkg; pd->blkg = blkg;
}
/* invoke per-policy init */ /* invoke per-policy init */
for (i = 0; i < BLKCG_MAX_POLS; i++) {
struct blkcg_policy *pol = blkcg_policy[i];
if (blkcg_policy_enabled(blkg->q, pol)) if (blkcg_policy_enabled(blkg->q, pol))
pol->pd_init_fn(blkg); pol->pd_init_fn(blkg);
} }
...@@ -245,10 +241,9 @@ EXPORT_SYMBOL_GPL(blkg_lookup_create); ...@@ -245,10 +241,9 @@ EXPORT_SYMBOL_GPL(blkg_lookup_create);
static void blkg_destroy(struct blkcg_gq *blkg) static void blkg_destroy(struct blkcg_gq *blkg)
{ {
struct request_queue *q = blkg->q;
struct blkcg *blkcg = blkg->blkcg; struct blkcg *blkcg = blkg->blkcg;
lockdep_assert_held(q->queue_lock); lockdep_assert_held(blkg->q->queue_lock);
lockdep_assert_held(&blkcg->lock); lockdep_assert_held(&blkcg->lock);
/* Something wrong if we are trying to remove same group twice */ /* Something wrong if we are trying to remove same group twice */
......
...@@ -361,9 +361,10 @@ EXPORT_SYMBOL(blk_put_queue); ...@@ -361,9 +361,10 @@ EXPORT_SYMBOL(blk_put_queue);
*/ */
void blk_drain_queue(struct request_queue *q, bool drain_all) void blk_drain_queue(struct request_queue *q, bool drain_all)
{ {
int i;
while (true) { while (true) {
bool drain = false; bool drain = false;
int i;
spin_lock_irq(q->queue_lock); spin_lock_irq(q->queue_lock);
...@@ -408,6 +409,18 @@ void blk_drain_queue(struct request_queue *q, bool drain_all) ...@@ -408,6 +409,18 @@ void blk_drain_queue(struct request_queue *q, bool drain_all)
break; break;
msleep(10); msleep(10);
} }
/*
* With queue marked dead, any woken up waiter will fail the
* allocation path, so the wakeup chaining is lost and we're
* left with hung waiters. We need to wake up those waiters.
*/
if (q->request_fn) {
spin_lock_irq(q->queue_lock);
for (i = 0; i < ARRAY_SIZE(q->rq.wait); i++)
wake_up_all(&q->rq.wait[i]);
spin_unlock_irq(q->queue_lock);
}
} }
/** /**
...@@ -467,7 +480,6 @@ void blk_cleanup_queue(struct request_queue *q) ...@@ -467,7 +480,6 @@ void blk_cleanup_queue(struct request_queue *q)
/* mark @q DEAD, no new request or merges will be allowed afterwards */ /* mark @q DEAD, no new request or merges will be allowed afterwards */
mutex_lock(&q->sysfs_lock); mutex_lock(&q->sysfs_lock);
queue_flag_set_unlocked(QUEUE_FLAG_DEAD, q); queue_flag_set_unlocked(QUEUE_FLAG_DEAD, q);
spin_lock_irq(lock); spin_lock_irq(lock);
/* /*
...@@ -485,10 +497,6 @@ void blk_cleanup_queue(struct request_queue *q) ...@@ -485,10 +497,6 @@ void blk_cleanup_queue(struct request_queue *q)
queue_flag_set(QUEUE_FLAG_NOMERGES, q); queue_flag_set(QUEUE_FLAG_NOMERGES, q);
queue_flag_set(QUEUE_FLAG_NOXMERGES, q); queue_flag_set(QUEUE_FLAG_NOXMERGES, q);
queue_flag_set(QUEUE_FLAG_DEAD, q); queue_flag_set(QUEUE_FLAG_DEAD, q);
if (q->queue_lock != &q->__queue_lock)
q->queue_lock = &q->__queue_lock;
spin_unlock_irq(lock); spin_unlock_irq(lock);
mutex_unlock(&q->sysfs_lock); mutex_unlock(&q->sysfs_lock);
...@@ -499,6 +507,11 @@ void blk_cleanup_queue(struct request_queue *q) ...@@ -499,6 +507,11 @@ void blk_cleanup_queue(struct request_queue *q)
del_timer_sync(&q->backing_dev_info.laptop_mode_wb_timer); del_timer_sync(&q->backing_dev_info.laptop_mode_wb_timer);
blk_sync_queue(q); blk_sync_queue(q);
spin_lock_irq(lock);
if (q->queue_lock != &q->__queue_lock)
q->queue_lock = &q->__queue_lock;
spin_unlock_irq(lock);
/* @q is and will stay empty, shutdown and put */ /* @q is and will stay empty, shutdown and put */
blk_put_queue(q); blk_put_queue(q);
} }
......
...@@ -197,44 +197,3 @@ void blk_add_timer(struct request *req) ...@@ -197,44 +197,3 @@ void blk_add_timer(struct request *req)
mod_timer(&q->timeout, expiry); mod_timer(&q->timeout, expiry);
} }
/**
* blk_abort_queue -- Abort all request on given queue
* @queue: pointer to queue
*
*/
void blk_abort_queue(struct request_queue *q)
{
unsigned long flags;
struct request *rq, *tmp;
LIST_HEAD(list);
/*
* Not a request based block device, nothing to abort
*/
if (!q->request_fn)
return;
spin_lock_irqsave(q->queue_lock, flags);
elv_abort_queue(q);
/*
* Splice entries to local list, to avoid deadlocking if entries
* get readded to the timeout list by error handling
*/
list_splice_init(&q->timeout_list, &list);
list_for_each_entry_safe(rq, tmp, &list, timeout_list)
blk_abort_request(rq);
/*
* Occasionally, blk_abort_request() will return without
* deleting the element from the list. Make sure we add those back
* instead of leaving them on the local stack list.
*/
list_splice(&list, &q->timeout_list);
spin_unlock_irqrestore(q->queue_lock, flags);
}
EXPORT_SYMBOL_GPL(blk_abort_queue);
...@@ -17,8 +17,6 @@ ...@@ -17,8 +17,6 @@
#include "blk.h" #include "blk.h"
#include "blk-cgroup.h" #include "blk-cgroup.h"
static struct blkcg_policy blkcg_policy_cfq __maybe_unused;
/* /*
* tunables * tunables
*/ */
...@@ -418,11 +416,6 @@ static inline struct cfq_group *pd_to_cfqg(struct blkg_policy_data *pd) ...@@ -418,11 +416,6 @@ static inline struct cfq_group *pd_to_cfqg(struct blkg_policy_data *pd)
return pd ? container_of(pd, struct cfq_group, pd) : NULL; return pd ? container_of(pd, struct cfq_group, pd) : NULL;
} }
static inline struct cfq_group *blkg_to_cfqg(struct blkcg_gq *blkg)
{
return pd_to_cfqg(blkg_to_pd(blkg, &blkcg_policy_cfq));
}
static inline struct blkcg_gq *cfqg_to_blkg(struct cfq_group *cfqg) static inline struct blkcg_gq *cfqg_to_blkg(struct cfq_group *cfqg)
{ {
return pd_to_blkg(&cfqg->pd); return pd_to_blkg(&cfqg->pd);
...@@ -572,6 +565,13 @@ static inline void cfqg_stats_update_avg_queue_size(struct cfq_group *cfqg) { } ...@@ -572,6 +565,13 @@ static inline void cfqg_stats_update_avg_queue_size(struct cfq_group *cfqg) { }
#ifdef CONFIG_CFQ_GROUP_IOSCHED #ifdef CONFIG_CFQ_GROUP_IOSCHED
static struct blkcg_policy blkcg_policy_cfq;
static inline struct cfq_group *blkg_to_cfqg(struct blkcg_gq *blkg)
{
return pd_to_cfqg(blkg_to_pd(blkg, &blkcg_policy_cfq));
}
static inline void cfqg_get(struct cfq_group *cfqg) static inline void cfqg_get(struct cfq_group *cfqg)
{ {
return blkg_get(cfqg_to_blkg(cfqg)); return blkg_get(cfqg_to_blkg(cfqg));
...@@ -3951,10 +3951,11 @@ static void cfq_exit_queue(struct elevator_queue *e) ...@@ -3951,10 +3951,11 @@ static void cfq_exit_queue(struct elevator_queue *e)
cfq_shutdown_timer_wq(cfqd); cfq_shutdown_timer_wq(cfqd);
#ifndef CONFIG_CFQ_GROUP_IOSCHED #ifdef CONFIG_CFQ_GROUP_IOSCHED
blkcg_deactivate_policy(q, &blkcg_policy_cfq);
#else
kfree(cfqd->root_group); kfree(cfqd->root_group);
#endif #endif
blkcg_deactivate_policy(q, &blkcg_policy_cfq);
kfree(cfqd); kfree(cfqd);
} }
...@@ -4194,14 +4195,15 @@ static int __init cfq_init(void) ...@@ -4194,14 +4195,15 @@ static int __init cfq_init(void)
#ifdef CONFIG_CFQ_GROUP_IOSCHED #ifdef CONFIG_CFQ_GROUP_IOSCHED
if (!cfq_group_idle) if (!cfq_group_idle)
cfq_group_idle = 1; cfq_group_idle = 1;
#else
cfq_group_idle = 0;
#endif
ret = blkcg_policy_register(&blkcg_policy_cfq); ret = blkcg_policy_register(&blkcg_policy_cfq);
if (ret) if (ret)
return ret; return ret;
#else
cfq_group_idle = 0;
#endif
ret = -ENOMEM;
cfq_pool = KMEM_CACHE(cfq_queue, 0); cfq_pool = KMEM_CACHE(cfq_queue, 0);
if (!cfq_pool) if (!cfq_pool)
goto err_pol_unreg; goto err_pol_unreg;
...@@ -4215,13 +4217,17 @@ static int __init cfq_init(void) ...@@ -4215,13 +4217,17 @@ static int __init cfq_init(void)
err_free_pool: err_free_pool:
kmem_cache_destroy(cfq_pool); kmem_cache_destroy(cfq_pool);
err_pol_unreg: err_pol_unreg:
#ifdef CONFIG_CFQ_GROUP_IOSCHED
blkcg_policy_unregister(&blkcg_policy_cfq); blkcg_policy_unregister(&blkcg_policy_cfq);
#endif
return ret; return ret;
} }
static void __exit cfq_exit(void) static void __exit cfq_exit(void)
{ {
#ifdef CONFIG_CFQ_GROUP_IOSCHED
blkcg_policy_unregister(&blkcg_policy_cfq); blkcg_policy_unregister(&blkcg_policy_cfq);
#endif
elv_unregister(&iosched_cfq); elv_unregister(&iosched_cfq);
kmem_cache_destroy(cfq_pool); kmem_cache_destroy(cfq_pool);
} }
......
...@@ -721,11 +721,14 @@ int scsi_verify_blk_ioctl(struct block_device *bd, unsigned int cmd) ...@@ -721,11 +721,14 @@ int scsi_verify_blk_ioctl(struct block_device *bd, unsigned int cmd)
break; break;
} }
if (capable(CAP_SYS_RAWIO))
return 0;
/* In particular, rule out all resets and host-specific ioctls. */ /* In particular, rule out all resets and host-specific ioctls. */
printk_ratelimited(KERN_WARNING printk_ratelimited(KERN_WARNING
"%s: sending ioctl %x to a partition!\n", current->comm, cmd); "%s: sending ioctl %x to a partition!\n", current->comm, cmd);
return capable(CAP_SYS_RAWIO) ? 0 : -ENOIOCTLCMD; return -ENOIOCTLCMD;
} }
EXPORT_SYMBOL(scsi_verify_blk_ioctl); EXPORT_SYMBOL(scsi_verify_blk_ioctl);
......
...@@ -1475,9 +1475,16 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi ...@@ -1475,9 +1475,16 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
first_word = 0; first_word = 0;
spin_lock_irq(&b->bm_lock); spin_lock_irq(&b->bm_lock);
} }
/* last page (respectively only page, for first page == last page) */ /* last page (respectively only page, for first page == last page) */
last_word = MLPP(el >> LN2_BPL); last_word = MLPP(el >> LN2_BPL);
/* consider bitmap->bm_bits = 32768, bitmap->bm_number_of_pages = 1. (or multiples).
* ==> e = 32767, el = 32768, last_page = 2,
* and now last_word = 0.
* We do not want to touch last_page in this case,
* as we did not allocate it, it is not present in bitmap->bm_pages.
*/
if (last_word)
bm_set_full_words_within_one_page(mdev->bitmap, last_page, first_word, last_word); bm_set_full_words_within_one_page(mdev->bitmap, last_page, first_word, last_word);
/* possibly trailing bits. /* possibly trailing bits.
......
...@@ -472,12 +472,17 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, ...@@ -472,12 +472,17 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
req->rq_state |= RQ_LOCAL_COMPLETED; req->rq_state |= RQ_LOCAL_COMPLETED;
req->rq_state &= ~RQ_LOCAL_PENDING; req->rq_state &= ~RQ_LOCAL_PENDING;
D_ASSERT(!(req->rq_state & RQ_NET_MASK)); if (req->rq_state & RQ_LOCAL_ABORTED) {
_req_may_be_done(req, m);
break;
}
__drbd_chk_io_error(mdev, false); __drbd_chk_io_error(mdev, false);
goto_queue_for_net_read: goto_queue_for_net_read:
D_ASSERT(!(req->rq_state & RQ_NET_MASK));
/* no point in retrying if there is no good remote data, /* no point in retrying if there is no good remote data,
* or we have no connection. */ * or we have no connection. */
if (mdev->state.pdsk != D_UP_TO_DATE) { if (mdev->state.pdsk != D_UP_TO_DATE) {
...@@ -765,6 +770,40 @@ static int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int s ...@@ -765,6 +770,40 @@ static int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int s
return 0 == drbd_bm_count_bits(mdev, sbnr, ebnr); return 0 == drbd_bm_count_bits(mdev, sbnr, ebnr);
} }
static void maybe_pull_ahead(struct drbd_conf *mdev)
{
int congested = 0;
/* If I don't even have good local storage, we can not reasonably try
* to pull ahead of the peer. We also need the local reference to make
* sure mdev->act_log is there.
* Note: caller has to make sure that net_conf is there.
*/
if (!get_ldev_if_state(mdev, D_UP_TO_DATE))
return;
if (mdev->net_conf->cong_fill &&
atomic_read(&mdev->ap_in_flight) >= mdev->net_conf->cong_fill) {
dev_info(DEV, "Congestion-fill threshold reached\n");
congested = 1;
}
if (mdev->act_log->used >= mdev->net_conf->cong_extents) {
dev_info(DEV, "Congestion-extents threshold reached\n");
congested = 1;
}
if (congested) {
queue_barrier(mdev); /* last barrier, after mirrored writes */
if (mdev->net_conf->on_congestion == OC_PULL_AHEAD)
_drbd_set_state(_NS(mdev, conn, C_AHEAD), 0, NULL);
else /*mdev->net_conf->on_congestion == OC_DISCONNECT */
_drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), 0, NULL);
}
put_ldev(mdev);
}
static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time) static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time)
{ {
const int rw = bio_rw(bio); const int rw = bio_rw(bio);
...@@ -972,29 +1011,8 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns ...@@ -972,29 +1011,8 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns
_req_mod(req, queue_for_send_oos); _req_mod(req, queue_for_send_oos);
if (remote && if (remote &&
mdev->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96) { mdev->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96)
int congested = 0; maybe_pull_ahead(mdev);
if (mdev->net_conf->cong_fill &&
atomic_read(&mdev->ap_in_flight) >= mdev->net_conf->cong_fill) {
dev_info(DEV, "Congestion-fill threshold reached\n");
congested = 1;
}
if (mdev->act_log->used >= mdev->net_conf->cong_extents) {
dev_info(DEV, "Congestion-extents threshold reached\n");
congested = 1;
}
if (congested) {
queue_barrier(mdev); /* last barrier, after mirrored writes */
if (mdev->net_conf->on_congestion == OC_PULL_AHEAD)
_drbd_set_state(_NS(mdev, conn, C_AHEAD), 0, NULL);
else /*mdev->net_conf->on_congestion == OC_DISCONNECT */
_drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), 0, NULL);
}
}
spin_unlock_irq(&mdev->req_lock); spin_unlock_irq(&mdev->req_lock);
kfree(b); /* if someone else has beaten us to it... */ kfree(b); /* if someone else has beaten us to it... */
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/kthread.h> #include <linux/kthread.h>
#include <../drivers/ata/ahci.h> #include <../drivers/ata/ahci.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/debugfs.h>
#include "mtip32xx.h" #include "mtip32xx.h"
#define HW_CMD_SLOT_SZ (MTIP_MAX_COMMAND_SLOTS * 32) #define HW_CMD_SLOT_SZ (MTIP_MAX_COMMAND_SLOTS * 32)
...@@ -85,6 +86,7 @@ static int instance; ...@@ -85,6 +86,7 @@ static int instance;
* allocated in mtip_init(). * allocated in mtip_init().
*/ */
static int mtip_major; static int mtip_major;
static struct dentry *dfs_parent;
static DEFINE_SPINLOCK(rssd_index_lock); static DEFINE_SPINLOCK(rssd_index_lock);
static DEFINE_IDA(rssd_index_ida); static DEFINE_IDA(rssd_index_ida);
...@@ -2546,7 +2548,7 @@ static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd, ...@@ -2546,7 +2548,7 @@ static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd,
} }
/* /*
* Sysfs register/status dump. * Sysfs status dump.
* *
* @dev Pointer to the device structure, passed by the kernrel. * @dev Pointer to the device structure, passed by the kernrel.
* @attr Pointer to the device_attribute structure passed by the kernel. * @attr Pointer to the device_attribute structure passed by the kernel.
...@@ -2555,45 +2557,68 @@ static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd, ...@@ -2555,45 +2557,68 @@ static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd,
* return value * return value
* The size, in bytes, of the data copied into buf. * The size, in bytes, of the data copied into buf.
*/ */
static ssize_t mtip_hw_show_registers(struct device *dev, static ssize_t mtip_hw_show_status(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
{ {
u32 group_allocated;
struct driver_data *dd = dev_to_disk(dev)->private_data; struct driver_data *dd = dev_to_disk(dev)->private_data;
int size = 0; int size = 0;
if (test_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag))
size += sprintf(buf, "%s", "thermal_shutdown\n");
else if (test_bit(MTIP_DDF_WRITE_PROTECT_BIT, &dd->dd_flag))
size += sprintf(buf, "%s", "write_protect\n");
else
size += sprintf(buf, "%s", "online\n");
return size;
}
static DEVICE_ATTR(status, S_IRUGO, mtip_hw_show_status, NULL);
static ssize_t mtip_hw_read_registers(struct file *f, char __user *ubuf,
size_t len, loff_t *offset)
{
struct driver_data *dd = (struct driver_data *)f->private_data;
char buf[MTIP_DFS_MAX_BUF_SIZE];
u32 group_allocated;
int size = *offset;
int n; int n;
size += sprintf(&buf[size], "Hardware\n--------\n"); if (!len || size)
size += sprintf(&buf[size], "S ACTive : [ 0x"); return 0;
if (size < 0)
return -EINVAL;
size += sprintf(&buf[size], "H/ S ACTive : [ 0x");
for (n = dd->slot_groups-1; n >= 0; n--) for (n = dd->slot_groups-1; n >= 0; n--)
size += sprintf(&buf[size], "%08X ", size += sprintf(&buf[size], "%08X ",
readl(dd->port->s_active[n])); readl(dd->port->s_active[n]));
size += sprintf(&buf[size], "]\n"); size += sprintf(&buf[size], "]\n");
size += sprintf(&buf[size], "Command Issue : [ 0x"); size += sprintf(&buf[size], "H/ Command Issue : [ 0x");
for (n = dd->slot_groups-1; n >= 0; n--) for (n = dd->slot_groups-1; n >= 0; n--)
size += sprintf(&buf[size], "%08X ", size += sprintf(&buf[size], "%08X ",
readl(dd->port->cmd_issue[n])); readl(dd->port->cmd_issue[n]));
size += sprintf(&buf[size], "]\n"); size += sprintf(&buf[size], "]\n");
size += sprintf(&buf[size], "Completed : [ 0x"); size += sprintf(&buf[size], "H/ Completed : [ 0x");
for (n = dd->slot_groups-1; n >= 0; n--) for (n = dd->slot_groups-1; n >= 0; n--)
size += sprintf(&buf[size], "%08X ", size += sprintf(&buf[size], "%08X ",
readl(dd->port->completed[n])); readl(dd->port->completed[n]));
size += sprintf(&buf[size], "]\n"); size += sprintf(&buf[size], "]\n");
size += sprintf(&buf[size], "PORT IRQ STAT : [ 0x%08X ]\n", size += sprintf(&buf[size], "H/ PORT IRQ STAT : [ 0x%08X ]\n",
readl(dd->port->mmio + PORT_IRQ_STAT)); readl(dd->port->mmio + PORT_IRQ_STAT));
size += sprintf(&buf[size], "HOST IRQ STAT : [ 0x%08X ]\n", size += sprintf(&buf[size], "H/ HOST IRQ STAT : [ 0x%08X ]\n",
readl(dd->mmio + HOST_IRQ_STAT)); readl(dd->mmio + HOST_IRQ_STAT));
size += sprintf(&buf[size], "\n"); size += sprintf(&buf[size], "\n");
size += sprintf(&buf[size], "Local\n-----\n"); size += sprintf(&buf[size], "L/ Allocated : [ 0x");
size += sprintf(&buf[size], "Allocated : [ 0x");
for (n = dd->slot_groups-1; n >= 0; n--) { for (n = dd->slot_groups-1; n >= 0; n--) {
if (sizeof(long) > sizeof(u32)) if (sizeof(long) > sizeof(u32))
...@@ -2605,7 +2630,7 @@ static ssize_t mtip_hw_show_registers(struct device *dev, ...@@ -2605,7 +2630,7 @@ static ssize_t mtip_hw_show_registers(struct device *dev,
} }
size += sprintf(&buf[size], "]\n"); size += sprintf(&buf[size], "]\n");
size += sprintf(&buf[size], "Commands in Q: [ 0x"); size += sprintf(&buf[size], "L/ Commands in Q : [ 0x");
for (n = dd->slot_groups-1; n >= 0; n--) { for (n = dd->slot_groups-1; n >= 0; n--) {
if (sizeof(long) > sizeof(u32)) if (sizeof(long) > sizeof(u32))
...@@ -2617,44 +2642,53 @@ static ssize_t mtip_hw_show_registers(struct device *dev, ...@@ -2617,44 +2642,53 @@ static ssize_t mtip_hw_show_registers(struct device *dev,
} }
size += sprintf(&buf[size], "]\n"); size += sprintf(&buf[size], "]\n");
return size; *offset = size <= len ? size : len;
size = copy_to_user(ubuf, buf, *offset);
if (size)
return -EFAULT;
return *offset;
} }
static ssize_t mtip_hw_show_status(struct device *dev, static ssize_t mtip_hw_read_flags(struct file *f, char __user *ubuf,
struct device_attribute *attr, size_t len, loff_t *offset)
char *buf)
{ {
struct driver_data *dd = dev_to_disk(dev)->private_data; struct driver_data *dd = (struct driver_data *)f->private_data;
int size = 0; char buf[MTIP_DFS_MAX_BUF_SIZE];
int size = *offset;
if (test_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag)) if (!len || size)
size += sprintf(buf, "%s", "thermal_shutdown\n"); return 0;
else if (test_bit(MTIP_DDF_WRITE_PROTECT_BIT, &dd->dd_flag))
size += sprintf(buf, "%s", "write_protect\n");
else
size += sprintf(buf, "%s", "online\n");
return size;
}
static ssize_t mtip_hw_show_flags(struct device *dev, if (size < 0)
struct device_attribute *attr, return -EINVAL;
char *buf)
{
struct driver_data *dd = dev_to_disk(dev)->private_data;
int size = 0;
size += sprintf(&buf[size], "Flag in port struct : [ %08lX ]\n", size += sprintf(&buf[size], "Flag-port : [ %08lX ]\n",
dd->port->flags); dd->port->flags);
size += sprintf(&buf[size], "Flag in dd struct : [ %08lX ]\n", size += sprintf(&buf[size], "Flag-dd : [ %08lX ]\n",
dd->dd_flag); dd->dd_flag);
return size; *offset = size <= len ? size : len;
size = copy_to_user(ubuf, buf, *offset);
if (size)
return -EFAULT;
return *offset;
} }
static DEVICE_ATTR(registers, S_IRUGO, mtip_hw_show_registers, NULL); static const struct file_operations mtip_regs_fops = {
static DEVICE_ATTR(status, S_IRUGO, mtip_hw_show_status, NULL); .owner = THIS_MODULE,
static DEVICE_ATTR(flags, S_IRUGO, mtip_hw_show_flags, NULL); .open = simple_open,
.read = mtip_hw_read_registers,
.llseek = no_llseek,
};
static const struct file_operations mtip_flags_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = mtip_hw_read_flags,
.llseek = no_llseek,
};
/* /*
* Create the sysfs related attributes. * Create the sysfs related attributes.
...@@ -2671,15 +2705,9 @@ static int mtip_hw_sysfs_init(struct driver_data *dd, struct kobject *kobj) ...@@ -2671,15 +2705,9 @@ static int mtip_hw_sysfs_init(struct driver_data *dd, struct kobject *kobj)
if (!kobj || !dd) if (!kobj || !dd)
return -EINVAL; return -EINVAL;
if (sysfs_create_file(kobj, &dev_attr_registers.attr))
dev_warn(&dd->pdev->dev,
"Error creating 'registers' sysfs entry\n");
if (sysfs_create_file(kobj, &dev_attr_status.attr)) if (sysfs_create_file(kobj, &dev_attr_status.attr))
dev_warn(&dd->pdev->dev, dev_warn(&dd->pdev->dev,
"Error creating 'status' sysfs entry\n"); "Error creating 'status' sysfs entry\n");
if (sysfs_create_file(kobj, &dev_attr_flags.attr))
dev_warn(&dd->pdev->dev,
"Error creating 'flags' sysfs entry\n");
return 0; return 0;
} }
...@@ -2698,13 +2726,39 @@ static int mtip_hw_sysfs_exit(struct driver_data *dd, struct kobject *kobj) ...@@ -2698,13 +2726,39 @@ static int mtip_hw_sysfs_exit(struct driver_data *dd, struct kobject *kobj)
if (!kobj || !dd) if (!kobj || !dd)
return -EINVAL; return -EINVAL;
sysfs_remove_file(kobj, &dev_attr_registers.attr);
sysfs_remove_file(kobj, &dev_attr_status.attr); sysfs_remove_file(kobj, &dev_attr_status.attr);
sysfs_remove_file(kobj, &dev_attr_flags.attr);
return 0; return 0;
} }
static int mtip_hw_debugfs_init(struct driver_data *dd)
{
if (!dfs_parent)
return -1;
dd->dfs_node = debugfs_create_dir(dd->disk->disk_name, dfs_parent);
if (IS_ERR_OR_NULL(dd->dfs_node)) {
dev_warn(&dd->pdev->dev,
"Error creating node %s under debugfs\n",
dd->disk->disk_name);
dd->dfs_node = NULL;
return -1;
}
debugfs_create_file("flags", S_IRUGO, dd->dfs_node, dd,
&mtip_flags_fops);
debugfs_create_file("registers", S_IRUGO, dd->dfs_node, dd,
&mtip_regs_fops);
return 0;
}
static void mtip_hw_debugfs_exit(struct driver_data *dd)
{
debugfs_remove_recursive(dd->dfs_node);
}
/* /*
* Perform any init/resume time hardware setup * Perform any init/resume time hardware setup
* *
...@@ -3730,6 +3784,7 @@ static int mtip_block_initialize(struct driver_data *dd) ...@@ -3730,6 +3784,7 @@ static int mtip_block_initialize(struct driver_data *dd)
mtip_hw_sysfs_init(dd, kobj); mtip_hw_sysfs_init(dd, kobj);
kobject_put(kobj); kobject_put(kobj);
} }
mtip_hw_debugfs_init(dd);
if (dd->mtip_svc_handler) { if (dd->mtip_svc_handler) {
set_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag); set_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag);
...@@ -3755,6 +3810,8 @@ static int mtip_block_initialize(struct driver_data *dd) ...@@ -3755,6 +3810,8 @@ static int mtip_block_initialize(struct driver_data *dd)
return rv; return rv;
kthread_run_error: kthread_run_error:
mtip_hw_debugfs_exit(dd);
/* Delete our gendisk. This also removes the device from /dev */ /* Delete our gendisk. This also removes the device from /dev */
del_gendisk(dd->disk); del_gendisk(dd->disk);
...@@ -3805,6 +3862,7 @@ static int mtip_block_remove(struct driver_data *dd) ...@@ -3805,6 +3862,7 @@ static int mtip_block_remove(struct driver_data *dd)
kobject_put(kobj); kobject_put(kobj);
} }
} }
mtip_hw_debugfs_exit(dd);
/* /*
* Delete our gendisk structure. This also removes the device * Delete our gendisk structure. This also removes the device
...@@ -4152,10 +4210,20 @@ static int __init mtip_init(void) ...@@ -4152,10 +4210,20 @@ static int __init mtip_init(void)
} }
mtip_major = error; mtip_major = error;
if (!dfs_parent) {
dfs_parent = debugfs_create_dir("rssd", NULL);
if (IS_ERR_OR_NULL(dfs_parent)) {
printk(KERN_WARNING "Error creating debugfs parent\n");
dfs_parent = NULL;
}
}
/* Register our PCI operations. */ /* Register our PCI operations. */
error = pci_register_driver(&mtip_pci_driver); error = pci_register_driver(&mtip_pci_driver);
if (error) if (error) {
debugfs_remove(dfs_parent);
unregister_blkdev(mtip_major, MTIP_DRV_NAME); unregister_blkdev(mtip_major, MTIP_DRV_NAME);
}
return error; return error;
} }
...@@ -4172,6 +4240,8 @@ static int __init mtip_init(void) ...@@ -4172,6 +4240,8 @@ static int __init mtip_init(void)
*/ */
static void __exit mtip_exit(void) static void __exit mtip_exit(void)
{ {
debugfs_remove_recursive(dfs_parent);
/* Release the allocated major block device number. */ /* Release the allocated major block device number. */
unregister_blkdev(mtip_major, MTIP_DRV_NAME); unregister_blkdev(mtip_major, MTIP_DRV_NAME);
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include <linux/ata.h> #include <linux/ata.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/genhd.h> #include <linux/genhd.h>
#include <linux/version.h>
/* Offset of Subsystem Device ID in pci confoguration space */ /* Offset of Subsystem Device ID in pci confoguration space */
#define PCI_SUBSYSTEM_DEVICEID 0x2E #define PCI_SUBSYSTEM_DEVICEID 0x2E
...@@ -111,6 +110,8 @@ ...@@ -111,6 +110,8 @@
#define dbg_printk(format, arg...) #define dbg_printk(format, arg...)
#endif #endif
#define MTIP_DFS_MAX_BUF_SIZE 1024
#define __force_bit2int (unsigned int __force) #define __force_bit2int (unsigned int __force)
enum { enum {
...@@ -447,6 +448,8 @@ struct driver_data { ...@@ -447,6 +448,8 @@ struct driver_data {
unsigned long dd_flag; /* NOTE: use atomic bit operations on this */ unsigned long dd_flag; /* NOTE: use atomic bit operations on this */
struct task_struct *mtip_svc_handler; /* task_struct of svc thd */ struct task_struct *mtip_svc_handler; /* task_struct of svc thd */
struct dentry *dfs_node;
}; };
#endif #endif
...@@ -513,6 +513,44 @@ static void process_page(unsigned long data) ...@@ -513,6 +513,44 @@ static void process_page(unsigned long data)
} }
} }
struct mm_plug_cb {
struct blk_plug_cb cb;
struct cardinfo *card;
};
static void mm_unplug(struct blk_plug_cb *cb)
{
struct mm_plug_cb *mmcb = container_of(cb, struct mm_plug_cb, cb);
spin_lock_irq(&mmcb->card->lock);
activate(mmcb->card);
spin_unlock_irq(&mmcb->card->lock);
kfree(mmcb);
}
static int mm_check_plugged(struct cardinfo *card)
{
struct blk_plug *plug = current->plug;
struct mm_plug_cb *mmcb;
if (!plug)
return 0;
list_for_each_entry(mmcb, &plug->cb_list, cb.list) {
if (mmcb->cb.callback == mm_unplug && mmcb->card == card)
return 1;
}
/* Not currently on the callback list */
mmcb = kmalloc(sizeof(*mmcb), GFP_ATOMIC);
if (!mmcb)
return 0;
mmcb->card = card;
mmcb->cb.callback = mm_unplug;
list_add(&mmcb->cb.list, &plug->cb_list);
return 1;
}
static void mm_make_request(struct request_queue *q, struct bio *bio) static void mm_make_request(struct request_queue *q, struct bio *bio)
{ {
struct cardinfo *card = q->queuedata; struct cardinfo *card = q->queuedata;
...@@ -523,6 +561,8 @@ static void mm_make_request(struct request_queue *q, struct bio *bio) ...@@ -523,6 +561,8 @@ static void mm_make_request(struct request_queue *q, struct bio *bio)
*card->biotail = bio; *card->biotail = bio;
bio->bi_next = NULL; bio->bi_next = NULL;
card->biotail = &bio->bi_next; card->biotail = &bio->bi_next;
if (bio->bi_rw & REQ_SYNC || !mm_check_plugged(card))
activate(card);
spin_unlock_irq(&card->lock); spin_unlock_irq(&card->lock);
return; return;
......
...@@ -257,6 +257,7 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst, ...@@ -257,6 +257,7 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst,
break; break;
case BLKIF_OP_DISCARD: case BLKIF_OP_DISCARD:
dst->u.discard.flag = src->u.discard.flag; dst->u.discard.flag = src->u.discard.flag;
dst->u.discard.id = src->u.discard.id;
dst->u.discard.sector_number = src->u.discard.sector_number; dst->u.discard.sector_number = src->u.discard.sector_number;
dst->u.discard.nr_sectors = src->u.discard.nr_sectors; dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
break; break;
...@@ -287,6 +288,7 @@ static inline void blkif_get_x86_64_req(struct blkif_request *dst, ...@@ -287,6 +288,7 @@ static inline void blkif_get_x86_64_req(struct blkif_request *dst,
break; break;
case BLKIF_OP_DISCARD: case BLKIF_OP_DISCARD:
dst->u.discard.flag = src->u.discard.flag; dst->u.discard.flag = src->u.discard.flag;
dst->u.discard.id = src->u.discard.id;
dst->u.discard.sector_number = src->u.discard.sector_number; dst->u.discard.sector_number = src->u.discard.sector_number;
dst->u.discard.nr_sectors = src->u.discard.nr_sectors; dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
break; break;
......
...@@ -141,14 +141,36 @@ static int get_id_from_freelist(struct blkfront_info *info) ...@@ -141,14 +141,36 @@ static int get_id_from_freelist(struct blkfront_info *info)
return free; return free;
} }
static void add_id_to_freelist(struct blkfront_info *info, static int add_id_to_freelist(struct blkfront_info *info,
unsigned long id) unsigned long id)
{ {
if (info->shadow[id].req.u.rw.id != id)
return -EINVAL;
if (info->shadow[id].request == NULL)
return -EINVAL;
info->shadow[id].req.u.rw.id = info->shadow_free; info->shadow[id].req.u.rw.id = info->shadow_free;
info->shadow[id].request = NULL; info->shadow[id].request = NULL;
info->shadow_free = id; info->shadow_free = id;
return 0;
} }
static const char *op_name(int op)
{
static const char *const names[] = {
[BLKIF_OP_READ] = "read",
[BLKIF_OP_WRITE] = "write",
[BLKIF_OP_WRITE_BARRIER] = "barrier",
[BLKIF_OP_FLUSH_DISKCACHE] = "flush",
[BLKIF_OP_DISCARD] = "discard" };
if (op < 0 || op >= ARRAY_SIZE(names))
return "unknown";
if (!names[op])
return "reserved";
return names[op];
}
static int xlbd_reserve_minors(unsigned int minor, unsigned int nr) static int xlbd_reserve_minors(unsigned int minor, unsigned int nr)
{ {
unsigned int end = minor + nr; unsigned int end = minor + nr;
...@@ -746,20 +768,36 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) ...@@ -746,20 +768,36 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
bret = RING_GET_RESPONSE(&info->ring, i); bret = RING_GET_RESPONSE(&info->ring, i);
id = bret->id; id = bret->id;
/*
* The backend has messed up and given us an id that we would
* never have given to it (we stamp it up to BLK_RING_SIZE -
* look in get_id_from_freelist.
*/
if (id >= BLK_RING_SIZE) {
WARN(1, "%s: response to %s has incorrect id (%ld)\n",
info->gd->disk_name, op_name(bret->operation), id);
/* We can't safely get the 'struct request' as
* the id is busted. */
continue;
}
req = info->shadow[id].request; req = info->shadow[id].request;
if (bret->operation != BLKIF_OP_DISCARD) if (bret->operation != BLKIF_OP_DISCARD)
blkif_completion(&info->shadow[id]); blkif_completion(&info->shadow[id]);
add_id_to_freelist(info, id); if (add_id_to_freelist(info, id)) {
WARN(1, "%s: response to %s (id %ld) couldn't be recycled!\n",
info->gd->disk_name, op_name(bret->operation), id);
continue;
}
error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO; error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO;
switch (bret->operation) { switch (bret->operation) {
case BLKIF_OP_DISCARD: case BLKIF_OP_DISCARD:
if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
struct request_queue *rq = info->rq; struct request_queue *rq = info->rq;
printk(KERN_WARNING "blkfront: %s: discard op failed\n", printk(KERN_WARNING "blkfront: %s: %s op failed\n",
info->gd->disk_name); info->gd->disk_name, op_name(bret->operation));
error = -EOPNOTSUPP; error = -EOPNOTSUPP;
info->feature_discard = 0; info->feature_discard = 0;
info->feature_secdiscard = 0; info->feature_secdiscard = 0;
...@@ -771,18 +809,14 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) ...@@ -771,18 +809,14 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
case BLKIF_OP_FLUSH_DISKCACHE: case BLKIF_OP_FLUSH_DISKCACHE:
case BLKIF_OP_WRITE_BARRIER: case BLKIF_OP_WRITE_BARRIER:
if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
printk(KERN_WARNING "blkfront: %s: write %s op failed\n", printk(KERN_WARNING "blkfront: %s: %s op failed\n",
info->flush_op == BLKIF_OP_WRITE_BARRIER ? info->gd->disk_name, op_name(bret->operation));
"barrier" : "flush disk cache",
info->gd->disk_name);
error = -EOPNOTSUPP; error = -EOPNOTSUPP;
} }
if (unlikely(bret->status == BLKIF_RSP_ERROR && if (unlikely(bret->status == BLKIF_RSP_ERROR &&
info->shadow[id].req.u.rw.nr_segments == 0)) { info->shadow[id].req.u.rw.nr_segments == 0)) {
printk(KERN_WARNING "blkfront: %s: empty write %s op failed\n", printk(KERN_WARNING "blkfront: %s: empty %s op failed\n",
info->flush_op == BLKIF_OP_WRITE_BARRIER ? info->gd->disk_name, op_name(bret->operation));
"barrier" : "flush disk cache",
info->gd->disk_name);
error = -EOPNOTSUPP; error = -EOPNOTSUPP;
} }
if (unlikely(error)) { if (unlikely(error)) {
......
...@@ -273,13 +273,16 @@ void spd_release_page(struct splice_pipe_desc *spd, unsigned int i) ...@@ -273,13 +273,16 @@ void spd_release_page(struct splice_pipe_desc *spd, unsigned int i)
* Check if we need to grow the arrays holding pages and partial page * Check if we need to grow the arrays holding pages and partial page
* descriptions. * descriptions.
*/ */
int splice_grow_spd(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd) int splice_grow_spd(const struct pipe_inode_info *pipe, struct splice_pipe_desc *spd)
{ {
if (pipe->buffers <= PIPE_DEF_BUFFERS) unsigned int buffers = ACCESS_ONCE(pipe->buffers);
spd->nr_pages_max = buffers;
if (buffers <= PIPE_DEF_BUFFERS)
return 0; return 0;
spd->pages = kmalloc(pipe->buffers * sizeof(struct page *), GFP_KERNEL); spd->pages = kmalloc(buffers * sizeof(struct page *), GFP_KERNEL);
spd->partial = kmalloc(pipe->buffers * sizeof(struct partial_page), GFP_KERNEL); spd->partial = kmalloc(buffers * sizeof(struct partial_page), GFP_KERNEL);
if (spd->pages && spd->partial) if (spd->pages && spd->partial)
return 0; return 0;
...@@ -289,10 +292,9 @@ int splice_grow_spd(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd) ...@@ -289,10 +292,9 @@ int splice_grow_spd(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd)
return -ENOMEM; return -ENOMEM;
} }
void splice_shrink_spd(struct pipe_inode_info *pipe, void splice_shrink_spd(struct splice_pipe_desc *spd)
struct splice_pipe_desc *spd)
{ {
if (pipe->buffers <= PIPE_DEF_BUFFERS) if (spd->nr_pages_max <= PIPE_DEF_BUFFERS)
return; return;
kfree(spd->pages); kfree(spd->pages);
...@@ -315,6 +317,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, ...@@ -315,6 +317,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
struct splice_pipe_desc spd = { struct splice_pipe_desc spd = {
.pages = pages, .pages = pages,
.partial = partial, .partial = partial,
.nr_pages_max = PIPE_DEF_BUFFERS,
.flags = flags, .flags = flags,
.ops = &page_cache_pipe_buf_ops, .ops = &page_cache_pipe_buf_ops,
.spd_release = spd_release_page, .spd_release = spd_release_page,
...@@ -326,7 +329,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, ...@@ -326,7 +329,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
index = *ppos >> PAGE_CACHE_SHIFT; index = *ppos >> PAGE_CACHE_SHIFT;
loff = *ppos & ~PAGE_CACHE_MASK; loff = *ppos & ~PAGE_CACHE_MASK;
req_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; req_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
nr_pages = min(req_pages, pipe->buffers); nr_pages = min(req_pages, spd.nr_pages_max);
/* /*
* Lookup the (hopefully) full range of pages we need. * Lookup the (hopefully) full range of pages we need.
...@@ -497,7 +500,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, ...@@ -497,7 +500,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
if (spd.nr_pages) if (spd.nr_pages)
error = splice_to_pipe(pipe, &spd); error = splice_to_pipe(pipe, &spd);
splice_shrink_spd(pipe, &spd); splice_shrink_spd(&spd);
return error; return error;
} }
...@@ -598,6 +601,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, ...@@ -598,6 +601,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
struct splice_pipe_desc spd = { struct splice_pipe_desc spd = {
.pages = pages, .pages = pages,
.partial = partial, .partial = partial,
.nr_pages_max = PIPE_DEF_BUFFERS,
.flags = flags, .flags = flags,
.ops = &default_pipe_buf_ops, .ops = &default_pipe_buf_ops,
.spd_release = spd_release_page, .spd_release = spd_release_page,
...@@ -608,8 +612,8 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, ...@@ -608,8 +612,8 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
res = -ENOMEM; res = -ENOMEM;
vec = __vec; vec = __vec;
if (pipe->buffers > PIPE_DEF_BUFFERS) { if (spd.nr_pages_max > PIPE_DEF_BUFFERS) {
vec = kmalloc(pipe->buffers * sizeof(struct iovec), GFP_KERNEL); vec = kmalloc(spd.nr_pages_max * sizeof(struct iovec), GFP_KERNEL);
if (!vec) if (!vec)
goto shrink_ret; goto shrink_ret;
} }
...@@ -617,7 +621,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, ...@@ -617,7 +621,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
offset = *ppos & ~PAGE_CACHE_MASK; offset = *ppos & ~PAGE_CACHE_MASK;
nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
for (i = 0; i < nr_pages && i < pipe->buffers && len; i++) { for (i = 0; i < nr_pages && i < spd.nr_pages_max && len; i++) {
struct page *page; struct page *page;
page = alloc_page(GFP_USER); page = alloc_page(GFP_USER);
...@@ -665,7 +669,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, ...@@ -665,7 +669,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
shrink_ret: shrink_ret:
if (vec != __vec) if (vec != __vec)
kfree(vec); kfree(vec);
splice_shrink_spd(pipe, &spd); splice_shrink_spd(&spd);
return res; return res;
err: err:
...@@ -1614,6 +1618,7 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov, ...@@ -1614,6 +1618,7 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov,
struct splice_pipe_desc spd = { struct splice_pipe_desc spd = {
.pages = pages, .pages = pages,
.partial = partial, .partial = partial,
.nr_pages_max = PIPE_DEF_BUFFERS,
.flags = flags, .flags = flags,
.ops = &user_page_pipe_buf_ops, .ops = &user_page_pipe_buf_ops,
.spd_release = spd_release_page, .spd_release = spd_release_page,
...@@ -1629,13 +1634,13 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov, ...@@ -1629,13 +1634,13 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov,
spd.nr_pages = get_iovec_page_array(iov, nr_segs, spd.pages, spd.nr_pages = get_iovec_page_array(iov, nr_segs, spd.pages,
spd.partial, false, spd.partial, false,
pipe->buffers); spd.nr_pages_max);
if (spd.nr_pages <= 0) if (spd.nr_pages <= 0)
ret = spd.nr_pages; ret = spd.nr_pages;
else else
ret = splice_to_pipe(pipe, &spd); ret = splice_to_pipe(pipe, &spd);
splice_shrink_spd(pipe, &spd); splice_shrink_spd(&spd);
return ret; return ret;
} }
......
...@@ -827,7 +827,6 @@ extern bool __blk_end_request_err(struct request *rq, int error); ...@@ -827,7 +827,6 @@ extern bool __blk_end_request_err(struct request *rq, int error);
extern void blk_complete_request(struct request *); extern void blk_complete_request(struct request *);
extern void __blk_complete_request(struct request *); extern void __blk_complete_request(struct request *);
extern void blk_abort_request(struct request *); extern void blk_abort_request(struct request *);
extern void blk_abort_queue(struct request_queue *);
extern void blk_unprep_request(struct request *); extern void blk_unprep_request(struct request *);
/* /*
......
...@@ -51,7 +51,8 @@ struct partial_page { ...@@ -51,7 +51,8 @@ struct partial_page {
struct splice_pipe_desc { struct splice_pipe_desc {
struct page **pages; /* page map */ struct page **pages; /* page map */
struct partial_page *partial; /* pages[] may not be contig */ struct partial_page *partial; /* pages[] may not be contig */
int nr_pages; /* number of pages in map */ int nr_pages; /* number of populated pages in map */
unsigned int nr_pages_max; /* pages[] & partial[] arrays size */
unsigned int flags; /* splice flags */ unsigned int flags; /* splice flags */
const struct pipe_buf_operations *ops;/* ops associated with output pipe */ const struct pipe_buf_operations *ops;/* ops associated with output pipe */
void (*spd_release)(struct splice_pipe_desc *, unsigned int); void (*spd_release)(struct splice_pipe_desc *, unsigned int);
...@@ -85,9 +86,8 @@ extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *, ...@@ -85,9 +86,8 @@ extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *,
/* /*
* for dynamic pipe sizing * for dynamic pipe sizing
*/ */
extern int splice_grow_spd(struct pipe_inode_info *, struct splice_pipe_desc *); extern int splice_grow_spd(const struct pipe_inode_info *, struct splice_pipe_desc *);
extern void splice_shrink_spd(struct pipe_inode_info *, extern void splice_shrink_spd(struct splice_pipe_desc *);
struct splice_pipe_desc *);
extern void spd_release_page(struct splice_pipe_desc *, unsigned int); extern void spd_release_page(struct splice_pipe_desc *, unsigned int);
extern const struct pipe_buf_operations page_cache_pipe_buf_ops; extern const struct pipe_buf_operations page_cache_pipe_buf_ops;
......
...@@ -1235,6 +1235,7 @@ static ssize_t subbuf_splice_actor(struct file *in, ...@@ -1235,6 +1235,7 @@ static ssize_t subbuf_splice_actor(struct file *in,
struct splice_pipe_desc spd = { struct splice_pipe_desc spd = {
.pages = pages, .pages = pages,
.nr_pages = 0, .nr_pages = 0,
.nr_pages_max = PIPE_DEF_BUFFERS,
.partial = partial, .partial = partial,
.flags = flags, .flags = flags,
.ops = &relay_pipe_buf_ops, .ops = &relay_pipe_buf_ops,
...@@ -1302,7 +1303,7 @@ static ssize_t subbuf_splice_actor(struct file *in, ...@@ -1302,7 +1303,7 @@ static ssize_t subbuf_splice_actor(struct file *in,
ret += padding; ret += padding;
out: out:
splice_shrink_spd(pipe, &spd); splice_shrink_spd(&spd);
return ret; return ret;
} }
......
...@@ -3609,6 +3609,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp, ...@@ -3609,6 +3609,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
.pages = pages_def, .pages = pages_def,
.partial = partial_def, .partial = partial_def,
.nr_pages = 0, /* This gets updated below. */ .nr_pages = 0, /* This gets updated below. */
.nr_pages_max = PIPE_DEF_BUFFERS,
.flags = flags, .flags = flags,
.ops = &tracing_pipe_buf_ops, .ops = &tracing_pipe_buf_ops,
.spd_release = tracing_spd_release_pipe, .spd_release = tracing_spd_release_pipe,
...@@ -3680,7 +3681,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp, ...@@ -3680,7 +3681,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
ret = splice_to_pipe(pipe, &spd); ret = splice_to_pipe(pipe, &spd);
out: out:
splice_shrink_spd(pipe, &spd); splice_shrink_spd(&spd);
return ret; return ret;
out_err: out_err:
...@@ -4231,6 +4232,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, ...@@ -4231,6 +4232,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
struct splice_pipe_desc spd = { struct splice_pipe_desc spd = {
.pages = pages_def, .pages = pages_def,
.partial = partial_def, .partial = partial_def,
.nr_pages_max = PIPE_DEF_BUFFERS,
.flags = flags, .flags = flags,
.ops = &buffer_pipe_buf_ops, .ops = &buffer_pipe_buf_ops,
.spd_release = buffer_spd_release, .spd_release = buffer_spd_release,
...@@ -4318,7 +4320,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, ...@@ -4318,7 +4320,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
} }
ret = splice_to_pipe(pipe, &spd); ret = splice_to_pipe(pipe, &spd);
splice_shrink_spd(pipe, &spd); splice_shrink_spd(&spd);
out: out:
return ret; return ret;
} }
......
...@@ -1594,6 +1594,7 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos, ...@@ -1594,6 +1594,7 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos,
struct splice_pipe_desc spd = { struct splice_pipe_desc spd = {
.pages = pages, .pages = pages,
.partial = partial, .partial = partial,
.nr_pages_max = PIPE_DEF_BUFFERS,
.flags = flags, .flags = flags,
.ops = &page_cache_pipe_buf_ops, .ops = &page_cache_pipe_buf_ops,
.spd_release = spd_release_page, .spd_release = spd_release_page,
...@@ -1682,7 +1683,7 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos, ...@@ -1682,7 +1683,7 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos,
if (spd.nr_pages) if (spd.nr_pages)
error = splice_to_pipe(pipe, &spd); error = splice_to_pipe(pipe, &spd);
splice_shrink_spd(pipe, &spd); splice_shrink_spd(&spd);
if (error > 0) { if (error > 0) {
*ppos += error; *ppos += error;
......
...@@ -1755,6 +1755,7 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset, ...@@ -1755,6 +1755,7 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
struct splice_pipe_desc spd = { struct splice_pipe_desc spd = {
.pages = pages, .pages = pages,
.partial = partial, .partial = partial,
.nr_pages_max = MAX_SKB_FRAGS,
.flags = flags, .flags = flags,
.ops = &sock_pipe_buf_ops, .ops = &sock_pipe_buf_ops,
.spd_release = sock_spd_release, .spd_release = sock_spd_release,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment