Commit 907196ab authored by Markus Pargmann's avatar Markus Pargmann Committed by Kleber Sacilotto de Souza

nbd: Create size change events for userspace

BugLink: http://bugs.launchpad.net/bugs/696435

The userspace needs to know when nbd devices are ready for use.
Currently no events are created for the userspace which doesn't work for
systemd.

See the discussion here: https://github.com/systemd/systemd/pull/358

This patch uses a central point to setup the nbd-internal sizes. A ioctl
to set a size does not lead to a visible size change. The size of the
block device will be kept at 0 until nbd is connected. As soon as it
connects, the size will be changed to the real value and a uevent is
created. When disconnecting, the blockdevice is set to 0 size and
another uevent is generated.
Signed-off-by: default avatarMarkus Pargmann <mpa@pengutronix.de>
(cherry picked from commit 37091fdd)
Signed-off-by: default avatarJoseph Salisbury <joseph.salisbury@canonical.com>
Acked-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
Acked-by: default avatarMarcelo Cerri <marcelo.cerri@canonical.com>
Signed-off-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
parent f9414870
...@@ -98,6 +98,11 @@ static inline struct device *nbd_to_dev(struct nbd_device *nbd) ...@@ -98,6 +98,11 @@ static inline struct device *nbd_to_dev(struct nbd_device *nbd)
return disk_to_dev(nbd->disk); return disk_to_dev(nbd->disk);
} }
static bool nbd_is_connected(struct nbd_device *nbd)
{
return !!nbd->task_recv;
}
static const char *nbdcmd_to_ascii(int cmd) static const char *nbdcmd_to_ascii(int cmd)
{ {
switch (cmd) { switch (cmd) {
...@@ -110,6 +115,42 @@ static const char *nbdcmd_to_ascii(int cmd) ...@@ -110,6 +115,42 @@ static const char *nbdcmd_to_ascii(int cmd)
return "invalid"; return "invalid";
} }
static int nbd_size_clear(struct nbd_device *nbd, struct block_device *bdev)
{
bdev->bd_inode->i_size = 0;
set_capacity(nbd->disk, 0);
kobject_uevent(&nbd_to_dev(nbd)->kobj, KOBJ_CHANGE);
return 0;
}
static void nbd_size_update(struct nbd_device *nbd, struct block_device *bdev)
{
if (!nbd_is_connected(nbd))
return;
bdev->bd_inode->i_size = nbd->bytesize;
set_capacity(nbd->disk, nbd->bytesize >> 9);
kobject_uevent(&nbd_to_dev(nbd)->kobj, KOBJ_CHANGE);
}
static int nbd_size_set(struct nbd_device *nbd, struct block_device *bdev,
int blocksize, int nr_blocks)
{
int ret;
ret = set_blocksize(bdev, blocksize);
if (ret)
return ret;
nbd->blksize = blocksize;
nbd->bytesize = (loff_t)blocksize * (loff_t)nr_blocks;
nbd_size_update(nbd, bdev);
return 0;
}
static void nbd_end_request(struct nbd_device *nbd, struct request *req) static void nbd_end_request(struct nbd_device *nbd, struct request *req)
{ {
int error = req->errors ? -EIO : 0; int error = req->errors ? -EIO : 0;
...@@ -402,7 +443,7 @@ static struct device_attribute pid_attr = { ...@@ -402,7 +443,7 @@ static struct device_attribute pid_attr = {
.show = pid_show, .show = pid_show,
}; };
static int nbd_thread_recv(struct nbd_device *nbd) static int nbd_thread_recv(struct nbd_device *nbd, struct block_device *bdev)
{ {
struct request *req; struct request *req;
int ret; int ret;
...@@ -427,6 +468,8 @@ static int nbd_thread_recv(struct nbd_device *nbd) ...@@ -427,6 +468,8 @@ static int nbd_thread_recv(struct nbd_device *nbd)
return ret; return ret;
} }
nbd_size_update(nbd, bdev);
while (1) { while (1) {
req = nbd_read_stat(nbd); req = nbd_read_stat(nbd);
if (IS_ERR(req)) { if (IS_ERR(req)) {
...@@ -437,6 +480,8 @@ static int nbd_thread_recv(struct nbd_device *nbd) ...@@ -437,6 +480,8 @@ static int nbd_thread_recv(struct nbd_device *nbd)
nbd_end_request(nbd, req); nbd_end_request(nbd, req);
} }
nbd_size_clear(nbd, bdev);
device_remove_file(disk_to_dev(nbd->disk), &pid_attr); device_remove_file(disk_to_dev(nbd->disk), &pid_attr);
spin_lock_irqsave(&nbd->tasks_lock, flags); spin_lock_irqsave(&nbd->tasks_lock, flags);
...@@ -696,20 +741,19 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, ...@@ -696,20 +741,19 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
return -EINVAL; return -EINVAL;
} }
case NBD_SET_BLKSIZE: case NBD_SET_BLKSIZE: {
nbd->blksize = arg; loff_t bsize = nbd->bytesize;
nbd->bytesize &= ~(nbd->blksize-1); do_div(bsize, arg);
bdev->bd_inode->i_size = nbd->bytesize;
set_blocksize(bdev, nbd->blksize); return nbd_size_set(nbd, bdev, arg, bsize);
set_capacity(nbd->disk, nbd->bytesize >> 9); }
return 0;
case NBD_SET_SIZE: case NBD_SET_SIZE:
nbd->bytesize = arg & ~(nbd->blksize-1); return nbd_size_set(nbd, bdev, nbd->blksize,
bdev->bd_inode->i_size = nbd->bytesize; arg / nbd->blksize);
set_blocksize(bdev, nbd->blksize);
set_capacity(nbd->disk, nbd->bytesize >> 9); case NBD_SET_SIZE_BLOCKS:
return 0; return nbd_size_set(nbd, bdev, nbd->blksize, arg);
case NBD_SET_TIMEOUT: case NBD_SET_TIMEOUT:
nbd->xmit_timeout = arg * HZ; nbd->xmit_timeout = arg * HZ;
...@@ -725,13 +769,6 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, ...@@ -725,13 +769,6 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
nbd->flags = arg; nbd->flags = arg;
return 0; return 0;
case NBD_SET_SIZE_BLOCKS:
nbd->bytesize = ((u64) arg) * nbd->blksize;
bdev->bd_inode->i_size = nbd->bytesize;
set_blocksize(bdev, nbd->blksize);
set_capacity(nbd->disk, nbd->bytesize >> 9);
return 0;
case NBD_DO_IT: { case NBD_DO_IT: {
struct task_struct *thread; struct task_struct *thread;
struct socket *sock; struct socket *sock;
...@@ -762,7 +799,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, ...@@ -762,7 +799,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
} }
nbd_dev_dbg_init(nbd); nbd_dev_dbg_init(nbd);
error = nbd_thread_recv(nbd); error = nbd_thread_recv(nbd, bdev);
nbd_dev_dbg_close(nbd); nbd_dev_dbg_close(nbd);
kthread_stop(thread); kthread_stop(thread);
......
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