Merge branch 'stable/for-jens-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip into for-3.16/drivers
Konrad writes: Please git pull the following branch: git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip.git stable/for-jens-3.16 which has a bunch of fixes to the Xen block frontend and backend driver and a new parameter for Xen backend driver - an override (set by the toolstack) whether to expose the discard support (if disk of course supports it) or not.
This commit is contained in:
commit
879466e6a5
|
@ -314,7 +314,7 @@ struct xen_blkif {
|
||||||
unsigned long long st_rd_sect;
|
unsigned long long st_rd_sect;
|
||||||
unsigned long long st_wr_sect;
|
unsigned long long st_wr_sect;
|
||||||
|
|
||||||
wait_queue_head_t waiting_to_free;
|
struct work_struct free_work;
|
||||||
/* Thread shutdown wait queue. */
|
/* Thread shutdown wait queue. */
|
||||||
wait_queue_head_t shutdown_wq;
|
wait_queue_head_t shutdown_wq;
|
||||||
};
|
};
|
||||||
|
@ -361,7 +361,7 @@ struct pending_req {
|
||||||
#define xen_blkif_put(_b) \
|
#define xen_blkif_put(_b) \
|
||||||
do { \
|
do { \
|
||||||
if (atomic_dec_and_test(&(_b)->refcnt)) \
|
if (atomic_dec_and_test(&(_b)->refcnt)) \
|
||||||
wake_up(&(_b)->waiting_to_free);\
|
schedule_work(&(_b)->free_work);\
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
struct phys_req {
|
struct phys_req {
|
||||||
|
|
|
@ -35,12 +35,26 @@ static void connect(struct backend_info *);
|
||||||
static int connect_ring(struct backend_info *);
|
static int connect_ring(struct backend_info *);
|
||||||
static void backend_changed(struct xenbus_watch *, const char **,
|
static void backend_changed(struct xenbus_watch *, const char **,
|
||||||
unsigned int);
|
unsigned int);
|
||||||
|
static void xen_blkif_free(struct xen_blkif *blkif);
|
||||||
|
static void xen_vbd_free(struct xen_vbd *vbd);
|
||||||
|
|
||||||
struct xenbus_device *xen_blkbk_xenbus(struct backend_info *be)
|
struct xenbus_device *xen_blkbk_xenbus(struct backend_info *be)
|
||||||
{
|
{
|
||||||
return be->dev;
|
return be->dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The last request could free the device from softirq context and
|
||||||
|
* xen_blkif_free() can sleep.
|
||||||
|
*/
|
||||||
|
static void xen_blkif_deferred_free(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct xen_blkif *blkif;
|
||||||
|
|
||||||
|
blkif = container_of(work, struct xen_blkif, free_work);
|
||||||
|
xen_blkif_free(blkif);
|
||||||
|
}
|
||||||
|
|
||||||
static int blkback_name(struct xen_blkif *blkif, char *buf)
|
static int blkback_name(struct xen_blkif *blkif, char *buf)
|
||||||
{
|
{
|
||||||
char *devpath, *devname;
|
char *devpath, *devname;
|
||||||
|
@ -121,7 +135,6 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid)
|
||||||
init_completion(&blkif->drain_complete);
|
init_completion(&blkif->drain_complete);
|
||||||
atomic_set(&blkif->drain, 0);
|
atomic_set(&blkif->drain, 0);
|
||||||
blkif->st_print = jiffies;
|
blkif->st_print = jiffies;
|
||||||
init_waitqueue_head(&blkif->waiting_to_free);
|
|
||||||
blkif->persistent_gnts.rb_node = NULL;
|
blkif->persistent_gnts.rb_node = NULL;
|
||||||
spin_lock_init(&blkif->free_pages_lock);
|
spin_lock_init(&blkif->free_pages_lock);
|
||||||
INIT_LIST_HEAD(&blkif->free_pages);
|
INIT_LIST_HEAD(&blkif->free_pages);
|
||||||
|
@ -132,6 +145,7 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid)
|
||||||
INIT_WORK(&blkif->persistent_purge_work, xen_blkbk_unmap_purged_grants);
|
INIT_WORK(&blkif->persistent_purge_work, xen_blkbk_unmap_purged_grants);
|
||||||
|
|
||||||
INIT_LIST_HEAD(&blkif->pending_free);
|
INIT_LIST_HEAD(&blkif->pending_free);
|
||||||
|
INIT_WORK(&blkif->free_work, xen_blkif_deferred_free);
|
||||||
|
|
||||||
for (i = 0; i < XEN_BLKIF_REQS; i++) {
|
for (i = 0; i < XEN_BLKIF_REQS; i++) {
|
||||||
req = kzalloc(sizeof(*req), GFP_KERNEL);
|
req = kzalloc(sizeof(*req), GFP_KERNEL);
|
||||||
|
@ -231,7 +245,7 @@ static int xen_blkif_map(struct xen_blkif *blkif, unsigned long shared_page,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xen_blkif_disconnect(struct xen_blkif *blkif)
|
static int xen_blkif_disconnect(struct xen_blkif *blkif)
|
||||||
{
|
{
|
||||||
if (blkif->xenblkd) {
|
if (blkif->xenblkd) {
|
||||||
kthread_stop(blkif->xenblkd);
|
kthread_stop(blkif->xenblkd);
|
||||||
|
@ -239,9 +253,12 @@ static void xen_blkif_disconnect(struct xen_blkif *blkif)
|
||||||
blkif->xenblkd = NULL;
|
blkif->xenblkd = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_dec(&blkif->refcnt);
|
/* The above kthread_stop() guarantees that at this point we
|
||||||
wait_event(blkif->waiting_to_free, atomic_read(&blkif->refcnt) == 0);
|
* don't have any discard_io or other_io requests. So, checking
|
||||||
atomic_inc(&blkif->refcnt);
|
* for inflight IO is enough.
|
||||||
|
*/
|
||||||
|
if (atomic_read(&blkif->inflight) > 0)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
if (blkif->irq) {
|
if (blkif->irq) {
|
||||||
unbind_from_irqhandler(blkif->irq, blkif);
|
unbind_from_irqhandler(blkif->irq, blkif);
|
||||||
|
@ -252,6 +269,8 @@ static void xen_blkif_disconnect(struct xen_blkif *blkif)
|
||||||
xenbus_unmap_ring_vfree(blkif->be->dev, blkif->blk_ring);
|
xenbus_unmap_ring_vfree(blkif->be->dev, blkif->blk_ring);
|
||||||
blkif->blk_rings.common.sring = NULL;
|
blkif->blk_rings.common.sring = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xen_blkif_free(struct xen_blkif *blkif)
|
static void xen_blkif_free(struct xen_blkif *blkif)
|
||||||
|
@ -259,8 +278,8 @@ static void xen_blkif_free(struct xen_blkif *blkif)
|
||||||
struct pending_req *req, *n;
|
struct pending_req *req, *n;
|
||||||
int i = 0, j;
|
int i = 0, j;
|
||||||
|
|
||||||
if (!atomic_dec_and_test(&blkif->refcnt))
|
xen_blkif_disconnect(blkif);
|
||||||
BUG();
|
xen_vbd_free(&blkif->vbd);
|
||||||
|
|
||||||
/* Remove all persistent grants and the cache of ballooned pages. */
|
/* Remove all persistent grants and the cache of ballooned pages. */
|
||||||
xen_blkbk_free_caches(blkif);
|
xen_blkbk_free_caches(blkif);
|
||||||
|
@ -449,16 +468,15 @@ static int xen_blkbk_remove(struct xenbus_device *dev)
|
||||||
be->backend_watch.node = NULL;
|
be->backend_watch.node = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dev_set_drvdata(&dev->dev, NULL);
|
||||||
|
|
||||||
if (be->blkif) {
|
if (be->blkif) {
|
||||||
xen_blkif_disconnect(be->blkif);
|
xen_blkif_disconnect(be->blkif);
|
||||||
xen_vbd_free(&be->blkif->vbd);
|
xen_blkif_put(be->blkif);
|
||||||
xen_blkif_free(be->blkif);
|
|
||||||
be->blkif = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(be->mode);
|
kfree(be->mode);
|
||||||
kfree(be);
|
kfree(be);
|
||||||
dev_set_drvdata(&dev->dev, NULL);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,10 +499,15 @@ static void xen_blkbk_discard(struct xenbus_transaction xbt, struct backend_info
|
||||||
struct xenbus_device *dev = be->dev;
|
struct xenbus_device *dev = be->dev;
|
||||||
struct xen_blkif *blkif = be->blkif;
|
struct xen_blkif *blkif = be->blkif;
|
||||||
int err;
|
int err;
|
||||||
int state = 0;
|
int state = 0, discard_enable;
|
||||||
struct block_device *bdev = be->blkif->vbd.bdev;
|
struct block_device *bdev = be->blkif->vbd.bdev;
|
||||||
struct request_queue *q = bdev_get_queue(bdev);
|
struct request_queue *q = bdev_get_queue(bdev);
|
||||||
|
|
||||||
|
err = xenbus_scanf(XBT_NIL, dev->nodename, "discard-enable", "%d",
|
||||||
|
&discard_enable);
|
||||||
|
if (err == 1 && !discard_enable)
|
||||||
|
return;
|
||||||
|
|
||||||
if (blk_queue_discard(q)) {
|
if (blk_queue_discard(q)) {
|
||||||
err = xenbus_printf(xbt, dev->nodename,
|
err = xenbus_printf(xbt, dev->nodename,
|
||||||
"discard-granularity", "%u",
|
"discard-granularity", "%u",
|
||||||
|
@ -700,7 +723,11 @@ static void frontend_changed(struct xenbus_device *dev,
|
||||||
* Enforce precondition before potential leak point.
|
* Enforce precondition before potential leak point.
|
||||||
* xen_blkif_disconnect() is idempotent.
|
* xen_blkif_disconnect() is idempotent.
|
||||||
*/
|
*/
|
||||||
xen_blkif_disconnect(be->blkif);
|
err = xen_blkif_disconnect(be->blkif);
|
||||||
|
if (err) {
|
||||||
|
xenbus_dev_fatal(dev, err, "pending I/O");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
err = connect_ring(be);
|
err = connect_ring(be);
|
||||||
if (err)
|
if (err)
|
||||||
|
|
|
@ -1635,36 +1635,24 @@ blkfront_closing(struct blkfront_info *info)
|
||||||
static void blkfront_setup_discard(struct blkfront_info *info)
|
static void blkfront_setup_discard(struct blkfront_info *info)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
char *type;
|
|
||||||
unsigned int discard_granularity;
|
unsigned int discard_granularity;
|
||||||
unsigned int discard_alignment;
|
unsigned int discard_alignment;
|
||||||
unsigned int discard_secure;
|
unsigned int discard_secure;
|
||||||
|
|
||||||
type = xenbus_read(XBT_NIL, info->xbdev->otherend, "type", NULL);
|
info->feature_discard = 1;
|
||||||
if (IS_ERR(type))
|
err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
|
||||||
return;
|
"discard-granularity", "%u", &discard_granularity,
|
||||||
|
"discard-alignment", "%u", &discard_alignment,
|
||||||
info->feature_secdiscard = 0;
|
NULL);
|
||||||
if (strncmp(type, "phy", 3) == 0) {
|
if (!err) {
|
||||||
err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
|
info->discard_granularity = discard_granularity;
|
||||||
"discard-granularity", "%u", &discard_granularity,
|
info->discard_alignment = discard_alignment;
|
||||||
"discard-alignment", "%u", &discard_alignment,
|
}
|
||||||
NULL);
|
err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
|
||||||
if (!err) {
|
"discard-secure", "%d", &discard_secure,
|
||||||
info->feature_discard = 1;
|
NULL);
|
||||||
info->discard_granularity = discard_granularity;
|
if (!err)
|
||||||
info->discard_alignment = discard_alignment;
|
info->feature_secdiscard = !!discard_secure;
|
||||||
}
|
|
||||||
err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
|
|
||||||
"discard-secure", "%d", &discard_secure,
|
|
||||||
NULL);
|
|
||||||
if (!err)
|
|
||||||
info->feature_secdiscard = discard_secure;
|
|
||||||
|
|
||||||
} else if (strncmp(type, "file", 4) == 0)
|
|
||||||
info->feature_discard = 1;
|
|
||||||
|
|
||||||
kfree(type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int blkfront_setup_indirect(struct blkfront_info *info)
|
static int blkfront_setup_indirect(struct blkfront_info *info)
|
||||||
|
|
|
@ -86,7 +86,7 @@ typedef uint64_t blkif_sector_t;
|
||||||
* Interface%20manuals/100293068c.pdf
|
* Interface%20manuals/100293068c.pdf
|
||||||
* The backend can optionally provide three extra XenBus attributes to
|
* The backend can optionally provide three extra XenBus attributes to
|
||||||
* further optimize the discard functionality:
|
* further optimize the discard functionality:
|
||||||
* 'discard-aligment' - Devices that support discard functionality may
|
* 'discard-alignment' - Devices that support discard functionality may
|
||||||
* internally allocate space in units that are bigger than the exported
|
* internally allocate space in units that are bigger than the exported
|
||||||
* logical block size. The discard-alignment parameter indicates how many bytes
|
* logical block size. The discard-alignment parameter indicates how many bytes
|
||||||
* the beginning of the partition is offset from the internal allocation unit's
|
* the beginning of the partition is offset from the internal allocation unit's
|
||||||
|
|
Loading…
Reference in New Issue