Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ublk: allow UBLK_IO_(UN)REGISTER_IO_BUF on any task

Currently, UBLK_IO_REGISTER_IO_BUF and UBLK_IO_UNREGISTER_IO_BUF are
only permitted on the ublk_io's daemon task. But this restriction is
unnecessary. ublk_register_io_buf() calls __ublk_check_and_get_req() to
look up the request from the tagset and atomically take a reference on
the request without accessing the ublk_io. ublk_unregister_io_buf()
doesn't use the q_id or tag at all.

So allow these opcodes even on tasks other than io->task.

Handle UBLK_IO_UNREGISTER_IO_BUF before obtaining the ubq and io since
the buffer index being unregistered is not necessarily related to the
specified q_id and tag.

Add a feature flag UBLK_F_BUF_REG_OFF_DAEMON that userspace can use to
determine whether the kernel supports off-daemon buffer registration.

Suggested-by: Ming Lei <ming.lei@redhat.com>
Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
Reviewed-by: Ming Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20250620151008.3976463-10-csander@purestorage.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Caleb Sander Mateos and committed by
Jens Axboe
763ff02c 2da1e7bb

+32 -5
+22 -5
drivers/block/ublk_drv.c
··· 70 70 | UBLK_F_UPDATE_SIZE \ 71 71 | UBLK_F_AUTO_BUF_REG \ 72 72 | UBLK_F_QUIESCE \ 73 - | UBLK_F_PER_IO_DAEMON) 73 + | UBLK_F_PER_IO_DAEMON \ 74 + | UBLK_F_BUF_REG_OFF_DAEMON) 74 75 75 76 #define UBLK_F_ALL_RECOVERY_FLAGS (UBLK_F_USER_RECOVERY \ 76 77 | UBLK_F_USER_RECOVERY_REISSUE \ ··· 2205 2204 if (ret) 2206 2205 goto out; 2207 2206 2207 + /* 2208 + * io_buffer_unregister_bvec() doesn't access the ubq or io, 2209 + * so no need to validate the q_id, tag, or task 2210 + */ 2211 + if (_IOC_NR(cmd_op) == UBLK_IO_UNREGISTER_IO_BUF) 2212 + return ublk_unregister_io_buf(cmd, ub, ub_cmd->addr, 2213 + issue_flags); 2214 + 2208 2215 ret = -EINVAL; 2209 2216 if (ub_cmd->q_id >= ub->dev_info.nr_hw_queues) 2210 2217 goto out; ··· 2233 2224 return -EIOCBQUEUED; 2234 2225 } 2235 2226 2236 - if (READ_ONCE(io->task) != current) 2227 + if (READ_ONCE(io->task) != current) { 2228 + /* 2229 + * ublk_register_io_buf() accesses only the io's refcount, 2230 + * so can be handled on any task 2231 + */ 2232 + if (_IOC_NR(cmd_op) == UBLK_IO_REGISTER_IO_BUF) 2233 + return ublk_register_io_buf(cmd, ubq, io, ub_cmd->addr, 2234 + issue_flags); 2235 + 2237 2236 goto out; 2237 + } 2238 2238 2239 2239 /* there is pending io cmd, something must be wrong */ 2240 2240 if (!(io->flags & UBLK_IO_FLAG_OWNED_BY_SRV)) { ··· 2262 2244 switch (_IOC_NR(cmd_op)) { 2263 2245 case UBLK_IO_REGISTER_IO_BUF: 2264 2246 return ublk_register_io_buf(cmd, ubq, io, ub_cmd->addr, issue_flags); 2265 - case UBLK_IO_UNREGISTER_IO_BUF: 2266 - return ublk_unregister_io_buf(cmd, ub, ub_cmd->addr, issue_flags); 2267 2247 case UBLK_IO_COMMIT_AND_FETCH_REQ: 2268 2248 ret = ublk_commit_and_fetch(ubq, io, cmd, ub_cmd, issue_flags); 2269 2249 if (ret) ··· 2977 2961 2978 2962 ub->dev_info.flags |= UBLK_F_CMD_IOCTL_ENCODE | 2979 2963 UBLK_F_URING_CMD_COMP_IN_TASK | 2980 - UBLK_F_PER_IO_DAEMON; 2964 + UBLK_F_PER_IO_DAEMON | 2965 + UBLK_F_BUF_REG_OFF_DAEMON; 2981 2966 2982 2967 /* GET_DATA isn't needed any more with USER_COPY or ZERO COPY */ 2983 2968 if (ub->dev_info.flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY |
+10
include/uapi/linux/ublk_cmd.h
··· 301 301 */ 302 302 #define UBLK_F_PER_IO_DAEMON (1ULL << 13) 303 303 304 + /* 305 + * If this feature is set, UBLK_U_IO_REGISTER_IO_BUF/UBLK_U_IO_UNREGISTER_IO_BUF 306 + * can be issued for an I/O on any task. q_id and tag are also ignored in 307 + * UBLK_U_IO_UNREGISTER_IO_BUF's ublksrv_io_cmd. 308 + * If it is unset, zero-copy buffers can only be registered and unregistered by 309 + * the I/O's daemon task. The q_id and tag of the registered buffer are required 310 + * in UBLK_U_IO_UNREGISTER_IO_BUF's ublksrv_io_cmd. 311 + */ 312 + #define UBLK_F_BUF_REG_OFF_DAEMON (1ULL << 14) 313 + 304 314 /* device state */ 305 315 #define UBLK_S_DEV_DEAD 0 306 316 #define UBLK_S_DEV_LIVE 1