nbd: Add the nbd NBD_DISCONNECT_ON_CLOSE config flag.
If NBD_DISCONNECT_ON_CLOSE is set on a device, then the driver will issue a disconnect from nbd_release if the device has no remaining bdev->bd_openers. Fix ret val so reconfigure with only setting the flag succeeds. Reviewed-by: Josef Bacik <josef@toxicpanda.com> Signed-off-by: Doron Roberts-Kedes <doronrk@fb.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Родитель
ce042c183b
Коммит
08ba91ee6e
|
@ -76,6 +76,7 @@ struct link_dead_args {
|
||||||
#define NBD_HAS_CONFIG_REF 4
|
#define NBD_HAS_CONFIG_REF 4
|
||||||
#define NBD_BOUND 5
|
#define NBD_BOUND 5
|
||||||
#define NBD_DESTROY_ON_DISCONNECT 6
|
#define NBD_DESTROY_ON_DISCONNECT 6
|
||||||
|
#define NBD_DISCONNECT_ON_CLOSE 7
|
||||||
|
|
||||||
struct nbd_config {
|
struct nbd_config {
|
||||||
u32 flags;
|
u32 flags;
|
||||||
|
@ -138,6 +139,7 @@ static void nbd_config_put(struct nbd_device *nbd);
|
||||||
static void nbd_connect_reply(struct genl_info *info, int index);
|
static void nbd_connect_reply(struct genl_info *info, int index);
|
||||||
static int nbd_genl_status(struct sk_buff *skb, struct genl_info *info);
|
static int nbd_genl_status(struct sk_buff *skb, struct genl_info *info);
|
||||||
static void nbd_dead_link_work(struct work_struct *work);
|
static void nbd_dead_link_work(struct work_struct *work);
|
||||||
|
static void nbd_disconnect_and_put(struct nbd_device *nbd);
|
||||||
|
|
||||||
static inline struct device *nbd_to_dev(struct nbd_device *nbd)
|
static inline struct device *nbd_to_dev(struct nbd_device *nbd)
|
||||||
{
|
{
|
||||||
|
@ -1305,6 +1307,12 @@ out:
|
||||||
static void nbd_release(struct gendisk *disk, fmode_t mode)
|
static void nbd_release(struct gendisk *disk, fmode_t mode)
|
||||||
{
|
{
|
||||||
struct nbd_device *nbd = disk->private_data;
|
struct nbd_device *nbd = disk->private_data;
|
||||||
|
struct block_device *bdev = bdget_disk(disk, 0);
|
||||||
|
|
||||||
|
if (test_bit(NBD_DISCONNECT_ON_CLOSE, &nbd->config->runtime_flags) &&
|
||||||
|
bdev->bd_openers == 0)
|
||||||
|
nbd_disconnect_and_put(nbd);
|
||||||
|
|
||||||
nbd_config_put(nbd);
|
nbd_config_put(nbd);
|
||||||
nbd_put(nbd);
|
nbd_put(nbd);
|
||||||
}
|
}
|
||||||
|
@ -1705,6 +1713,10 @@ again:
|
||||||
&config->runtime_flags);
|
&config->runtime_flags);
|
||||||
put_dev = true;
|
put_dev = true;
|
||||||
}
|
}
|
||||||
|
if (flags & NBD_CFLAG_DISCONNECT_ON_CLOSE) {
|
||||||
|
set_bit(NBD_DISCONNECT_ON_CLOSE,
|
||||||
|
&config->runtime_flags);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->attrs[NBD_ATTR_SOCKETS]) {
|
if (info->attrs[NBD_ATTR_SOCKETS]) {
|
||||||
|
@ -1749,6 +1761,17 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nbd_disconnect_and_put(struct nbd_device *nbd)
|
||||||
|
{
|
||||||
|
mutex_lock(&nbd->config_lock);
|
||||||
|
nbd_disconnect(nbd);
|
||||||
|
nbd_clear_sock(nbd);
|
||||||
|
mutex_unlock(&nbd->config_lock);
|
||||||
|
if (test_and_clear_bit(NBD_HAS_CONFIG_REF,
|
||||||
|
&nbd->config->runtime_flags))
|
||||||
|
nbd_config_put(nbd);
|
||||||
|
}
|
||||||
|
|
||||||
static int nbd_genl_disconnect(struct sk_buff *skb, struct genl_info *info)
|
static int nbd_genl_disconnect(struct sk_buff *skb, struct genl_info *info)
|
||||||
{
|
{
|
||||||
struct nbd_device *nbd;
|
struct nbd_device *nbd;
|
||||||
|
@ -1781,13 +1804,7 @@ static int nbd_genl_disconnect(struct sk_buff *skb, struct genl_info *info)
|
||||||
nbd_put(nbd);
|
nbd_put(nbd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
mutex_lock(&nbd->config_lock);
|
nbd_disconnect_and_put(nbd);
|
||||||
nbd_disconnect(nbd);
|
|
||||||
nbd_clear_sock(nbd);
|
|
||||||
mutex_unlock(&nbd->config_lock);
|
|
||||||
if (test_and_clear_bit(NBD_HAS_CONFIG_REF,
|
|
||||||
&nbd->config->runtime_flags))
|
|
||||||
nbd_config_put(nbd);
|
|
||||||
nbd_config_put(nbd);
|
nbd_config_put(nbd);
|
||||||
nbd_put(nbd);
|
nbd_put(nbd);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1798,7 +1815,7 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info)
|
||||||
struct nbd_device *nbd = NULL;
|
struct nbd_device *nbd = NULL;
|
||||||
struct nbd_config *config;
|
struct nbd_config *config;
|
||||||
int index;
|
int index;
|
||||||
int ret = -EINVAL;
|
int ret = 0;
|
||||||
bool put_dev = false;
|
bool put_dev = false;
|
||||||
|
|
||||||
if (!netlink_capable(skb, CAP_SYS_ADMIN))
|
if (!netlink_capable(skb, CAP_SYS_ADMIN))
|
||||||
|
@ -1838,6 +1855,7 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info)
|
||||||
!nbd->task_recv) {
|
!nbd->task_recv) {
|
||||||
dev_err(nbd_to_dev(nbd),
|
dev_err(nbd_to_dev(nbd),
|
||||||
"not configured, cannot reconfigure\n");
|
"not configured, cannot reconfigure\n");
|
||||||
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1862,6 +1880,14 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info)
|
||||||
&config->runtime_flags))
|
&config->runtime_flags))
|
||||||
refcount_inc(&nbd->refs);
|
refcount_inc(&nbd->refs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & NBD_CFLAG_DISCONNECT_ON_CLOSE) {
|
||||||
|
set_bit(NBD_DISCONNECT_ON_CLOSE,
|
||||||
|
&config->runtime_flags);
|
||||||
|
} else {
|
||||||
|
clear_bit(NBD_DISCONNECT_ON_CLOSE,
|
||||||
|
&config->runtime_flags);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->attrs[NBD_ATTR_SOCKETS]) {
|
if (info->attrs[NBD_ATTR_SOCKETS]) {
|
||||||
|
|
|
@ -53,6 +53,9 @@ enum {
|
||||||
/* These are client behavior specific flags. */
|
/* These are client behavior specific flags. */
|
||||||
#define NBD_CFLAG_DESTROY_ON_DISCONNECT (1 << 0) /* delete the nbd device on
|
#define NBD_CFLAG_DESTROY_ON_DISCONNECT (1 << 0) /* delete the nbd device on
|
||||||
disconnect. */
|
disconnect. */
|
||||||
|
#define NBD_CFLAG_DISCONNECT_ON_CLOSE (1 << 1) /* disconnect the nbd device on
|
||||||
|
* close by last opener.
|
||||||
|
*/
|
||||||
|
|
||||||
/* userspace doesn't need the nbd_device structure */
|
/* userspace doesn't need the nbd_device structure */
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче