int lwt_lookup_string (int *size, char *knl_ptr, char *user_ptr, int user_size) { int maxsize = 128; /* knl_ptr was retrieved from an LWT snapshot and the caller wants to * turn it into a string. NB we can crash with an access violation * trying to determine the string length, so we're trusting our * caller... */ if (!cfs_capable(CFS_CAP_SYS_ADMIN)) return (-EPERM); if (user_size > 0 && maxsize > user_size) maxsize = user_size; *size = strnlen (knl_ptr, maxsize - 1) + 1; if (user_ptr != NULL) { if (user_size < 4) return (-EINVAL); if (cfs_copy_to_user (user_ptr, knl_ptr, *size)) return (-EFAULT); /* Did I truncate the string? */ if (knl_ptr[*size - 1] != 0) cfs_copy_to_user (user_ptr + *size - 4, "...", 4); } return (0); }
int LL_PROC_PROTO(proc_alloc_fail_rate) { int rc = 0; DECLARE_LL_PROC_PPOS_DECL; if (!table->data || !table->maxlen || !*lenp || (*ppos && !write)) { *lenp = 0; return 0; } if (write) { rc = lprocfs_write_frac_helper(buffer, *lenp, (unsigned int*)table->data, OBD_ALLOC_FAIL_MULT); } else { char buf[21]; int len; len = lprocfs_read_frac_helper(buf, 21, *(unsigned int*)table->data, OBD_ALLOC_FAIL_MULT); if (len > *lenp) len = *lenp; buf[len] = '\0'; if (cfs_copy_to_user(buffer, buf, len)) return -EFAULT; *lenp = len; } *ppos += *lenp; return rc; }
int LL_PROC_PROTO(proc_max_dirty_pages_in_mb) { int rc = 0; DECLARE_LL_PROC_PPOS_DECL; if (!table->data || !table->maxlen || !*lenp || (*ppos && !write)) { *lenp = 0; return 0; } if (write) { rc = lprocfs_write_frac_helper(buffer, *lenp, (unsigned int*)table->data, 1 << (20 - CFS_PAGE_SHIFT)); /* Don't allow them to let dirty pages exceed 90% of system * memory and set a hard minimum of 4MB. */ if (obd_max_dirty_pages > ((cfs_num_physpages / 10) * 9)) { CERROR("Refusing to set max dirty pages to %u, which " "is more than 90%% of available RAM; setting " "to %lu\n", obd_max_dirty_pages, ((cfs_num_physpages / 10) * 9)); obd_max_dirty_pages = ((cfs_num_physpages / 10) * 9); } else if (obd_max_dirty_pages < 4 << (20 - CFS_PAGE_SHIFT)) { obd_max_dirty_pages = 4 << (20 - CFS_PAGE_SHIFT); } } else { char buf[21]; int len; len = lprocfs_read_frac_helper(buf, sizeof(buf), *(unsigned int*)table->data, 1 << (20 - CFS_PAGE_SHIFT)); if (len > *lenp) len = *lenp; buf[len] = '\0'; if (cfs_copy_to_user(buffer, buf, len)) return -EFAULT; *lenp = len; } *ppos += *lenp; return rc; }
int lwt_snapshot (cfs_cycles_t *now, int *ncpu, int *total_size, void *user_ptr, int user_size) { const int events_per_page = CFS_PAGE_SIZE / sizeof(lwt_event_t); const int bytes_per_page = events_per_page * sizeof(lwt_event_t); lwt_page_t *p; int i; int j; if (!cfs_capable(CFS_CAP_SYS_ADMIN)) return (-EPERM); *ncpu = cfs_num_online_cpus(); *total_size = cfs_num_online_cpus() * lwt_pages_per_cpu * bytes_per_page; *now = get_cycles(); if (user_ptr == NULL) return (0); for (i = 0; i < cfs_num_online_cpus(); i++) { p = lwt_cpus[i].lwtc_current_page; if (p == NULL) return (-ENODATA); for (j = 0; j < lwt_pages_per_cpu; j++) { if (cfs_copy_to_user(user_ptr, p->lwtp_events, bytes_per_page)) return (-EFAULT); user_ptr = ((char *)user_ptr) + bytes_per_page; p = cfs_list_entry(p->lwtp_list.next, lwt_page_t, lwtp_list); } } return (0); }
int LL_PROC_PROTO(proc_pages_max) { char buf[22]; int len; DECLARE_LL_PROC_PPOS_DECL; if (!*lenp || (*ppos && !write)) { *lenp = 0; return 0; } if (write) return -EINVAL; len = snprintf(buf, sizeof(buf), LPU64"\n", obd_pages_max()); if (len > *lenp) len = *lenp; buf[len] = '\0'; if (cfs_copy_to_user(buffer, buf, len)) return -EFAULT; *lenp = len; *ppos += *lenp; return 0; }
/* Retrieve object striping information. * * @lump is a pointer to an in-core struct with lmm_ost_count indicating * the maximum number of OST indices which will fit in the user buffer. * lmm_magic must be LOV_USER_MAGIC. */ int lov_getstripe(struct obd_export *exp, struct lov_stripe_md *lsm, struct lov_user_md *lump) { /* * XXX huge struct allocated on stack. */ /* we use lov_user_md_v3 because it is larger than lov_user_md_v1 */ struct lov_user_md_v3 lum; struct lov_mds_md *lmmk = NULL; int rc, lmm_size; int lum_size; mm_segment_t seg; ENTRY; if (!lsm) RETURN(-ENODATA); /* * "Switch to kernel segment" to allow copying from kernel space by * copy_{to,from}_user(). */ seg = get_fs(); set_fs(KERNEL_DS); /* we only need the header part from user space to get lmm_magic and * lmm_stripe_count, (the header part is common to v1 and v3) */ lum_size = sizeof(struct lov_user_md_v1); if (cfs_copy_from_user(&lum, lump, lum_size)) GOTO(out_set, rc = -EFAULT); else if ((lum.lmm_magic != LOV_USER_MAGIC) && (lum.lmm_magic != LOV_USER_MAGIC_V3)) GOTO(out_set, rc = -EINVAL); if (lum.lmm_stripe_count && (lum.lmm_stripe_count < lsm->lsm_stripe_count)) { /* Return right size of stripe to user */ lum.lmm_stripe_count = lsm->lsm_stripe_count; rc = cfs_copy_to_user(lump, &lum, lum_size); GOTO(out_set, rc = -EOVERFLOW); } rc = lov_packmd(exp, &lmmk, lsm); if (rc < 0) GOTO(out_set, rc); lmm_size = rc; rc = 0; /* FIXME: Bug 1185 - copy fields properly when structs change */ /* struct lov_user_md_v3 and struct lov_mds_md_v3 must be the same */ CLASSERT(sizeof(lum) == sizeof(struct lov_mds_md_v3)); CLASSERT(sizeof lum.lmm_objects[0] == sizeof lmmk->lmm_objects[0]); if ((cpu_to_le32(LOV_MAGIC) != LOV_MAGIC) && ((lmmk->lmm_magic == cpu_to_le32(LOV_MAGIC_V1)) || (lmmk->lmm_magic == cpu_to_le32(LOV_MAGIC_V3)))) { lustre_swab_lov_mds_md(lmmk); lustre_swab_lov_user_md_objects( (struct lov_user_ost_data*)lmmk->lmm_objects, lmmk->lmm_stripe_count); } if (lum.lmm_magic == LOV_USER_MAGIC) { /* User request for v1, we need skip lmm_pool_name */ if (lmmk->lmm_magic == LOV_MAGIC_V3) { memmove((char*)(&lmmk->lmm_stripe_count) + sizeof(lmmk->lmm_stripe_count), ((struct lov_mds_md_v3*)lmmk)->lmm_objects, lmmk->lmm_stripe_count * sizeof(struct lov_ost_data_v1)); lmm_size -= LOV_MAXPOOLNAME; } } else { /* if v3 we just have to update the lum_size */ lum_size = sizeof(struct lov_user_md_v3); } /* User wasn't expecting this many OST entries */ if (lum.lmm_stripe_count == 0) lmm_size = lum_size; else if (lum.lmm_stripe_count < lmmk->lmm_stripe_count) GOTO(out_set, rc = -EOVERFLOW); /* * Have a difference between lov_mds_md & lov_user_md. * So we have to re-order the data before copy to user. */ lum.lmm_stripe_count = lmmk->lmm_stripe_count; ((struct lov_user_md*)lmmk)->lmm_stripe_offset = 0; ((struct lov_user_md*)lmmk)->lmm_stripe_count = lum.lmm_stripe_count; if (cfs_copy_to_user(lump, lmmk, lmm_size)) rc = -EFAULT; obd_free_diskmd(exp, &lmmk); out_set: set_fs(seg); RETURN(rc); }
int lstcon_ioctl_entry(unsigned int cmd, struct libcfs_ioctl_data *data) { char *buf; int opc = data->ioc_u32[0]; int rc; if (cmd != IOC_LIBCFS_LNETST) return -EINVAL; if (data->ioc_plen1 > CFS_PAGE_SIZE) return -EINVAL; LIBCFS_ALLOC(buf, data->ioc_plen1); if (buf == NULL) return -ENOMEM; /* copy in parameter */ if (cfs_copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) { LIBCFS_FREE(buf, data->ioc_plen1); return -EFAULT; } cfs_mutex_down(&console_session.ses_mutex); console_session.ses_laststamp = cfs_time_current_sec(); if (console_session.ses_shutdown) { rc = -ESHUTDOWN; goto out; } if (console_session.ses_expired) lstcon_session_end(); if (opc != LSTIO_SESSION_NEW && console_session.ses_state == LST_SESSION_NONE) { CDEBUG(D_NET, "LST no active session\n"); rc = -ESRCH; goto out; } memset(&console_session.ses_trans_stat, 0, sizeof(lstcon_trans_stat_t)); switch (opc) { case LSTIO_SESSION_NEW: rc = lst_session_new_ioctl((lstio_session_new_args_t *)buf); break; case LSTIO_SESSION_END: rc = lst_session_end_ioctl((lstio_session_end_args_t *)buf); break; case LSTIO_SESSION_INFO: rc = lst_session_info_ioctl((lstio_session_info_args_t *)buf); break; case LSTIO_DEBUG: rc = lst_debug_ioctl((lstio_debug_args_t *)buf); break; case LSTIO_GROUP_ADD: rc = lst_group_add_ioctl((lstio_group_add_args_t *)buf); break; case LSTIO_GROUP_DEL: rc = lst_group_del_ioctl((lstio_group_del_args_t *)buf); break; case LSTIO_GROUP_UPDATE: rc = lst_group_update_ioctl((lstio_group_update_args_t *)buf); break; case LSTIO_NODES_ADD: rc = lst_nodes_add_ioctl((lstio_group_nodes_args_t *)buf); break; case LSTIO_GROUP_LIST: rc = lst_group_list_ioctl((lstio_group_list_args_t *)buf); break; case LSTIO_GROUP_INFO: rc = lst_group_info_ioctl((lstio_group_info_args_t *)buf); break; case LSTIO_BATCH_ADD: rc = lst_batch_add_ioctl((lstio_batch_add_args_t *)buf); break; case LSTIO_BATCH_START: rc = lst_batch_run_ioctl((lstio_batch_run_args_t *)buf); break; case LSTIO_BATCH_STOP: rc = lst_batch_stop_ioctl((lstio_batch_stop_args_t *)buf); break; case LSTIO_BATCH_QUERY: rc = lst_batch_query_ioctl((lstio_batch_query_args_t *)buf); break; case LSTIO_BATCH_LIST: rc = lst_batch_list_ioctl((lstio_batch_list_args_t *)buf); break; case LSTIO_BATCH_INFO: rc = lst_batch_info_ioctl((lstio_batch_info_args_t *)buf); break; case LSTIO_TEST_ADD: rc = lst_test_add_ioctl((lstio_test_args_t *)buf); break; case LSTIO_STAT_QUERY: rc = lst_stat_query_ioctl((lstio_stat_args_t *)buf); break; default: rc = -EINVAL; } if (cfs_copy_to_user(data->ioc_pbuf2, &console_session.ses_trans_stat, sizeof(lstcon_trans_stat_t))) rc = -EFAULT; out: cfs_mutex_up(&console_session.ses_mutex); LIBCFS_FREE(buf, data->ioc_plen1); return rc; }
int lst_test_add_ioctl(lstio_test_args_t *args) { char *name; char *srcgrp = NULL; char *dstgrp = NULL; void *param = NULL; int ret = 0; int rc = -ENOMEM; if (args->lstio_tes_resultp == NULL || args->lstio_tes_retp == NULL || args->lstio_tes_bat_name == NULL || /* no specified batch */ args->lstio_tes_bat_nmlen <= 0 || args->lstio_tes_bat_nmlen > LST_NAME_SIZE || args->lstio_tes_sgrp_name == NULL || /* no source group */ args->lstio_tes_sgrp_nmlen <= 0 || args->lstio_tes_sgrp_nmlen > LST_NAME_SIZE || args->lstio_tes_dgrp_name == NULL || /* no target group */ args->lstio_tes_dgrp_nmlen <= 0 || args->lstio_tes_dgrp_nmlen > LST_NAME_SIZE) return -EINVAL; /* have parameter, check if parameter length is valid */ if (args->lstio_tes_param != NULL && (args->lstio_tes_param_len <= 0 || args->lstio_tes_param_len > CFS_PAGE_SIZE - sizeof(lstcon_test_t))) return -EINVAL; LIBCFS_ALLOC(name, args->lstio_tes_bat_nmlen + 1); if (name == NULL) return rc; LIBCFS_ALLOC(srcgrp, args->lstio_tes_sgrp_nmlen + 1); if (srcgrp == NULL) goto out; LIBCFS_ALLOC(dstgrp, args->lstio_tes_dgrp_nmlen + 1); if (srcgrp == NULL) goto out; if (args->lstio_tes_param != NULL) { LIBCFS_ALLOC(param, args->lstio_tes_param_len); if (param == NULL) goto out; } rc = -EFAULT; if (cfs_copy_from_user(name, args->lstio_tes_bat_name, args->lstio_tes_bat_nmlen) || cfs_copy_from_user(srcgrp, args->lstio_tes_sgrp_name, args->lstio_tes_sgrp_nmlen) || cfs_copy_from_user(dstgrp, args->lstio_tes_dgrp_name, args->lstio_tes_dgrp_nmlen) || cfs_copy_from_user(param, args->lstio_tes_param, args->lstio_tes_param_len)) goto out; rc = lstcon_test_add(name, args->lstio_tes_type, args->lstio_tes_loop, args->lstio_tes_concur, args->lstio_tes_dist, args->lstio_tes_span, srcgrp, dstgrp, param, args->lstio_tes_param_len, &ret, args->lstio_tes_resultp); if (ret != 0) rc = (cfs_copy_to_user(args->lstio_tes_retp, &ret, sizeof(ret))) ? -EFAULT : 0; out: if (name != NULL) LIBCFS_FREE(name, args->lstio_tes_bat_nmlen + 1); if (srcgrp != NULL) LIBCFS_FREE(srcgrp, args->lstio_tes_sgrp_nmlen + 1); if (dstgrp != NULL) LIBCFS_FREE(dstgrp, args->lstio_tes_dgrp_nmlen + 1); if (param != NULL) LIBCFS_FREE(param, args->lstio_tes_param_len); return rc; }
int lst_batch_info_ioctl(lstio_batch_info_args_t *args) { char *name; int rc; int index; int ndent; if (args->lstio_bat_key != console_session.ses_key) return -EACCES; if (args->lstio_bat_namep == NULL || /* batch name */ args->lstio_bat_nmlen <= 0 || args->lstio_bat_nmlen > LST_NAME_SIZE) return -EINVAL; if (args->lstio_bat_entp == NULL && /* output: batch entry */ args->lstio_bat_dentsp == NULL) /* output: node entry */ return -EINVAL; if (args->lstio_bat_dentsp != NULL) { /* have node entry */ if (args->lstio_bat_idxp == NULL || /* node index */ args->lstio_bat_ndentp == NULL) /* # of node entry */ return -EINVAL; if (cfs_copy_from_user(&index, args->lstio_bat_idxp, sizeof(index)) || cfs_copy_from_user(&ndent, args->lstio_bat_ndentp, sizeof(ndent))) return -EFAULT; if (ndent <= 0 || index < 0) return -EINVAL; } LIBCFS_ALLOC(name, args->lstio_bat_nmlen + 1); if (name == NULL) return -ENOMEM; if (cfs_copy_from_user(name, args->lstio_bat_namep, args->lstio_bat_nmlen)) { LIBCFS_FREE(name, args->lstio_bat_nmlen + 1); return -EFAULT; } name[args->lstio_bat_nmlen] = 0; rc = lstcon_batch_info(name, args->lstio_bat_entp, args->lstio_bat_server, args->lstio_bat_testidx, &index, &ndent, args->lstio_bat_dentsp); LIBCFS_FREE(name, args->lstio_bat_nmlen + 1); if (rc != 0) return rc; if (args->lstio_bat_dentsp != NULL && (cfs_copy_to_user(args->lstio_bat_idxp, &index, sizeof(index)) || cfs_copy_to_user(args->lstio_bat_ndentp, &ndent, sizeof(ndent)))) rc = -EFAULT; return rc; }
int gss_do_ctx_init_rpc(__user char *buffer, unsigned long count) { struct obd_import *imp; struct ptlrpc_request *req; struct lgssd_ioctl_param param; struct obd_device *obd; char obdname[64]; long lsize; int rc; if (count != sizeof(param)) { CERROR("ioctl size %lu, expect %lu, please check lgss_keyring " "version\n", count, (unsigned long) sizeof(param)); RETURN(-EINVAL); } if (cfs_copy_from_user(¶m, buffer, sizeof(param))) { CERROR("failed copy data from lgssd\n"); RETURN(-EFAULT); } if (param.version != GSSD_INTERFACE_VERSION) { CERROR("gssd interface version %d (expect %d)\n", param.version, GSSD_INTERFACE_VERSION); RETURN(-EINVAL); } /* take name */ if (strncpy_from_user(obdname, param.uuid, sizeof(obdname)) <= 0) { CERROR("Invalid obdname pointer\n"); RETURN(-EFAULT); } obd = class_name2obd(obdname); if (!obd) { CERROR("no such obd %s\n", obdname); RETURN(-EINVAL); } if (unlikely(!obd->obd_set_up)) { CERROR("obd %s not setup\n", obdname); RETURN(-EINVAL); } cfs_spin_lock(&obd->obd_dev_lock); if (obd->obd_stopping) { CERROR("obd %s has stopped\n", obdname); cfs_spin_unlock(&obd->obd_dev_lock); RETURN(-EINVAL); } if (strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) && strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME) && strcmp(obd->obd_type->typ_name, LUSTRE_MGC_NAME)) { CERROR("obd %s is not a client device\n", obdname); cfs_spin_unlock(&obd->obd_dev_lock); RETURN(-EINVAL); } cfs_spin_unlock(&obd->obd_dev_lock); cfs_down_read(&obd->u.cli.cl_sem); if (obd->u.cli.cl_import == NULL) { CERROR("obd %s: import has gone\n", obd->obd_name); cfs_up_read(&obd->u.cli.cl_sem); RETURN(-EINVAL); } imp = class_import_get(obd->u.cli.cl_import); cfs_up_read(&obd->u.cli.cl_sem); if (imp->imp_deactive) { CERROR("import has been deactivated\n"); class_import_put(imp); RETURN(-EINVAL); } req = ptlrpc_request_alloc_pack(imp, &RQF_SEC_CTX, LUSTRE_OBD_VERSION, SEC_CTX_INIT); if (req == NULL) { param.status = -ENOMEM; goto out_copy; } if (req->rq_cli_ctx->cc_sec->ps_id != param.secid) { CWARN("original secid %d, now has changed to %d, " "cancel this negotiation\n", param.secid, req->rq_cli_ctx->cc_sec->ps_id); param.status = -EINVAL; goto out_copy; } /* get token */ rc = ctx_init_pack_request(imp, req, param.lustre_svc, param.uid, param.gid, param.send_token_size, param.send_token); if (rc) { param.status = rc; goto out_copy; } ptlrpc_request_set_replen(req); rc = ptlrpc_queue_wait(req); if (rc) { /* If any _real_ denial be made, we expect server return * -EACCES reply or return success but indicate gss error * inside reply messsage. All other errors are treated as * timeout, caller might try the negotiation repeatedly, * leave recovery decisions to general ptlrpc layer. * * FIXME maybe some other error code shouldn't be treated * as timeout. */ param.status = rc; if (rc != -EACCES) param.status = -ETIMEDOUT; goto out_copy; } LASSERT(req->rq_repdata); lsize = ctx_init_parse_reply(req->rq_repdata, ptlrpc_rep_need_swab(req), param.reply_buf, param.reply_buf_size); if (lsize < 0) { param.status = (int) lsize; goto out_copy; } param.status = 0; param.reply_length = lsize; out_copy: if (cfs_copy_to_user(buffer, ¶m, sizeof(param))) rc = -EFAULT; else rc = 0; class_import_put(imp); ptlrpc_req_finished(req); RETURN(rc); }
static int ctx_init_parse_reply(struct lustre_msg *msg, int swabbed, char __user *outbuf, long outlen) { struct gss_rep_header *ghdr; __u32 obj_len, round_len; __u32 status, effective = 0; if (msg->lm_bufcount != 3) { CERROR("unexpected bufcount %u\n", msg->lm_bufcount); return -EPROTO; } ghdr = (struct gss_rep_header *) gss_swab_header(msg, 0, swabbed); if (ghdr == NULL) { CERROR("unable to extract gss reply header\n"); return -EPROTO; } if (ghdr->gh_version != PTLRPC_GSS_VERSION) { CERROR("invalid gss version %u\n", ghdr->gh_version); return -EPROTO; } if (outlen < (4 + 2) * 4 + cfs_size_round4(ghdr->gh_handle.len) + cfs_size_round4(msg->lm_buflens[2])) { CERROR("output buffer size %ld too small\n", outlen); return -EFAULT; } status = 0; effective = 0; if (cfs_copy_to_user(outbuf, &status, 4)) return -EFAULT; outbuf += 4; if (cfs_copy_to_user(outbuf, &ghdr->gh_major, 4)) return -EFAULT; outbuf += 4; if (cfs_copy_to_user(outbuf, &ghdr->gh_minor, 4)) return -EFAULT; outbuf += 4; if (cfs_copy_to_user(outbuf, &ghdr->gh_seqwin, 4)) return -EFAULT; outbuf += 4; effective += 4 * 4; /* handle */ obj_len = ghdr->gh_handle.len; round_len = (obj_len + 3) & ~ 3; if (cfs_copy_to_user(outbuf, &obj_len, 4)) return -EFAULT; outbuf += 4; if (cfs_copy_to_user(outbuf, (char *) ghdr->gh_handle.data, round_len)) return -EFAULT; outbuf += round_len; effective += 4 + round_len; /* out token */ obj_len = msg->lm_buflens[2]; round_len = (obj_len + 3) & ~ 3; if (cfs_copy_to_user(outbuf, &obj_len, 4)) return -EFAULT; outbuf += 4; if (cfs_copy_to_user(outbuf, lustre_msg_buf(msg, 2, 0), round_len)) return -EFAULT; outbuf += round_len; effective += 4 + round_len; return effective; }