Message ID | dab1787c8dd4da85efae928b4dbafbf005c726aa.1508520497.git.joseph.salisbury@canonical.com |
---|---|
State | New |
Headers | show |
Series | [SRU,Xenial,1/1] nbd: Create size change events for userspace | expand |
On 10/20/17 19:33, Joseph Salisbury wrote: > From: Markus Pargmann <mpa@pengutronix.de> > > 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: Markus Pargmann <mpa@pengutronix.de> > (cherry picked from commit 37091fdd831f28a6509008542174ed324dd645bc) > Signed-off-by: Joseph Salisbury <joseph.salisbury@canonical.com> Clean cherry-pick, good test results, fixing 6 y/o bug :-). Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> > --- > drivers/block/nbd.c | 79 +++++++++++++++++++++++++++++++++++++++-------------- > 1 file changed, 58 insertions(+), 21 deletions(-) > > diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c > index b05226d..5f807a6 100644 > --- a/drivers/block/nbd.c > +++ b/drivers/block/nbd.c > @@ -98,6 +98,11 @@ static inline struct device *nbd_to_dev(struct nbd_device *nbd) > 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) > { > switch (cmd) { > @@ -110,6 +115,42 @@ static const char *nbdcmd_to_ascii(int cmd) > 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) > { > int error = req->errors ? -EIO : 0; > @@ -402,7 +443,7 @@ static struct device_attribute pid_attr = { > .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; > int ret; > @@ -427,6 +468,8 @@ static int nbd_thread_recv(struct nbd_device *nbd) > return ret; > } > > + nbd_size_update(nbd, bdev); > + > while (1) { > req = nbd_read_stat(nbd); > if (IS_ERR(req)) { > @@ -437,6 +480,8 @@ static int nbd_thread_recv(struct nbd_device *nbd) > nbd_end_request(nbd, req); > } > > + nbd_size_clear(nbd, bdev); > + > device_remove_file(disk_to_dev(nbd->disk), &pid_attr); > > spin_lock_irqsave(&nbd->tasks_lock, flags); > @@ -696,20 +741,19 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, > return -EINVAL; > } > > - case NBD_SET_BLKSIZE: > - nbd->blksize = arg; > - nbd->bytesize &= ~(nbd->blksize-1); > - bdev->bd_inode->i_size = nbd->bytesize; > - set_blocksize(bdev, nbd->blksize); > - set_capacity(nbd->disk, nbd->bytesize >> 9); > - return 0; > + case NBD_SET_BLKSIZE: { > + loff_t bsize = nbd->bytesize; > + do_div(bsize, arg); > + > + return nbd_size_set(nbd, bdev, arg, bsize); > + } > > case NBD_SET_SIZE: > - nbd->bytesize = arg & ~(nbd->blksize-1); > - bdev->bd_inode->i_size = nbd->bytesize; > - set_blocksize(bdev, nbd->blksize); > - set_capacity(nbd->disk, nbd->bytesize >> 9); > - return 0; > + return nbd_size_set(nbd, bdev, nbd->blksize, > + arg / nbd->blksize); > + > + case NBD_SET_SIZE_BLOCKS: > + return nbd_size_set(nbd, bdev, nbd->blksize, arg); > > case NBD_SET_TIMEOUT: > nbd->xmit_timeout = arg * HZ; > @@ -725,13 +769,6 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, > nbd->flags = arg; > 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: { > struct task_struct *thread; > struct socket *sock; > @@ -762,7 +799,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, > } > > nbd_dev_dbg_init(nbd); > - error = nbd_thread_recv(nbd); > + error = nbd_thread_recv(nbd, bdev); > nbd_dev_dbg_close(nbd); > kthread_stop(thread); > >
Applied to xenial/master-next branch. Thanks.
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index b05226d..5f807a6 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -98,6 +98,11 @@ static inline struct device *nbd_to_dev(struct nbd_device *nbd) 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) { switch (cmd) { @@ -110,6 +115,42 @@ static const char *nbdcmd_to_ascii(int cmd) 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) { int error = req->errors ? -EIO : 0; @@ -402,7 +443,7 @@ static struct device_attribute pid_attr = { .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; int ret; @@ -427,6 +468,8 @@ static int nbd_thread_recv(struct nbd_device *nbd) return ret; } + nbd_size_update(nbd, bdev); + while (1) { req = nbd_read_stat(nbd); if (IS_ERR(req)) { @@ -437,6 +480,8 @@ static int nbd_thread_recv(struct nbd_device *nbd) nbd_end_request(nbd, req); } + nbd_size_clear(nbd, bdev); + device_remove_file(disk_to_dev(nbd->disk), &pid_attr); spin_lock_irqsave(&nbd->tasks_lock, flags); @@ -696,20 +741,19 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, return -EINVAL; } - case NBD_SET_BLKSIZE: - nbd->blksize = arg; - nbd->bytesize &= ~(nbd->blksize-1); - bdev->bd_inode->i_size = nbd->bytesize; - set_blocksize(bdev, nbd->blksize); - set_capacity(nbd->disk, nbd->bytesize >> 9); - return 0; + case NBD_SET_BLKSIZE: { + loff_t bsize = nbd->bytesize; + do_div(bsize, arg); + + return nbd_size_set(nbd, bdev, arg, bsize); + } case NBD_SET_SIZE: - nbd->bytesize = arg & ~(nbd->blksize-1); - bdev->bd_inode->i_size = nbd->bytesize; - set_blocksize(bdev, nbd->blksize); - set_capacity(nbd->disk, nbd->bytesize >> 9); - return 0; + return nbd_size_set(nbd, bdev, nbd->blksize, + arg / nbd->blksize); + + case NBD_SET_SIZE_BLOCKS: + return nbd_size_set(nbd, bdev, nbd->blksize, arg); case NBD_SET_TIMEOUT: nbd->xmit_timeout = arg * HZ; @@ -725,13 +769,6 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, nbd->flags = arg; 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: { struct task_struct *thread; struct socket *sock; @@ -762,7 +799,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, } nbd_dev_dbg_init(nbd); - error = nbd_thread_recv(nbd); + error = nbd_thread_recv(nbd, bdev); nbd_dev_dbg_close(nbd); kthread_stop(thread);