RDMA/ucma: Allow user space to set service type
Sean Hefty [Wed, 8 Aug 2007 22:51:13 +0000 (15:51 -0700)]
Export the ability to set the type of service to user space.  Model
the interface after setsockopt.

Signed-off-by: Sean Hefty <sean.hefty@intel.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>

drivers/infiniband/core/ucma.c
include/rdma/rdma_user_cm.h

index 53b4c94..90d675a 100644 (file)
@@ -792,6 +792,78 @@ out:
        return ret;
 }
 
+static int ucma_set_option_id(struct ucma_context *ctx, int optname,
+                             void *optval, size_t optlen)
+{
+       int ret = 0;
+
+       switch (optname) {
+       case RDMA_OPTION_ID_TOS:
+               if (optlen != sizeof(u8)) {
+                       ret = -EINVAL;
+                       break;
+               }
+               rdma_set_service_type(ctx->cm_id, *((u8 *) optval));
+               break;
+       default:
+               ret = -ENOSYS;
+       }
+
+       return ret;
+}
+
+static int ucma_set_option_level(struct ucma_context *ctx, int level,
+                                int optname, void *optval, size_t optlen)
+{
+       int ret;
+
+       switch (level) {
+       case RDMA_OPTION_ID:
+               ret = ucma_set_option_id(ctx, optname, optval, optlen);
+               break;
+       default:
+               ret = -ENOSYS;
+       }
+
+       return ret;
+}
+
+static ssize_t ucma_set_option(struct ucma_file *file, const char __user *inbuf,
+                              int in_len, int out_len)
+{
+       struct rdma_ucm_set_option cmd;
+       struct ucma_context *ctx;
+       void *optval;
+       int ret;
+
+       if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+               return -EFAULT;
+
+       ctx = ucma_get_ctx(file, cmd.id);
+       if (IS_ERR(ctx))
+               return PTR_ERR(ctx);
+
+       optval = kmalloc(cmd.optlen, GFP_KERNEL);
+       if (!optval) {
+               ret = -ENOMEM;
+               goto out1;
+       }
+
+       if (copy_from_user(optval, (void __user *) (unsigned long) cmd.optval,
+                          cmd.optlen)) {
+               ret = -EFAULT;
+               goto out2;
+       }
+
+       ret = ucma_set_option_level(ctx, cmd.level, cmd.optname, optval,
+                                   cmd.optlen);
+out2:
+       kfree(optval);
+out1:
+       ucma_put_ctx(ctx);
+       return ret;
+}
+
 static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf,
                           int in_len, int out_len)
 {
@@ -936,7 +1008,7 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
        [RDMA_USER_CM_CMD_INIT_QP_ATTR] = ucma_init_qp_attr,
        [RDMA_USER_CM_CMD_GET_EVENT]    = ucma_get_event,
        [RDMA_USER_CM_CMD_GET_OPTION]   = NULL,
-       [RDMA_USER_CM_CMD_SET_OPTION]   = NULL,
+       [RDMA_USER_CM_CMD_SET_OPTION]   = ucma_set_option,
        [RDMA_USER_CM_CMD_NOTIFY]       = ucma_notify,
        [RDMA_USER_CM_CMD_JOIN_MCAST]   = ucma_join_multicast,
        [RDMA_USER_CM_CMD_LEAVE_MCAST]  = ucma_leave_multicast,
index f632b0c..9749c1b 100644 (file)
@@ -212,4 +212,22 @@ struct rdma_ucm_event_resp {
        } param;
 };
 
+/* Option levels */
+enum {
+       RDMA_OPTION_ID          = 0
+};
+
+/* Option details */
+enum {
+       RDMA_OPTION_ID_TOS      = 0
+};
+
+struct rdma_ucm_set_option {
+       __u64 optval;
+       __u32 id;
+       __u32 level;
+       __u32 optname;
+       __u32 optlen;
+};
+
 #endif /* RDMA_USER_CM_H */