| 839 | } |
| 840 | |
| 841 | static int cmd_dev_add(char *tgt_type, int *exp_id, unsigned nr_queues, |
| 842 | unsigned depth) |
| 843 | { |
| 844 | const struct ublk_tgt_ops *ops; |
| 845 | struct ublksrv_ctrl_dev_info *info; |
| 846 | struct ublk_dev *dev; |
| 847 | int dev_id = *exp_id; |
| 848 | char ublkb[64]; |
| 849 | int ret; |
| 850 | |
| 851 | ops = ublk_find_tgt(tgt_type); |
| 852 | if (!ops) { |
| 853 | ublk_err("%s: no such tgt type, type %s\n", |
| 854 | __func__, tgt_type); |
| 855 | return -ENODEV; |
| 856 | } |
| 857 | |
| 858 | if (nr_queues > UBLK_MAX_QUEUES || depth > UBLK_QUEUE_DEPTH) { |
| 859 | ublk_err("%s: invalid nr_queues or depth queues %u depth %u\n", |
| 860 | __func__, nr_queues, depth); |
| 861 | return -EINVAL; |
| 862 | } |
| 863 | |
| 864 | dev = ublk_ctrl_init(); |
| 865 | if (!dev) { |
| 866 | ublk_err("%s: can't alloc dev id %d, type %s\n", |
| 867 | __func__, dev_id, tgt_type); |
| 868 | return -ENOMEM; |
| 869 | } |
| 870 | |
| 871 | info = &dev->dev_info; |
| 872 | info->dev_id = dev_id; |
| 873 | info->nr_hw_queues = nr_queues; |
| 874 | info->queue_depth = depth; |
| 875 | dev->tgt.ops = ops; |
| 876 | |
| 877 | ret = ublk_ctrl_add_dev(dev); |
| 878 | if (ret < 0) { |
| 879 | ublk_err("%s: can't add dev id %d, type %s ret %d\n", |
| 880 | __func__, dev_id, tgt_type, ret); |
| 881 | goto fail; |
| 882 | } |
| 883 | |
| 884 | switch (fork()) { |
| 885 | case -1: |
| 886 | goto fail; |
| 887 | case 0: |
| 888 | ublk_start_daemon(dev); |
| 889 | return 0; |
| 890 | } |
| 891 | |
| 892 | /* |
| 893 | * Wait until ublk disk is added, when our daemon is started |
| 894 | * successfully |
| 895 | */ |
| 896 | snprintf(ublkb, sizeof(ublkb), "%s%u", "ublkb", dev->dev_info.dev_id); |
| 897 | ret = wait_ublk_dev(ublkb, IN_CREATE, 3); |
| 898 | if (ret < 0) { |