History

scsi: target: tcmu: Add new feature KEEP_BUF

When running command pipelining for WRITE direction commands (e.g. tape device write), userspace sends cmd completion to cmd ring before processing write data. In that case userspace has to copy data before sending completion, because cmd completion also implicitly releases the data buffer in data area. The new feature KEEP_BUF allows userspace to optionally keep the buffer after completion by setting new bit TCMU_UFLAG_KEEP_BUF in tcmu_cmd_entry_hdr->uflags. In that case buffer has to be released explicitly by writing the cmd_id to new action item free_kept_buf. All kept buffers are released during reset_ring and if userspace closes uio device (tcmu_release).

Bodo Stroesser committed 5 years ago

Commit 018c1491 parent c11a1ae2 files · +141 −11Browse files

Unified · Split

2 files
  1. drivers/target/target_core_user.c +139 −11
  2. include/uapi/linux/target_core_user.h +2 −0
drivers/target/target_core_user.c+139−11
@@ -191,6 +191,7 @@ struct tcmu_cmd { · 190 unmodified lines
191 unsigned long deadline;191 unsigned long deadline;
192 192
193#define TCMU_CMD_BIT_EXPIRED 0193#define TCMU_CMD_BIT_EXPIRED 0
194#define TCMU_CMD_BIT_KEEP_BUF 1
194 unsigned long flags;195 unsigned long flags;
195};196};
196 197
@@ -1315,11 +1316,13 @@ unlock: · 1118 unmodified lines
1315 mutex_unlock(&udev->cmdr_lock);1316 mutex_unlock(&udev->cmdr_lock);
1316}1317}
1317 1318
1318static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry *entry)1319static bool tcmu_handle_completion(struct tcmu_cmd *cmd,
1320 struct tcmu_cmd_entry *entry, bool keep_buf)
1319{1321{
1320 struct se_cmd *se_cmd = cmd->se_cmd;1322 struct se_cmd *se_cmd = cmd->se_cmd;
1321 struct tcmu_dev *udev = cmd->tcmu_dev;1323 struct tcmu_dev *udev = cmd->tcmu_dev;
1322 bool read_len_valid = false;1324 bool read_len_valid = false;
1325 bool ret = true;
1323 uint32_t read_len;1326 uint32_t read_len;
1324 1327
1325 /*1328 /*
@@ -1330,6 +1333,13 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry * · 4 unmodified lines
1330 WARN_ON_ONCE(se_cmd);1333 WARN_ON_ONCE(se_cmd);
1331 goto out;1334 goto out;
1332 }1335 }
1336 if (test_bit(TCMU_CMD_BIT_KEEP_BUF, &cmd->flags)) {
1337 pr_err("cmd_id %u already completed with KEEP_BUF, ring is broken\n",
1338 entry->hdr.cmd_id);
1339 set_bit(TCMU_DEV_BIT_BROKEN, &udev->flags);
1340 ret = false;
1341 goto out;
1342 }
1333 1343
1334 list_del_init(&cmd->queue_entry);1344 list_del_init(&cmd->queue_entry);
1335 1345
@@ -1379,8 +1389,22 @@ done: · 43 unmodified lines
1379 target_complete_cmd(cmd->se_cmd, entry->rsp.scsi_status);1389 target_complete_cmd(cmd->se_cmd, entry->rsp.scsi_status);
1380 1390
1381out:1391out:
1382 tcmu_cmd_free_data(cmd, cmd->dbi_cnt);1392 if (!keep_buf) {
1383 tcmu_free_cmd(cmd);1393 tcmu_cmd_free_data(cmd, cmd->dbi_cnt);
1394 tcmu_free_cmd(cmd);
1395 } else {
1396 /*
1397 * Keep this command after completion, since userspace still
1398 * needs the data buffer. Mark it with TCMU_CMD_BIT_KEEP_BUF
1399 * and reset potential TCMU_CMD_BIT_EXPIRED, so we don't accept
1400 * a second completion later.
1401 * Userspace can free the buffer later by writing the cmd_id
1402 * to new action attribute free_kept_buf.
1403 */
1404 clear_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags);
1405 set_bit(TCMU_CMD_BIT_KEEP_BUF, &cmd->flags);
1406 }
1407 return ret;
1384}1408}
1385 1409
1386static int tcmu_run_tmr_queue(struct tcmu_dev *udev)1410static int tcmu_run_tmr_queue(struct tcmu_dev *udev)
@@ -1432,6 +1456,7 @@ static bool tcmu_handle_completions(struct tcmu_dev *udev) · 45 unmodified lines
1432 while (udev->cmdr_last_cleaned != READ_ONCE(mb->cmd_tail)) {1456 while (udev->cmdr_last_cleaned != READ_ONCE(mb->cmd_tail)) {
1433 1457
1434 struct tcmu_cmd_entry *entry = udev->cmdr + udev->cmdr_last_cleaned;1458 struct tcmu_cmd_entry *entry = udev->cmdr + udev->cmdr_last_cleaned;
1459 bool keep_buf;
1435 1460
1436 /*1461 /*
1437 * Flush max. up to end of cmd ring since current entry might1462 * Flush max. up to end of cmd ring since current entry might
@@ -1453,7 +1478,11 @@ static bool tcmu_handle_completions(struct tcmu_dev *udev) · 15 unmodified lines
1453 }1478 }
1454 WARN_ON(tcmu_hdr_get_op(entry->hdr.len_op) != TCMU_OP_CMD);1479 WARN_ON(tcmu_hdr_get_op(entry->hdr.len_op) != TCMU_OP_CMD);
1455 1480
1456 cmd = xa_erase(&udev->commands, entry->hdr.cmd_id);1481 keep_buf = !!(entry->hdr.uflags & TCMU_UFLAG_KEEP_BUF);
1482 if (keep_buf)
1483 cmd = xa_load(&udev->commands, entry->hdr.cmd_id);
1484 else
1485 cmd = xa_erase(&udev->commands, entry->hdr.cmd_id);
1457 if (!cmd) {1486 if (!cmd) {
1458 pr_err("cmd_id %u not found, ring is broken\n",1487 pr_err("cmd_id %u not found, ring is broken\n",
1459 entry->hdr.cmd_id);1488 entry->hdr.cmd_id);
@@ -1461,7 +1490,8 @@ static bool tcmu_handle_completions(struct tcmu_dev *udev) · 1 unmodified line
1461 return false;1490 return false;
1462 }1491 }
1463 1492
1464 tcmu_handle_completion(cmd, entry);1493 if (!tcmu_handle_completion(cmd, entry, keep_buf))
1494 break;
1465 1495
1466 UPDATE_HEAD(udev->cmdr_last_cleaned,1496 UPDATE_HEAD(udev->cmdr_last_cleaned,
1467 tcmu_hdr_get_len(entry->hdr.len_op),1497 tcmu_hdr_get_len(entry->hdr.len_op),
@@ -1619,7 +1649,8 @@ static void tcmu_dev_call_rcu(struct rcu_head *p) · 151 unmodified lines
1619 1649
1620static int tcmu_check_and_free_pending_cmd(struct tcmu_cmd *cmd)1650static int tcmu_check_and_free_pending_cmd(struct tcmu_cmd *cmd)
1621{1651{
1622 if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) {1652 if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags) ||
1653 test_bit(TCMU_CMD_BIT_KEEP_BUF, &cmd->flags)) {
1623 kmem_cache_free(tcmu_cmd_cache, cmd);1654 kmem_cache_free(tcmu_cmd_cache, cmd);
1624 return 0;1655 return 0;
1625 }1656 }
@@ -1903,6 +1934,38 @@ static int tcmu_open(struct uio_info *info, struct inode *inode) · 277 unmodified lines
1903static int tcmu_release(struct uio_info *info, struct inode *inode)1934static int tcmu_release(struct uio_info *info, struct inode *inode)
1904{1935{
1905 struct tcmu_dev *udev = container_of(info, struct tcmu_dev, uio_info);1936 struct tcmu_dev *udev = container_of(info, struct tcmu_dev, uio_info);
1937 struct tcmu_cmd *cmd;
1938 unsigned long i;
1939 bool freed = false;
1940
1941 mutex_lock(&udev->cmdr_lock);
1942
1943 xa_for_each(&udev->commands, i, cmd) {
1944 /* Cmds with KEEP_BUF set are no longer on the ring, but
1945 * userspace still holds the data buffer. If userspace closes
1946 * we implicitly free these cmds and buffers, since after new
1947 * open the (new ?) userspace cannot find the cmd in the ring
1948 * and thus never will release the buffer by writing cmd_id to
1949 * free_kept_buf action attribute.
1950 */
1951 if (!test_bit(TCMU_CMD_BIT_KEEP_BUF, &cmd->flags))
1952 continue;
1953 pr_debug("removing KEEP_BUF cmd %u on dev %s from ring\n",
1954 cmd->cmd_id, udev->name);
1955 freed = true;
1956
1957 xa_erase(&udev->commands, i);
1958 tcmu_cmd_free_data(cmd, cmd->dbi_cnt);
1959 tcmu_free_cmd(cmd);
1960 }
1961 /*
1962 * We only freed data space, not ring space. Therefore we dont call
1963 * run_tmr_queue, but call run_qfull_queue if tmr_list is empty.
1964 */
1965 if (freed && list_empty(&udev->tmr_queue))
1966 run_qfull_queue(udev, false);
1967
1968 mutex_unlock(&udev->cmdr_lock);
1906 1969
1907 clear_bit(TCMU_DEV_BIT_OPEN, &udev->flags);1970 clear_bit(TCMU_DEV_BIT_OPEN, &udev->flags);
1908 1971
@@ -2147,7 +2210,8 @@ static int tcmu_configure_device(struct se_device *dev) · 238 unmodified lines
2147 mb->version = TCMU_MAILBOX_VERSION;2210 mb->version = TCMU_MAILBOX_VERSION;
2148 mb->flags = TCMU_MAILBOX_FLAG_CAP_OOOC |2211 mb->flags = TCMU_MAILBOX_FLAG_CAP_OOOC |
2149 TCMU_MAILBOX_FLAG_CAP_READ_LEN |2212 TCMU_MAILBOX_FLAG_CAP_READ_LEN |
2150 TCMU_MAILBOX_FLAG_CAP_TMR;2213 TCMU_MAILBOX_FLAG_CAP_TMR |
2214 TCMU_MAILBOX_FLAG_CAP_KEEP_BUF;
2151 mb->cmdr_off = CMDR_OFF;2215 mb->cmdr_off = CMDR_OFF;
2152 mb->cmdr_size = udev->cmdr_size;2216 mb->cmdr_size = udev->cmdr_size;
2153 2217
@@ -2279,12 +2343,16 @@ static void tcmu_reset_ring(struct tcmu_dev *udev, u8 err_level) · 125 unmodified lines
2279 mutex_lock(&udev->cmdr_lock);2343 mutex_lock(&udev->cmdr_lock);
2280 2344
2281 xa_for_each(&udev->commands, i, cmd) {2345 xa_for_each(&udev->commands, i, cmd) {
2282 pr_debug("removing cmd %u on dev %s from ring (is expired %d)\n",2346 pr_debug("removing cmd %u on dev %s from ring %s\n",
2283 cmd->cmd_id, udev->name,2347 cmd->cmd_id, udev->name,
2284 test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags));2348 test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags) ?
2349 "(is expired)" :
2350 (test_bit(TCMU_CMD_BIT_KEEP_BUF, &cmd->flags) ?
2351 "(is keep buffer)" : ""));
2285 2352
2286 xa_erase(&udev->commands, i);2353 xa_erase(&udev->commands, i);
2287 if (!test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) {2354 if (!test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags) &&
2355 !test_bit(TCMU_CMD_BIT_KEEP_BUF, &cmd->flags)) {
2288 WARN_ON(!cmd->se_cmd);2356 WARN_ON(!cmd->se_cmd);
2289 list_del_init(&cmd->queue_entry);2357 list_del_init(&cmd->queue_entry);
2290 cmd->se_cmd->priv = NULL;2358 cmd->se_cmd->priv = NULL;
@@ -2933,6 +3001,65 @@ static ssize_t tcmu_reset_ring_store(struct config_item *item, const char *page, · 642 unmodified lines
2933}3001}
2934CONFIGFS_ATTR_WO(tcmu_, reset_ring);3002CONFIGFS_ATTR_WO(tcmu_, reset_ring);
2935 3003
3004static ssize_t tcmu_free_kept_buf_store(struct config_item *item, const char *page,
3005 size_t count)
3006{
3007 struct se_device *se_dev = container_of(to_config_group(item),
3008 struct se_device,
3009 dev_action_group);
3010 struct tcmu_dev *udev = TCMU_DEV(se_dev);
3011 struct tcmu_cmd *cmd;
3012 u16 cmd_id;
3013 int ret;
3014
3015 if (!target_dev_configured(&udev->se_dev)) {
3016 pr_err("Device is not configured.\n");
3017 return -EINVAL;
3018 }
3019
3020 ret = kstrtou16(page, 0, &cmd_id);
3021 if (ret < 0)
3022 return ret;
3023
3024 mutex_lock(&udev->cmdr_lock);
3025
3026 {
3027 XA_STATE(xas, &udev->commands, cmd_id);
3028
3029 xas_lock(&xas);
3030 cmd = xas_load(&xas);
3031 if (!cmd) {
3032 pr_err("free_kept_buf: cmd_id %d not found\n", cmd_id);
3033 count = -EINVAL;
3034 xas_unlock(&xas);
3035 goto out_unlock;
3036 }
3037 if (!test_bit(TCMU_CMD_BIT_KEEP_BUF, &cmd->flags)) {
3038 pr_err("free_kept_buf: cmd_id %d was not completed with KEEP_BUF\n",
3039 cmd_id);
3040 count = -EINVAL;
3041 xas_unlock(&xas);
3042 goto out_unlock;
3043 }
3044 xas_store(&xas, NULL);
3045 xas_unlock(&xas);
3046 }
3047
3048 tcmu_cmd_free_data(cmd, cmd->dbi_cnt);
3049 tcmu_free_cmd(cmd);
3050 /*
3051 * We only freed data space, not ring space. Therefore we dont call
3052 * run_tmr_queue, but call run_qfull_queue if tmr_list is empty.
3053 */
3054 if (list_empty(&udev->tmr_queue))
3055 run_qfull_queue(udev, false);
3056
3057out_unlock:
3058 mutex_unlock(&udev->cmdr_lock);
3059 return count;
3060}
3061CONFIGFS_ATTR_WO(tcmu_, free_kept_buf);
3062
2936static struct configfs_attribute *tcmu_attrib_attrs[] = {3063static struct configfs_attribute *tcmu_attrib_attrs[] = {
2937 &tcmu_attr_cmd_time_out,3064 &tcmu_attr_cmd_time_out,
2938 &tcmu_attr_qfull_time_out,3065 &tcmu_attr_qfull_time_out,
@@ -2951,6 +3078,7 @@ static struct configfs_attribute **tcmu_attrs; · 12 unmodified lines
2951static struct configfs_attribute *tcmu_action_attrs[] = {3078static struct configfs_attribute *tcmu_action_attrs[] = {
2952 &tcmu_attr_block_dev,3079 &tcmu_attr_block_dev,
2953 &tcmu_attr_reset_ring,3080 &tcmu_attr_reset_ring,
3081 &tcmu_attr_free_kept_buf,
2954 NULL,3082 NULL,
2955};3083};
2956 3084
include/uapi/linux/target_core_user.h+2−0
@@ -46,6 +46,7 @@ · 45 unmodified lines
46#define TCMU_MAILBOX_FLAG_CAP_OOOC (1 << 0) /* Out-of-order completions */46#define TCMU_MAILBOX_FLAG_CAP_OOOC (1 << 0) /* Out-of-order completions */
47#define TCMU_MAILBOX_FLAG_CAP_READ_LEN (1 << 1) /* Read data length */47#define TCMU_MAILBOX_FLAG_CAP_READ_LEN (1 << 1) /* Read data length */
48#define TCMU_MAILBOX_FLAG_CAP_TMR (1 << 2) /* TMR notifications */48#define TCMU_MAILBOX_FLAG_CAP_TMR (1 << 2) /* TMR notifications */
49#define TCMU_MAILBOX_FLAG_CAP_KEEP_BUF (1<<3) /* Keep buf after cmd completion */
49 50
50struct tcmu_mailbox {51struct tcmu_mailbox {
51 __u16 version;52 __u16 version;
@@ -75,6 +76,7 @@ struct tcmu_cmd_entry_hdr { · 23 unmodified lines
75 __u8 kflags;76 __u8 kflags;
76#define TCMU_UFLAG_UNKNOWN_OP 0x177#define TCMU_UFLAG_UNKNOWN_OP 0x1
77#define TCMU_UFLAG_READ_LEN 0x278#define TCMU_UFLAG_READ_LEN 0x2
79#define TCMU_UFLAG_KEEP_BUF 0x4
78 __u8 uflags;80 __u8 uflags;
79 81
80} __packed;82} __packed;