Enable NBD_CFLAG_DISCONNECT_ON_CLOSE to allow `umount(2)` to unmount the filesystem and disconnect NBD devices in a single operation.
Signed-off-by: Gao Xiang <hsiang...@linux.alibaba.com> --- lib/backends/nbd.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ lib/liberofs_nbd.h | 2 ++ mount/main.c | 16 +++++++++++++++- 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/lib/backends/nbd.c b/lib/backends/nbd.c index 682fc7b..b9535dc 100644 --- a/lib/backends/nbd.c +++ b/lib/backends/nbd.c @@ -466,6 +466,46 @@ err_out: close(sv[1]); return err; } + +int erofs_nbd_nl_reconfigure(int index, const char *identifier, + bool autoclear) +{ + struct nl_sock *socket; + struct nl_msg *msg; + int err, driver_id; + unsigned int cflags; + + socket = erofs_nbd_get_nl_sock(&driver_id); + if (IS_ERR(socket)) + return PTR_ERR(socket); + + msg = nlmsg_alloc(); + if (!msg) { + erofs_err("Couldn't allocate netlink message"); + err = -ENOMEM; + goto err_nls_free; + } + + err = -EINVAL; + genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, driver_id, 0, 0, + NBD_CMD_RECONFIGURE, 0); + NLA_PUT_U32(msg, NBD_ATTR_INDEX, index); + if (identifier) + NLA_PUT_STRING(msg, NBD_ATTR_BACKEND_IDENTIFIER, identifier); + + cflags = (autoclear ? NBD_CFLAG_DISCONNECT_ON_CLOSE : 0); + NLA_PUT_U64(msg, NBD_ATTR_CLIENT_FLAGS, cflags); + + err = nl_send_sync(socket, msg); + nl_socket_free(socket); + return err; + +nla_put_failure: + nlmsg_free(msg); +err_nls_free: + nl_socket_free(socket); + return err; +} #else int erofs_nbd_nl_connect(int *index, int blkbits, u64 blocks, const char *identifier) @@ -477,6 +517,12 @@ int erofs_nbd_nl_reconnect(int index, const char *identifier) { return -EOPNOTSUPP; } + +int erofs_nbd_nl_reconfigure(int index, const char *identifier, + bool autoclear) +{ + return -EOPNOTSUPP; +} #endif int erofs_nbd_do_it(int nbdfd) diff --git a/lib/liberofs_nbd.h b/lib/liberofs_nbd.h index 049c318..260605a 100644 --- a/lib/liberofs_nbd.h +++ b/lib/liberofs_nbd.h @@ -47,4 +47,6 @@ int erofs_nbd_disconnect(int nbdfd); int erofs_nbd_nl_connect(int *index, int blkbits, u64 blocks, const char *identifier); int erofs_nbd_nl_reconnect(int index, const char *identifier); +int erofs_nbd_nl_reconfigure(int index, const char *identifier, + bool autoclear); #endif diff --git a/mount/main.c b/mount/main.c index 139b532..a270f0a 100644 --- a/mount/main.c +++ b/mount/main.c @@ -544,7 +544,8 @@ static int erofsmount_nbd(const char *source, const char *mountpoint, const char *fstype, int flags, const char *options) { - char nbdpath[32]; + bool is_netlink = false; + char nbdpath[32], *id; int num, nbdfd; pid_t pid = 0; long err; @@ -575,6 +576,7 @@ static int erofsmount_nbd(const char *source, const char *mountpoint, } else { num = err; (void)snprintf(nbdpath, sizeof(nbdpath), "/dev/nbd%d", num); + is_netlink = true; } while (1) { @@ -591,6 +593,18 @@ static int erofsmount_nbd(const char *source, const char *mountpoint, err = mount(nbdpath, mountpoint, fstype, flags, options); if (err < 0) err = -errno; + + if (!err && is_netlink) { + id = erofs_nbd_get_identifier(num); + if (id == ERR_PTR(-ENOENT)) + id = NULL; + + err = IS_ERR(id) ? PTR_ERR(id) : + erofs_nbd_nl_reconfigure(num, id, true); + if (err) + erofs_warn("failed to turn on autoclear for nbd%d: %s", + num, erofs_strerror(err)); + } } return err; } -- 2.43.5