@@ -666,6 +666,7 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
struct ib_mr *mr;
int ret;
struct ib_device *ib_dev;
+ struct ib_uobject *pd_uobj;
if (out_len < sizeof resp)
return -ENOSPC;
@@ -689,7 +690,8 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
if (IS_ERR(uobj))
return PTR_ERR(uobj);
- pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, file);
+ pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, file,
+ pd_uobj);
if (!pd) {
ret = -EINVAL;
goto err_free;
@@ -759,6 +761,7 @@ ssize_t ib_uverbs_rereg_mr(struct ib_uverbs_file *file,
struct ib_pd *old_pd;
int ret;
struct ib_uobject *uobj;
+ struct ib_uobject *pd_uobj;
if (out_len < sizeof(resp))
return -ENOSPC;
@@ -798,7 +801,7 @@ ssize_t ib_uverbs_rereg_mr(struct ib_uverbs_file *file,
if (cmd.flags & IB_MR_REREG_PD) {
pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle,
- file);
+ file, pd_uobj);
if (!pd) {
ret = -EINVAL;
goto put_uobjs;
@@ -863,6 +866,7 @@ ssize_t ib_uverbs_alloc_mw(struct ib_uverbs_file *file,
struct ib_udata udata;
int ret;
struct ib_device *ib_dev;
+ struct ib_uobject *pd_uobj;
if (out_len < sizeof(resp))
return -ENOSPC;
@@ -874,7 +878,8 @@ ssize_t ib_uverbs_alloc_mw(struct ib_uverbs_file *file,
if (IS_ERR(uobj))
return PTR_ERR(uobj);
- pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, file);
+ pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, file,
+ pd_uobj);
if (!pd) {
ret = -EINVAL;
goto err_free;
@@ -1172,6 +1177,7 @@ ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file,
struct ib_udata udata;
struct ib_cq *cq;
int ret = -EINVAL;
+ struct ib_uobject *cq_uobj;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -1181,7 +1187,8 @@ ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file,
in_len - sizeof(cmd) - sizeof(struct ib_uverbs_cmd_hdr),
out_len - sizeof(resp), file->ucontext);
- cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, file);
+ cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, file,
+ cq_uobj);
if (!cq)
return -EINVAL;
@@ -1241,11 +1248,13 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
struct ib_cq *cq;
struct ib_wc wc;
int ret;
+ struct ib_uobject *cq_uobj;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, file);
+ cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, file,
+ cq_uobj);
if (!cq)
return -EINVAL;
@@ -1287,11 +1296,13 @@ ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file,
{
struct ib_uverbs_req_notify_cq cmd;
struct ib_cq *cq;
+ struct ib_uobject *cq_uobj;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, file);
+ cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, file,
+ cq_uobj);
if (!cq)
return -EINVAL;
@@ -1357,6 +1368,11 @@ static int create_qp(struct ib_uverbs_file *file,
struct ib_rwq_ind_table *ind_tbl = NULL;
bool has_sq = true;
struct ib_device *ib_dev;
+ struct ib_uobject *ind_tbl_uobj = NULL;
+ struct ib_uobject *srq_uobj = NULL;
+ struct ib_uobject *scq_uobj = NULL;
+ struct ib_uobject *rcq_uobj = NULL;
+ struct ib_uobject *pd_uobj = NULL;
if (cmd->qp_type == IB_QPT_RAW_PACKET && !capable(CAP_NET_RAW))
return -EPERM;
@@ -1374,7 +1390,8 @@ static int create_qp(struct ib_uverbs_file *file,
(cmd->comp_mask & IB_UVERBS_CREATE_QP_MASK_IND_TABLE)) {
ind_tbl = uobj_get_obj_read(rwq_ind_table,
UVERBS_OBJECT_RWQ_IND_TBL,
- cmd->rwq_ind_tbl_handle, file);
+ cmd->rwq_ind_tbl_handle, file,
+ ind_tbl_uobj);
if (!ind_tbl) {
ret = -EINVAL;
goto err_put;
@@ -1420,7 +1437,8 @@ static int create_qp(struct ib_uverbs_file *file,
} else {
if (cmd->is_srq) {
srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ,
- cmd->srq_handle, file);
+ cmd->srq_handle, file,
+ srq_uobj);
if (!srq || srq->srq_type == IB_SRQT_XRC) {
ret = -EINVAL;
goto err_put;
@@ -1431,7 +1449,8 @@ static int create_qp(struct ib_uverbs_file *file,
if (cmd->recv_cq_handle != cmd->send_cq_handle) {
rcq = uobj_get_obj_read(
cq, UVERBS_OBJECT_CQ,
- cmd->recv_cq_handle, file);
+ cmd->recv_cq_handle, file,
+ rcq_uobj);
if (!rcq) {
ret = -EINVAL;
goto err_put;
@@ -1442,11 +1461,12 @@ static int create_qp(struct ib_uverbs_file *file,
if (has_sq)
scq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ,
- cmd->send_cq_handle, file);
+ cmd->send_cq_handle, file,
+ scq_uobj);
if (!ind_tbl)
rcq = rcq ?: scq;
pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd->pd_handle,
- file);
+ file, pd_uobj);
if (!pd || (!scq && has_sq)) {
ret = -EINVAL;
goto err_put;
@@ -1831,6 +1851,7 @@ ssize_t ib_uverbs_query_qp(struct ib_uverbs_file *file,
struct ib_qp_attr *attr;
struct ib_qp_init_attr *init_attr;
int ret;
+ struct ib_uobject *qp_uobj;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -1842,7 +1863,8 @@ ssize_t ib_uverbs_query_qp(struct ib_uverbs_file *file,
goto out;
}
- qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, file);
+ qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, file,
+ qp_uobj);
if (!qp) {
ret = -EINVAL;
goto out;
@@ -1942,12 +1964,14 @@ static int modify_qp(struct ib_uverbs_file *file,
struct ib_qp_attr *attr;
struct ib_qp *qp;
int ret;
+ struct ib_uobject *qp_uobj;
attr = kzalloc(sizeof(*attr), GFP_KERNEL);
if (!attr)
return -ENOMEM;
- qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd->base.qp_handle, file);
+ qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd->base.qp_handle, file,
+ qp_uobj);
if (!qp) {
ret = -EINVAL;
goto out;
@@ -2185,6 +2209,8 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
int is_ud;
ssize_t ret = -EINVAL;
size_t next_size;
+ struct ib_uobject *qp_uobj;
+ struct ib_uobject *ah_uobj;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -2200,7 +2226,8 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
if (!user_wr)
return -ENOMEM;
- qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, file);
+ qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, file,
+ qp_uobj);
if (!qp)
goto out;
@@ -2237,7 +2264,8 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
}
ud->ah = uobj_get_obj_read(ah, UVERBS_OBJECT_AH,
- user_wr->wr.ud.ah, file);
+ user_wr->wr.ud.ah, file,
+ ah_uobj);
if (!ud->ah) {
kfree(ud);
ret = -EINVAL;
@@ -2461,6 +2489,7 @@ ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file,
const struct ib_recv_wr *bad_wr;
struct ib_qp *qp;
ssize_t ret = -EINVAL;
+ struct ib_uobject *qp_uobj;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -2471,7 +2500,8 @@ ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file,
if (IS_ERR(wr))
return PTR_ERR(wr);
- qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, file);
+ qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, file,
+ qp_uobj);
if (!qp)
goto out;
@@ -2510,6 +2540,7 @@ ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file,
const struct ib_recv_wr *bad_wr;
struct ib_srq *srq;
ssize_t ret = -EINVAL;
+ struct ib_uobject *srq_uobj;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -2520,7 +2551,8 @@ ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file,
if (IS_ERR(wr))
return PTR_ERR(wr);
- srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, file);
+ srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, file,
+ srq_uobj);
if (!srq)
goto out;
@@ -2563,6 +2595,7 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
int ret;
struct ib_udata udata;
struct ib_device *ib_dev;
+ struct ib_uobject *pd_uobj;
if (out_len < sizeof resp)
return -ENOSPC;
@@ -2584,7 +2617,8 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
goto err;
}
- pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, file);
+ pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, file,
+ pd_uobj);
if (!pd) {
ret = -EINVAL;
goto err;
@@ -2660,11 +2694,13 @@ ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
struct ib_uqp_object *obj;
struct ib_uverbs_mcast_entry *mcast;
int ret;
+ struct ib_uobject *qp_uobj;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, file);
+ qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, file,
+ qp_uobj);
if (!qp)
return -EINVAL;
@@ -2710,11 +2746,13 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
struct ib_uverbs_mcast_entry *mcast;
int ret = -EINVAL;
bool found = false;
+ struct ib_uobject *qp_uobj;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, file);
+ qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, file,
+ qp_uobj);
if (!qp)
return -EINVAL;
@@ -2824,6 +2862,9 @@ static int kern_spec_to_ib_spec_action(struct ib_uverbs_file *ufile,
union ib_flow_spec *ib_spec,
struct ib_uflow_resources *uflow_res)
{
+ struct ib_uobject *flow_act_uobj;
+ struct ib_uobject *cnt_uobj;
+
ib_spec->type = kern_spec->type;
switch (ib_spec->type) {
case IB_FLOW_SPEC_ACTION_TAG:
@@ -2848,7 +2889,8 @@ static int kern_spec_to_ib_spec_action(struct ib_uverbs_file *ufile,
ib_spec->action.act = uobj_get_obj_read(flow_action,
UVERBS_OBJECT_FLOW_ACTION,
kern_spec->action.handle,
- ufile);
+ ufile,
+ flow_act_uobj);
if (!ib_spec->action.act)
return -EINVAL;
ib_spec->action.size =
@@ -2866,7 +2908,8 @@ static int kern_spec_to_ib_spec_action(struct ib_uverbs_file *ufile,
uobj_get_obj_read(counters,
UVERBS_OBJECT_COUNTERS,
kern_spec->flow_count.handle,
- ufile);
+ ufile,
+ cnt_uobj);
if (!ib_spec->flow_count.counters)
return -EINVAL;
ib_spec->flow_count.size =
@@ -3077,6 +3120,8 @@ int ib_uverbs_ex_create_wq(struct ib_uverbs_file *file,
size_t required_cmd_sz;
size_t required_resp_len;
struct ib_device *ib_dev;
+ struct ib_uobject *pd_uobj;
+ struct ib_uobject *cq_uobj;
required_cmd_sz = offsetof(typeof(cmd), max_sge) + sizeof(cmd.max_sge);
required_resp_len = offsetof(typeof(resp), wqn) + sizeof(resp.wqn);
@@ -3104,13 +3149,15 @@ int ib_uverbs_ex_create_wq(struct ib_uverbs_file *file,
if (IS_ERR(obj))
return PTR_ERR(obj);
- pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, file);
+ pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, file,
+ pd_uobj);
if (!pd) {
err = -EINVAL;
goto err_uobj;
}
- cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, file);
+ cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, file,
+ cq_uobj);
if (!cq) {
err = -EINVAL;
goto err_put_pd;
@@ -3233,6 +3280,7 @@ int ib_uverbs_ex_modify_wq(struct ib_uverbs_file *file,
struct ib_wq_attr wq_attr = {};
size_t required_cmd_sz;
int ret;
+ struct ib_uobject *wq_uobj;
required_cmd_sz = offsetof(typeof(cmd), curr_wq_state) + sizeof(cmd.curr_wq_state);
if (ucore->inlen < required_cmd_sz)
@@ -3253,7 +3301,8 @@ int ib_uverbs_ex_modify_wq(struct ib_uverbs_file *file,
if (cmd.attr_mask > (IB_WQ_STATE | IB_WQ_CUR_STATE | IB_WQ_FLAGS))
return -EINVAL;
- wq = uobj_get_obj_read(wq, UVERBS_OBJECT_WQ, cmd.wq_handle, file);
+ wq = uobj_get_obj_read(wq, UVERBS_OBJECT_WQ, cmd.wq_handle, file,
+ wq_uobj);
if (!wq)
return -EINVAL;
@@ -3292,6 +3341,7 @@ int ib_uverbs_ex_create_rwq_ind_table(struct ib_uverbs_file *file,
size_t required_cmd_sz_header;
size_t required_resp_len;
struct ib_device *ib_dev;
+ struct ib_uobject **wqs_uobj = NULL;
required_cmd_sz_header = offsetof(typeof(cmd), log_ind_tbl_size) + sizeof(cmd.log_ind_tbl_size);
required_resp_len = offsetof(typeof(resp), ind_tbl_num) + sizeof(resp.ind_tbl_num);
@@ -3345,10 +3395,17 @@ int ib_uverbs_ex_create_rwq_ind_table(struct ib_uverbs_file *file,
goto err_free;
}
+ wqs_uobj = kcalloc(num_wq_handles, sizeof(*wqs_uobj), GFP_KERNEL);
+ if (!wqs_uobj) {
+ err = -ENOMEM;
+ goto err_free;
+ }
+
for (num_read_wqs = 0; num_read_wqs < num_wq_handles;
num_read_wqs++) {
wq = uobj_get_obj_read(wq, UVERBS_OBJECT_WQ,
- wqs_handles[num_read_wqs], file);
+ wqs_handles[num_read_wqs], file,
+ wqs_uobj[num_read_wqs]);
if (!wq) {
err = -EINVAL;
goto put_wqs;
@@ -3401,6 +3458,8 @@ int ib_uverbs_ex_create_rwq_ind_table(struct ib_uverbs_file *file,
for (j = 0; j < num_read_wqs; j++)
uobj_put_obj_read(wqs[j]);
+ kfree(wqs_uobj);
+
return uobj_alloc_commit(uobj, 0);
err_copy:
@@ -3412,6 +3471,7 @@ int ib_uverbs_ex_create_rwq_ind_table(struct ib_uverbs_file *file,
uobj_put_obj_read(wqs[j]);
err_free:
kfree(wqs_handles);
+ kfree(wqs_uobj);
kfree(wqs);
return err;
}
@@ -3462,6 +3522,7 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
void *ib_spec;
int i;
struct ib_device *ib_dev;
+ struct ib_uobject *qp_uobj;
if (ucore->inlen < sizeof(cmd))
return -EINVAL;
@@ -3523,7 +3584,8 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
goto err_free_attr;
}
- qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, file);
+ qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, file,
+ qp_uobj);
if (!qp) {
err = -EINVAL;
goto err_uobj;
@@ -3656,6 +3718,8 @@ static int __uverbs_create_xsrq(struct ib_uverbs_file *file,
struct ib_srq_init_attr attr;
int ret;
struct ib_device *ib_dev;
+ struct ib_uobject *cq_uobj;
+ struct ib_uobject *pd_uobj;
obj = (struct ib_usrq_object *)uobj_alloc(UVERBS_OBJECT_SRQ, file,
&ib_dev);
@@ -3685,14 +3749,16 @@ static int __uverbs_create_xsrq(struct ib_uverbs_file *file,
if (ib_srq_has_cq(cmd->srq_type)) {
attr.ext.cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ,
- cmd->cq_handle, file);
+ cmd->cq_handle, file,
+ cq_uobj);
if (!attr.ext.cq) {
ret = -EINVAL;
goto err_put_xrcd;
}
}
- pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd->pd_handle, file);
+ pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd->pd_handle, file,
+ pd_uobj);
if (!pd) {
ret = -EINVAL;
goto err_put_cq;
@@ -3852,6 +3918,7 @@ ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file,
struct ib_srq *srq;
struct ib_srq_attr attr;
int ret;
+ struct ib_uobject *srq_uobj;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -3859,7 +3926,8 @@ ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file,
ib_uverbs_init_udata(&udata, buf + sizeof cmd, NULL, in_len - sizeof cmd,
out_len, file->ucontext);
- srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, file);
+ srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, file,
+ srq_uobj);
if (!srq)
return -EINVAL;
@@ -3882,6 +3950,7 @@ ssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file,
struct ib_srq_attr attr;
struct ib_srq *srq;
int ret;
+ struct ib_uobject *srq_uobj;
if (out_len < sizeof resp)
return -ENOSPC;
@@ -3889,7 +3958,8 @@ ssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file,
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, file);
+ srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, file,
+ srq_uobj);
if (!srq)
return -EINVAL;
@@ -4075,6 +4145,7 @@ int ib_uverbs_ex_modify_cq(struct ib_uverbs_file *file,
struct ib_cq *cq;
size_t required_cmd_sz;
int ret;
+ struct ib_uobject *cq_uobj;
required_cmd_sz = offsetof(typeof(cmd), reserved) +
sizeof(cmd.reserved);
@@ -4097,7 +4168,8 @@ int ib_uverbs_ex_modify_cq(struct ib_uverbs_file *file,
if (cmd.attr_mask > IB_CQ_MODERATE)
return -EOPNOTSUPP;
- cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, file);
+ cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, file,
+ cq_uobj);
if (!cq)
return -EINVAL;
@@ -72,9 +72,9 @@ static inline void *_uobj_get_obj_read(struct ib_uobject *uobj)
return NULL;
return uobj->object;
}
-#define uobj_get_obj_read(_object, _type, _id, _ufile) \
+#define uobj_get_obj_read(_object, _type, _id, _ufile, _uobject) \
((struct ib_##_object *)_uobj_get_obj_read( \
- uobj_get_read(_type, _id, _ufile)))
+ (_uobject = uobj_get_read(_type, _id, _ufile))))
#define uobj_get_write(_type, _id, _ufile) \
rdma_lookup_get_uobject(uobj_get_type(_ufile, _type), _ufile, \
prepare the code for shared ib_x model. uobj_put_obj_read rely on ib_x uobject pointer. having single pointer in ib_x object is not aligned with future shared ib_x model. in future shared ib_x model each ib_x object can belong to 1 or more ib_uobject. thus the ib_uobject used in the macro cannot come from the ib_x object. Signed-off-by: Shamir Rabinovitch <shamir.rabinovitch@oracle.com> --- drivers/infiniband/core/uverbs_cmd.c | 136 ++++++++++++++++++++------- include/rdma/uverbs_std_types.h | 4 +- 2 files changed, 106 insertions(+), 34 deletions(-)