diff options
Diffstat (limited to 'drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c')
-rw-r--r-- | drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c | 1332 |
1 files changed, 0 insertions, 1332 deletions
diff --git a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c deleted file mode 100644 index 36eea50a77e7..000000000000 --- a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c +++ /dev/null @@ -1,1332 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see - * http://www.gnu.org/licenses/gpl-2.0.html - * - * GPL HEADER END - */ -/* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2011, 2015, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - */ -#define DEBUG_SUBSYSTEM S_CLASS - -#include <obd_support.h> -#include <obd.h> -#include <lprocfs_status.h> -#include <uapi/linux/lustre/lustre_idl.h> -#include <lustre_net.h> -#include <obd_class.h> -#include "ptlrpc_internal.h" - -static struct ll_rpc_opcode { - __u32 opcode; - const char *opname; -} ll_rpc_opcode_table[LUSTRE_MAX_OPCODES] = { - { OST_REPLY, "ost_reply" }, - { OST_GETATTR, "ost_getattr" }, - { OST_SETATTR, "ost_setattr" }, - { OST_READ, "ost_read" }, - { OST_WRITE, "ost_write" }, - { OST_CREATE, "ost_create" }, - { OST_DESTROY, "ost_destroy" }, - { OST_GET_INFO, "ost_get_info" }, - { OST_CONNECT, "ost_connect" }, - { OST_DISCONNECT, "ost_disconnect" }, - { OST_PUNCH, "ost_punch" }, - { OST_OPEN, "ost_open" }, - { OST_CLOSE, "ost_close" }, - { OST_STATFS, "ost_statfs" }, - { 14, NULL }, /* formerly OST_SAN_READ */ - { 15, NULL }, /* formerly OST_SAN_WRITE */ - { OST_SYNC, "ost_sync" }, - { OST_SET_INFO, "ost_set_info" }, - { OST_QUOTACHECK, "ost_quotacheck" }, - { OST_QUOTACTL, "ost_quotactl" }, - { OST_QUOTA_ADJUST_QUNIT, "ost_quota_adjust_qunit" }, - { MDS_GETATTR, "mds_getattr" }, - { MDS_GETATTR_NAME, "mds_getattr_lock" }, - { MDS_CLOSE, "mds_close" }, - { MDS_REINT, "mds_reint" }, - { MDS_READPAGE, "mds_readpage" }, - { MDS_CONNECT, "mds_connect" }, - { MDS_DISCONNECT, "mds_disconnect" }, - { MDS_GETSTATUS, "mds_getstatus" }, - { MDS_STATFS, "mds_statfs" }, - { MDS_PIN, "mds_pin" }, - { MDS_UNPIN, "mds_unpin" }, - { MDS_SYNC, "mds_sync" }, - { MDS_DONE_WRITING, "mds_done_writing" }, - { MDS_SET_INFO, "mds_set_info" }, - { MDS_QUOTACHECK, "mds_quotacheck" }, - { MDS_QUOTACTL, "mds_quotactl" }, - { MDS_GETXATTR, "mds_getxattr" }, - { MDS_SETXATTR, "mds_setxattr" }, - { MDS_WRITEPAGE, "mds_writepage" }, - { MDS_IS_SUBDIR, "mds_is_subdir" }, - { MDS_GET_INFO, "mds_get_info" }, - { MDS_HSM_STATE_GET, "mds_hsm_state_get" }, - { MDS_HSM_STATE_SET, "mds_hsm_state_set" }, - { MDS_HSM_ACTION, "mds_hsm_action" }, - { MDS_HSM_PROGRESS, "mds_hsm_progress" }, - { MDS_HSM_REQUEST, "mds_hsm_request" }, - { MDS_HSM_CT_REGISTER, "mds_hsm_ct_register" }, - { MDS_HSM_CT_UNREGISTER, "mds_hsm_ct_unregister" }, - { MDS_SWAP_LAYOUTS, "mds_swap_layouts" }, - { LDLM_ENQUEUE, "ldlm_enqueue" }, - { LDLM_CONVERT, "ldlm_convert" }, - { LDLM_CANCEL, "ldlm_cancel" }, - { LDLM_BL_CALLBACK, "ldlm_bl_callback" }, - { LDLM_CP_CALLBACK, "ldlm_cp_callback" }, - { LDLM_GL_CALLBACK, "ldlm_gl_callback" }, - { LDLM_SET_INFO, "ldlm_set_info" }, - { MGS_CONNECT, "mgs_connect" }, - { MGS_DISCONNECT, "mgs_disconnect" }, - { MGS_EXCEPTION, "mgs_exception" }, - { MGS_TARGET_REG, "mgs_target_reg" }, - { MGS_TARGET_DEL, "mgs_target_del" }, - { MGS_SET_INFO, "mgs_set_info" }, - { MGS_CONFIG_READ, "mgs_config_read" }, - { OBD_PING, "obd_ping" }, - { OBD_LOG_CANCEL, "llog_cancel" }, - { OBD_QC_CALLBACK, "obd_quota_callback" }, - { OBD_IDX_READ, "dt_index_read" }, - { LLOG_ORIGIN_HANDLE_CREATE, "llog_origin_handle_open" }, - { LLOG_ORIGIN_HANDLE_NEXT_BLOCK, "llog_origin_handle_next_block" }, - { LLOG_ORIGIN_HANDLE_READ_HEADER, "llog_origin_handle_read_header" }, - { LLOG_ORIGIN_HANDLE_WRITE_REC, "llog_origin_handle_write_rec" }, - { LLOG_ORIGIN_HANDLE_CLOSE, "llog_origin_handle_close" }, - { LLOG_ORIGIN_CONNECT, "llog_origin_connect" }, - { LLOG_CATINFO, "llog_catinfo" }, - { LLOG_ORIGIN_HANDLE_PREV_BLOCK, "llog_origin_handle_prev_block" }, - { LLOG_ORIGIN_HANDLE_DESTROY, "llog_origin_handle_destroy" }, - { QUOTA_DQACQ, "quota_acquire" }, - { QUOTA_DQREL, "quota_release" }, - { SEQ_QUERY, "seq_query" }, - { SEC_CTX_INIT, "sec_ctx_init" }, - { SEC_CTX_INIT_CONT, "sec_ctx_init_cont" }, - { SEC_CTX_FINI, "sec_ctx_fini" }, - { FLD_QUERY, "fld_query" }, - { FLD_READ, "fld_read" }, -}; - -static struct ll_eopcode { - __u32 opcode; - const char *opname; -} ll_eopcode_table[EXTRA_LAST_OPC] = { - { LDLM_GLIMPSE_ENQUEUE, "ldlm_glimpse_enqueue" }, - { LDLM_PLAIN_ENQUEUE, "ldlm_plain_enqueue" }, - { LDLM_EXTENT_ENQUEUE, "ldlm_extent_enqueue" }, - { LDLM_FLOCK_ENQUEUE, "ldlm_flock_enqueue" }, - { LDLM_IBITS_ENQUEUE, "ldlm_ibits_enqueue" }, - { MDS_REINT_SETATTR, "mds_reint_setattr" }, - { MDS_REINT_CREATE, "mds_reint_create" }, - { MDS_REINT_LINK, "mds_reint_link" }, - { MDS_REINT_UNLINK, "mds_reint_unlink" }, - { MDS_REINT_RENAME, "mds_reint_rename" }, - { MDS_REINT_OPEN, "mds_reint_open" }, - { MDS_REINT_SETXATTR, "mds_reint_setxattr" }, - { BRW_READ_BYTES, "read_bytes" }, - { BRW_WRITE_BYTES, "write_bytes" }, -}; - -const char *ll_opcode2str(__u32 opcode) -{ - /* When one of the assertions below fail, chances are that: - * 1) A new opcode was added in include/lustre/lustre_idl.h, - * but is missing from the table above. - * or 2) The opcode space was renumbered or rearranged, - * and the opcode_offset() function in - * ptlrpc_internal.h needs to be modified. - */ - __u32 offset = opcode_offset(opcode); - - LASSERTF(offset < LUSTRE_MAX_OPCODES, - "offset %u >= LUSTRE_MAX_OPCODES %u\n", - offset, LUSTRE_MAX_OPCODES); - LASSERTF(ll_rpc_opcode_table[offset].opcode == opcode, - "ll_rpc_opcode_table[%u].opcode %u != opcode %u\n", - offset, ll_rpc_opcode_table[offset].opcode, opcode); - return ll_rpc_opcode_table[offset].opname; -} - -static const char *ll_eopcode2str(__u32 opcode) -{ - LASSERT(ll_eopcode_table[opcode].opcode == opcode); - return ll_eopcode_table[opcode].opname; -} - -static void -ptlrpc_ldebugfs_register(struct dentry *root, char *dir, - char *name, - struct dentry **debugfs_root_ret, - struct lprocfs_stats **stats_ret) -{ - struct dentry *svc_debugfs_entry; - struct lprocfs_stats *svc_stats; - int i, rc; - unsigned int svc_counter_config = LPROCFS_CNTR_AVGMINMAX | - LPROCFS_CNTR_STDDEV; - - LASSERT(!*debugfs_root_ret); - LASSERT(!*stats_ret); - - svc_stats = lprocfs_alloc_stats(EXTRA_MAX_OPCODES + LUSTRE_MAX_OPCODES, - 0); - if (!svc_stats) - return; - - if (dir) { - svc_debugfs_entry = ldebugfs_register(dir, root, NULL, NULL); - if (IS_ERR(svc_debugfs_entry)) { - lprocfs_free_stats(&svc_stats); - return; - } - } else { - svc_debugfs_entry = root; - } - - lprocfs_counter_init(svc_stats, PTLRPC_REQWAIT_CNTR, - svc_counter_config, "req_waittime", "usec"); - lprocfs_counter_init(svc_stats, PTLRPC_REQQDEPTH_CNTR, - svc_counter_config, "req_qdepth", "reqs"); - lprocfs_counter_init(svc_stats, PTLRPC_REQACTIVE_CNTR, - svc_counter_config, "req_active", "reqs"); - lprocfs_counter_init(svc_stats, PTLRPC_TIMEOUT, - svc_counter_config, "req_timeout", "sec"); - lprocfs_counter_init(svc_stats, PTLRPC_REQBUF_AVAIL_CNTR, - svc_counter_config, "reqbuf_avail", "bufs"); - for (i = 0; i < EXTRA_LAST_OPC; i++) { - char *units; - - switch (i) { - case BRW_WRITE_BYTES: - case BRW_READ_BYTES: - units = "bytes"; - break; - default: - units = "reqs"; - break; - } - lprocfs_counter_init(svc_stats, PTLRPC_LAST_CNTR + i, - svc_counter_config, - ll_eopcode2str(i), units); - } - for (i = 0; i < LUSTRE_MAX_OPCODES; i++) { - __u32 opcode = ll_rpc_opcode_table[i].opcode; - - lprocfs_counter_init(svc_stats, - EXTRA_MAX_OPCODES + i, svc_counter_config, - ll_opcode2str(opcode), "usec"); - } - - rc = ldebugfs_register_stats(svc_debugfs_entry, name, svc_stats); - if (rc < 0) { - if (dir) - ldebugfs_remove(&svc_debugfs_entry); - lprocfs_free_stats(&svc_stats); - } else { - if (dir) - *debugfs_root_ret = svc_debugfs_entry; - *stats_ret = svc_stats; - } -} - -static int -ptlrpc_lprocfs_req_history_len_seq_show(struct seq_file *m, void *v) -{ - struct ptlrpc_service *svc = m->private; - struct ptlrpc_service_part *svcpt; - int total = 0; - int i; - - ptlrpc_service_for_each_part(svcpt, i, svc) - total += svcpt->scp_hist_nrqbds; - - seq_printf(m, "%d\n", total); - return 0; -} - -LPROC_SEQ_FOPS_RO(ptlrpc_lprocfs_req_history_len); - -static int -ptlrpc_lprocfs_req_history_max_seq_show(struct seq_file *m, void *n) -{ - struct ptlrpc_service *svc = m->private; - struct ptlrpc_service_part *svcpt; - int total = 0; - int i; - - ptlrpc_service_for_each_part(svcpt, i, svc) - total += svc->srv_hist_nrqbds_cpt_max; - - seq_printf(m, "%d\n", total); - return 0; -} - -static ssize_t -ptlrpc_lprocfs_req_history_max_seq_write(struct file *file, - const char __user *buffer, - size_t count, loff_t *off) -{ - struct ptlrpc_service *svc = ((struct seq_file *)file->private_data)->private; - int bufpages; - int val; - int rc; - - rc = lprocfs_write_helper(buffer, count, &val); - if (rc < 0) - return rc; - - if (val < 0) - return -ERANGE; - - /* This sanity check is more of an insanity check; we can still - * hose a kernel by allowing the request history to grow too - * far. - */ - bufpages = (svc->srv_buf_size + PAGE_SIZE - 1) >> PAGE_SHIFT; - if (val > totalram_pages / (2 * bufpages)) - return -ERANGE; - - spin_lock(&svc->srv_lock); - - if (val == 0) - svc->srv_hist_nrqbds_cpt_max = 0; - else - svc->srv_hist_nrqbds_cpt_max = max(1, (val / svc->srv_ncpts)); - - spin_unlock(&svc->srv_lock); - - return count; -} - -LPROC_SEQ_FOPS(ptlrpc_lprocfs_req_history_max); - -static ssize_t threads_min_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct ptlrpc_service *svc = container_of(kobj, struct ptlrpc_service, - srv_kobj); - - return sprintf(buf, "%d\n", svc->srv_nthrs_cpt_init * svc->srv_ncpts); -} - -static ssize_t threads_min_store(struct kobject *kobj, struct attribute *attr, - const char *buffer, size_t count) -{ - struct ptlrpc_service *svc = container_of(kobj, struct ptlrpc_service, - srv_kobj); - unsigned long val; - int rc = kstrtoul(buffer, 10, &val); - - if (rc < 0) - return rc; - - if (val / svc->srv_ncpts < PTLRPC_NTHRS_INIT) - return -ERANGE; - - spin_lock(&svc->srv_lock); - if (val > svc->srv_nthrs_cpt_limit * svc->srv_ncpts) { - spin_unlock(&svc->srv_lock); - return -ERANGE; - } - - svc->srv_nthrs_cpt_init = val / svc->srv_ncpts; - - spin_unlock(&svc->srv_lock); - - return count; -} -LUSTRE_RW_ATTR(threads_min); - -static ssize_t threads_started_show(struct kobject *kobj, - struct attribute *attr, - char *buf) -{ - struct ptlrpc_service *svc = container_of(kobj, struct ptlrpc_service, - srv_kobj); - struct ptlrpc_service_part *svcpt; - int total = 0; - int i; - - ptlrpc_service_for_each_part(svcpt, i, svc) - total += svcpt->scp_nthrs_running; - - return sprintf(buf, "%d\n", total); -} -LUSTRE_RO_ATTR(threads_started); - -static ssize_t threads_max_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct ptlrpc_service *svc = container_of(kobj, struct ptlrpc_service, - srv_kobj); - - return sprintf(buf, "%d\n", svc->srv_nthrs_cpt_limit * svc->srv_ncpts); -} - -static ssize_t threads_max_store(struct kobject *kobj, struct attribute *attr, - const char *buffer, size_t count) -{ - struct ptlrpc_service *svc = container_of(kobj, struct ptlrpc_service, - srv_kobj); - unsigned long val; - int rc = kstrtoul(buffer, 10, &val); - - if (rc < 0) - return rc; - - if (val / svc->srv_ncpts < PTLRPC_NTHRS_INIT) - return -ERANGE; - - spin_lock(&svc->srv_lock); - if (val < svc->srv_nthrs_cpt_init * svc->srv_ncpts) { - spin_unlock(&svc->srv_lock); - return -ERANGE; - } - - svc->srv_nthrs_cpt_limit = val / svc->srv_ncpts; - - spin_unlock(&svc->srv_lock); - - return count; -} -LUSTRE_RW_ATTR(threads_max); - -/** - * \addtogoup nrs - * @{ - */ - -/** - * Translates \e ptlrpc_nrs_pol_state values to human-readable strings. - * - * \param[in] state The policy state - */ -static const char *nrs_state2str(enum ptlrpc_nrs_pol_state state) -{ - switch (state) { - default: - LBUG(); - case NRS_POL_STATE_INVALID: - return "invalid"; - case NRS_POL_STATE_STOPPED: - return "stopped"; - case NRS_POL_STATE_STOPPING: - return "stopping"; - case NRS_POL_STATE_STARTING: - return "starting"; - case NRS_POL_STATE_STARTED: - return "started"; - } -} - -/** - * Obtains status information for \a policy. - * - * Information is copied in \a info. - * - * \param[in] policy The policy - * \param[out] info Holds returned status information - */ -static void nrs_policy_get_info_locked(struct ptlrpc_nrs_policy *policy, - struct ptlrpc_nrs_pol_info *info) -{ - assert_spin_locked(&policy->pol_nrs->nrs_lock); - - memcpy(info->pi_name, policy->pol_desc->pd_name, NRS_POL_NAME_MAX); - - info->pi_fallback = !!(policy->pol_flags & PTLRPC_NRS_FL_FALLBACK); - info->pi_state = policy->pol_state; - /** - * XXX: These are accessed without holding - * ptlrpc_service_part::scp_req_lock. - */ - info->pi_req_queued = policy->pol_req_queued; - info->pi_req_started = policy->pol_req_started; -} - -/** - * Reads and prints policy status information for all policies of a PTLRPC - * service. - */ -static int ptlrpc_lprocfs_nrs_seq_show(struct seq_file *m, void *n) -{ - struct ptlrpc_service *svc = m->private; - struct ptlrpc_service_part *svcpt; - struct ptlrpc_nrs *nrs; - struct ptlrpc_nrs_policy *policy; - struct ptlrpc_nrs_pol_info *infos; - struct ptlrpc_nrs_pol_info tmp; - unsigned int num_pols; - unsigned int pol_idx = 0; - bool hp = false; - int i; - int rc = 0; - - /** - * Serialize NRS core lprocfs operations with policy registration/ - * unregistration. - */ - mutex_lock(&nrs_core.nrs_mutex); - - /** - * Use the first service partition's regular NRS head in order to obtain - * the number of policies registered with NRS heads of this service. All - * service partitions will have the same number of policies. - */ - nrs = nrs_svcpt2nrs(svc->srv_parts[0], false); - - spin_lock(&nrs->nrs_lock); - num_pols = svc->srv_parts[0]->scp_nrs_reg.nrs_num_pols; - spin_unlock(&nrs->nrs_lock); - - infos = kcalloc(num_pols, sizeof(*infos), GFP_NOFS); - if (!infos) { - rc = -ENOMEM; - goto unlock; - } -again: - - ptlrpc_service_for_each_part(svcpt, i, svc) { - nrs = nrs_svcpt2nrs(svcpt, hp); - spin_lock(&nrs->nrs_lock); - - pol_idx = 0; - - list_for_each_entry(policy, &nrs->nrs_policy_list, pol_list) { - LASSERT(pol_idx < num_pols); - - nrs_policy_get_info_locked(policy, &tmp); - /** - * Copy values when handling the first service - * partition. - */ - if (i == 0) { - memcpy(infos[pol_idx].pi_name, tmp.pi_name, - NRS_POL_NAME_MAX); - memcpy(&infos[pol_idx].pi_state, &tmp.pi_state, - sizeof(tmp.pi_state)); - infos[pol_idx].pi_fallback = tmp.pi_fallback; - /** - * For the rest of the service partitions - * sanity-check the values we get. - */ - } else { - LASSERT(strncmp(infos[pol_idx].pi_name, - tmp.pi_name, - NRS_POL_NAME_MAX) == 0); - /** - * Not asserting ptlrpc_nrs_pol_info::pi_state, - * because it may be different between - * instances of the same policy in different - * service partitions. - */ - LASSERT(infos[pol_idx].pi_fallback == - tmp.pi_fallback); - } - - infos[pol_idx].pi_req_queued += tmp.pi_req_queued; - infos[pol_idx].pi_req_started += tmp.pi_req_started; - - pol_idx++; - } - spin_unlock(&nrs->nrs_lock); - } - - /** - * Policy status information output is in YAML format. - * For example: - * - * regular_requests: - * - name: fifo - * state: started - * fallback: yes - * queued: 0 - * active: 0 - * - * - name: crrn - * state: started - * fallback: no - * queued: 2015 - * active: 384 - * - * high_priority_requests: - * - name: fifo - * state: started - * fallback: yes - * queued: 0 - * active: 2 - * - * - name: crrn - * state: stopped - * fallback: no - * queued: 0 - * active: 0 - */ - seq_printf(m, "%s\n", - !hp ? "\nregular_requests:" : "high_priority_requests:"); - - for (pol_idx = 0; pol_idx < num_pols; pol_idx++) { - seq_printf(m, " - name: %s\n" - " state: %s\n" - " fallback: %s\n" - " queued: %-20d\n" - " active: %-20d\n\n", - infos[pol_idx].pi_name, - nrs_state2str(infos[pol_idx].pi_state), - infos[pol_idx].pi_fallback ? "yes" : "no", - (int)infos[pol_idx].pi_req_queued, - (int)infos[pol_idx].pi_req_started); - } - - if (!hp && nrs_svc_has_hp(svc)) { - memset(infos, 0, num_pols * sizeof(*infos)); - - /** - * Redo the processing for the service's HP NRS heads' policies. - */ - hp = true; - goto again; - } - - kfree(infos); -unlock: - mutex_unlock(&nrs_core.nrs_mutex); - - return rc; -} - -/** - * The longest valid command string is the maximum policy name size, plus the - * length of the " reg" substring - */ -#define LPROCFS_NRS_WR_MAX_CMD (NRS_POL_NAME_MAX + sizeof(" reg") - 1) - -/** - * Starts and stops a given policy on a PTLRPC service. - * - * Commands consist of the policy name, followed by an optional [reg|hp] token; - * if the optional token is omitted, the operation is performed on both the - * regular and high-priority (if the service has one) NRS head. - */ -static ssize_t ptlrpc_lprocfs_nrs_seq_write(struct file *file, - const char __user *buffer, - size_t count, loff_t *off) -{ - struct ptlrpc_service *svc = ((struct seq_file *)file->private_data)->private; - enum ptlrpc_nrs_queue_type queue = PTLRPC_NRS_QUEUE_BOTH; - char *cmd; - char *cmd_copy = NULL; - char *token; - int rc = 0; - - if (count >= LPROCFS_NRS_WR_MAX_CMD) - return -EINVAL; - - cmd = kzalloc(LPROCFS_NRS_WR_MAX_CMD, GFP_NOFS); - if (!cmd) - return -ENOMEM; - /** - * strsep() modifies its argument, so keep a copy - */ - cmd_copy = cmd; - - if (copy_from_user(cmd, buffer, count)) { - rc = -EFAULT; - goto out; - } - - cmd[count] = '\0'; - - token = strsep(&cmd, " "); - - if (strlen(token) > NRS_POL_NAME_MAX - 1) { - rc = -EINVAL; - goto out; - } - - /** - * No [reg|hp] token has been specified - */ - if (!cmd) - goto default_queue; - - /** - * The second token is either NULL, or an optional [reg|hp] string - */ - if (strcmp(cmd, "reg") == 0) { - queue = PTLRPC_NRS_QUEUE_REG; - } else if (strcmp(cmd, "hp") == 0) { - queue = PTLRPC_NRS_QUEUE_HP; - } else { - rc = -EINVAL; - goto out; - } - -default_queue: - - if (queue == PTLRPC_NRS_QUEUE_HP && !nrs_svc_has_hp(svc)) { - rc = -ENODEV; - goto out; - } else if (queue == PTLRPC_NRS_QUEUE_BOTH && !nrs_svc_has_hp(svc)) { - queue = PTLRPC_NRS_QUEUE_REG; - } - - /** - * Serialize NRS core lprocfs operations with policy registration/ - * unregistration. - */ - mutex_lock(&nrs_core.nrs_mutex); - - rc = ptlrpc_nrs_policy_control(svc, queue, token, PTLRPC_NRS_CTL_START, - false, NULL); - - mutex_unlock(&nrs_core.nrs_mutex); -out: - kfree(cmd_copy); - - return rc < 0 ? rc : count; -} - -LPROC_SEQ_FOPS(ptlrpc_lprocfs_nrs); - -/** @} nrs */ - -struct ptlrpc_srh_iterator { - int srhi_idx; - __u64 srhi_seq; - struct ptlrpc_request *srhi_req; -}; - -static int -ptlrpc_lprocfs_svc_req_history_seek(struct ptlrpc_service_part *svcpt, - struct ptlrpc_srh_iterator *srhi, - __u64 seq) -{ - struct list_head *e; - struct ptlrpc_request *req; - - if (srhi->srhi_req && srhi->srhi_seq > svcpt->scp_hist_seq_culled && - srhi->srhi_seq <= seq) { - /* If srhi_req was set previously, hasn't been culled and - * we're searching for a seq on or after it (i.e. more - * recent), search from it onwards. - * Since the service history is LRU (i.e. culled reqs will - * be near the head), we shouldn't have to do long - * re-scans - */ - LASSERTF(srhi->srhi_seq == srhi->srhi_req->rq_history_seq, - "%s:%d: seek seq %llu, request seq %llu\n", - svcpt->scp_service->srv_name, svcpt->scp_cpt, - srhi->srhi_seq, srhi->srhi_req->rq_history_seq); - LASSERTF(!list_empty(&svcpt->scp_hist_reqs), - "%s:%d: seek offset %llu, request seq %llu, last culled %llu\n", - svcpt->scp_service->srv_name, svcpt->scp_cpt, - seq, srhi->srhi_seq, svcpt->scp_hist_seq_culled); - e = &srhi->srhi_req->rq_history_list; - } else { - /* search from start */ - e = svcpt->scp_hist_reqs.next; - } - - while (e != &svcpt->scp_hist_reqs) { - req = list_entry(e, struct ptlrpc_request, rq_history_list); - - if (req->rq_history_seq >= seq) { - srhi->srhi_seq = req->rq_history_seq; - srhi->srhi_req = req; - return 0; - } - e = e->next; - } - - return -ENOENT; -} - -/* - * ptlrpc history sequence is used as "position" of seq_file, in some case, - * seq_read() will increase "position" to indicate reading the next - * element, however, low bits of history sequence are reserved for CPT id - * (check the details from comments before ptlrpc_req_add_history), which - * means seq_read() might change CPT id of history sequence and never - * finish reading of requests on a CPT. To make it work, we have to shift - * CPT id to high bits and timestamp to low bits, so seq_read() will only - * increase timestamp which can correctly indicate the next position. - */ - -/* convert seq_file pos to cpt */ -#define PTLRPC_REQ_POS2CPT(svc, pos) \ - ((svc)->srv_cpt_bits == 0 ? 0 : \ - (__u64)(pos) >> (64 - (svc)->srv_cpt_bits)) - -/* make up seq_file pos from cpt */ -#define PTLRPC_REQ_CPT2POS(svc, cpt) \ - ((svc)->srv_cpt_bits == 0 ? 0 : \ - (cpt) << (64 - (svc)->srv_cpt_bits)) - -/* convert sequence to position */ -#define PTLRPC_REQ_SEQ2POS(svc, seq) \ - ((svc)->srv_cpt_bits == 0 ? (seq) : \ - ((seq) >> (svc)->srv_cpt_bits) | \ - ((seq) << (64 - (svc)->srv_cpt_bits))) - -/* convert position to sequence */ -#define PTLRPC_REQ_POS2SEQ(svc, pos) \ - ((svc)->srv_cpt_bits == 0 ? (pos) : \ - ((__u64)(pos) << (svc)->srv_cpt_bits) | \ - ((__u64)(pos) >> (64 - (svc)->srv_cpt_bits))) - -static void * -ptlrpc_lprocfs_svc_req_history_start(struct seq_file *s, loff_t *pos) -{ - struct ptlrpc_service *svc = s->private; - struct ptlrpc_service_part *svcpt; - struct ptlrpc_srh_iterator *srhi; - unsigned int cpt; - int rc; - int i; - - if (sizeof(loff_t) != sizeof(__u64)) { /* can't support */ - CWARN("Failed to read request history because size of loff_t %d can't match size of u64\n", - (int)sizeof(loff_t)); - return NULL; - } - - srhi = kzalloc(sizeof(*srhi), GFP_NOFS); - if (!srhi) - return NULL; - - srhi->srhi_seq = 0; - srhi->srhi_req = NULL; - - cpt = PTLRPC_REQ_POS2CPT(svc, *pos); - - ptlrpc_service_for_each_part(svcpt, i, svc) { - if (i < cpt) /* skip */ - continue; - if (i > cpt) /* make up the lowest position for this CPT */ - *pos = PTLRPC_REQ_CPT2POS(svc, i); - - spin_lock(&svcpt->scp_lock); - rc = ptlrpc_lprocfs_svc_req_history_seek(svcpt, srhi, - PTLRPC_REQ_POS2SEQ(svc, *pos)); - spin_unlock(&svcpt->scp_lock); - if (rc == 0) { - *pos = PTLRPC_REQ_SEQ2POS(svc, srhi->srhi_seq); - srhi->srhi_idx = i; - return srhi; - } - } - - kfree(srhi); - return NULL; -} - -static void -ptlrpc_lprocfs_svc_req_history_stop(struct seq_file *s, void *iter) -{ - struct ptlrpc_srh_iterator *srhi = iter; - - kfree(srhi); -} - -static void * -ptlrpc_lprocfs_svc_req_history_next(struct seq_file *s, - void *iter, loff_t *pos) -{ - struct ptlrpc_service *svc = s->private; - struct ptlrpc_srh_iterator *srhi = iter; - struct ptlrpc_service_part *svcpt; - __u64 seq; - int rc; - int i; - - for (i = srhi->srhi_idx; i < svc->srv_ncpts; i++) { - svcpt = svc->srv_parts[i]; - - if (i > srhi->srhi_idx) { /* reset iterator for a new CPT */ - srhi->srhi_req = NULL; - seq = 0; - srhi->srhi_seq = 0; - } else { /* the next sequence */ - seq = srhi->srhi_seq + (1 << svc->srv_cpt_bits); - } - - spin_lock(&svcpt->scp_lock); - rc = ptlrpc_lprocfs_svc_req_history_seek(svcpt, srhi, seq); - spin_unlock(&svcpt->scp_lock); - if (rc == 0) { - *pos = PTLRPC_REQ_SEQ2POS(svc, srhi->srhi_seq); - srhi->srhi_idx = i; - return srhi; - } - } - - kfree(srhi); - return NULL; -} - -static int ptlrpc_lprocfs_svc_req_history_show(struct seq_file *s, void *iter) -{ - struct ptlrpc_service *svc = s->private; - struct ptlrpc_srh_iterator *srhi = iter; - struct ptlrpc_service_part *svcpt; - struct ptlrpc_request *req; - int rc; - - LASSERT(srhi->srhi_idx < svc->srv_ncpts); - - svcpt = svc->srv_parts[srhi->srhi_idx]; - - spin_lock(&svcpt->scp_lock); - - rc = ptlrpc_lprocfs_svc_req_history_seek(svcpt, srhi, srhi->srhi_seq); - - if (rc == 0) { - struct timespec64 arrival, sent, arrivaldiff; - char nidstr[LNET_NIDSTR_SIZE]; - - req = srhi->srhi_req; - - libcfs_nid2str_r(req->rq_self, nidstr, sizeof(nidstr)); - arrival.tv_sec = req->rq_arrival_time.tv_sec; - arrival.tv_nsec = req->rq_arrival_time.tv_nsec; - sent.tv_sec = req->rq_sent; - sent.tv_nsec = 0; - arrivaldiff = timespec64_sub(sent, arrival); - - /* Print common req fields. - * CAVEAT EMPTOR: we're racing with the service handler - * here. The request could contain any old crap, so you - * must be just as careful as the service's request - * parser. Currently I only print stuff here I know is OK - * to look at coz it was set up in request_in_callback()!!! - */ - seq_printf(s, "%lld:%s:%s:x%llu:%d:%s:%lld.%06lld:%lld.%06llds(%+lld.0s) ", - req->rq_history_seq, nidstr, - libcfs_id2str(req->rq_peer), req->rq_xid, - req->rq_reqlen, ptlrpc_rqphase2str(req), - (s64)req->rq_arrival_time.tv_sec, - (s64)req->rq_arrival_time.tv_nsec / NSEC_PER_USEC, - (s64)arrivaldiff.tv_sec, - (s64)(arrivaldiff.tv_nsec / NSEC_PER_USEC), - (s64)(req->rq_sent - req->rq_deadline)); - if (!svc->srv_ops.so_req_printer) - seq_putc(s, '\n'); - else - svc->srv_ops.so_req_printer(s, srhi->srhi_req); - } - - spin_unlock(&svcpt->scp_lock); - return rc; -} - -static int -ptlrpc_lprocfs_svc_req_history_open(struct inode *inode, struct file *file) -{ - static const struct seq_operations sops = { - .start = ptlrpc_lprocfs_svc_req_history_start, - .stop = ptlrpc_lprocfs_svc_req_history_stop, - .next = ptlrpc_lprocfs_svc_req_history_next, - .show = ptlrpc_lprocfs_svc_req_history_show, - }; - struct seq_file *seqf; - int rc; - - rc = seq_open(file, &sops); - if (rc) - return rc; - - seqf = file->private_data; - seqf->private = inode->i_private; - return 0; -} - -/* See also lprocfs_rd_timeouts */ -static int ptlrpc_lprocfs_timeouts_seq_show(struct seq_file *m, void *n) -{ - struct ptlrpc_service *svc = m->private; - struct ptlrpc_service_part *svcpt; - struct dhms ts; - time64_t worstt; - unsigned int cur; - unsigned int worst; - int i; - - if (AT_OFF) { - seq_printf(m, "adaptive timeouts off, using obd_timeout %u\n", - obd_timeout); - return 0; - } - - ptlrpc_service_for_each_part(svcpt, i, svc) { - cur = at_get(&svcpt->scp_at_estimate); - worst = svcpt->scp_at_estimate.at_worst_ever; - worstt = svcpt->scp_at_estimate.at_worst_time; - s2dhms(&ts, ktime_get_real_seconds() - worstt); - - seq_printf(m, "%10s : cur %3u worst %3u (at %lld, " - DHMS_FMT " ago) ", "service", - cur, worst, (s64)worstt, DHMS_VARS(&ts)); - - lprocfs_at_hist_helper(m, &svcpt->scp_at_estimate); - } - - return 0; -} - -LPROC_SEQ_FOPS_RO(ptlrpc_lprocfs_timeouts); - -static ssize_t high_priority_ratio_show(struct kobject *kobj, - struct attribute *attr, - char *buf) -{ - struct ptlrpc_service *svc = container_of(kobj, struct ptlrpc_service, - srv_kobj); - return sprintf(buf, "%d\n", svc->srv_hpreq_ratio); -} - -static ssize_t high_priority_ratio_store(struct kobject *kobj, - struct attribute *attr, - const char *buffer, - size_t count) -{ - struct ptlrpc_service *svc = container_of(kobj, struct ptlrpc_service, - srv_kobj); - int rc; - int val; - - rc = kstrtoint(buffer, 10, &val); - if (rc < 0) - return rc; - - if (val < 0) - return -ERANGE; - - spin_lock(&svc->srv_lock); - svc->srv_hpreq_ratio = val; - spin_unlock(&svc->srv_lock); - - return count; -} -LUSTRE_RW_ATTR(high_priority_ratio); - -static struct attribute *ptlrpc_svc_attrs[] = { - &lustre_attr_threads_min.attr, - &lustre_attr_threads_started.attr, - &lustre_attr_threads_max.attr, - &lustre_attr_high_priority_ratio.attr, - NULL, -}; - -static void ptlrpc_sysfs_svc_release(struct kobject *kobj) -{ - struct ptlrpc_service *svc = container_of(kobj, struct ptlrpc_service, - srv_kobj); - - complete(&svc->srv_kobj_unregister); -} - -static struct kobj_type ptlrpc_svc_ktype = { - .default_attrs = ptlrpc_svc_attrs, - .sysfs_ops = &lustre_sysfs_ops, - .release = ptlrpc_sysfs_svc_release, -}; - -void ptlrpc_sysfs_unregister_service(struct ptlrpc_service *svc) -{ - /* Let's see if we had a chance at initialization first */ - if (svc->srv_kobj.kset) { - kobject_put(&svc->srv_kobj); - wait_for_completion(&svc->srv_kobj_unregister); - } -} - -int ptlrpc_sysfs_register_service(struct kset *parent, - struct ptlrpc_service *svc) -{ - int rc; - - svc->srv_kobj.kset = parent; - init_completion(&svc->srv_kobj_unregister); - rc = kobject_init_and_add(&svc->srv_kobj, &ptlrpc_svc_ktype, NULL, - "%s", svc->srv_name); - - return rc; -} - -void ptlrpc_ldebugfs_register_service(struct dentry *entry, - struct ptlrpc_service *svc) -{ - struct lprocfs_vars lproc_vars[] = { - {.name = "req_buffer_history_len", - .fops = &ptlrpc_lprocfs_req_history_len_fops, - .data = svc}, - {.name = "req_buffer_history_max", - .fops = &ptlrpc_lprocfs_req_history_max_fops, - .data = svc}, - {.name = "timeouts", - .fops = &ptlrpc_lprocfs_timeouts_fops, - .data = svc}, - {.name = "nrs_policies", - .fops = &ptlrpc_lprocfs_nrs_fops, - .data = svc}, - {NULL} - }; - static const struct file_operations req_history_fops = { - .owner = THIS_MODULE, - .open = ptlrpc_lprocfs_svc_req_history_open, - .read = seq_read, - .llseek = seq_lseek, - .release = lprocfs_seq_release, - }; - - int rc; - - ptlrpc_ldebugfs_register(entry, svc->srv_name, - "stats", &svc->srv_debugfs_entry, - &svc->srv_stats); - - if (IS_ERR_OR_NULL(svc->srv_debugfs_entry)) - return; - - ldebugfs_add_vars(svc->srv_debugfs_entry, lproc_vars, NULL); - - rc = ldebugfs_seq_create(svc->srv_debugfs_entry, "req_history", - 0400, &req_history_fops, svc); - if (rc) - CWARN("Error adding the req_history file\n"); -} - -void ptlrpc_lprocfs_register_obd(struct obd_device *obddev) -{ - ptlrpc_ldebugfs_register(obddev->obd_debugfs_entry, NULL, "stats", - &obddev->obd_svc_debugfs_entry, - &obddev->obd_svc_stats); -} -EXPORT_SYMBOL(ptlrpc_lprocfs_register_obd); - -void ptlrpc_lprocfs_rpc_sent(struct ptlrpc_request *req, long amount) -{ - struct lprocfs_stats *svc_stats; - __u32 op = lustre_msg_get_opc(req->rq_reqmsg); - int opc = opcode_offset(op); - - svc_stats = req->rq_import->imp_obd->obd_svc_stats; - if (!svc_stats || opc <= 0) - return; - LASSERT(opc < LUSTRE_MAX_OPCODES); - if (!(op == LDLM_ENQUEUE || op == MDS_REINT)) - lprocfs_counter_add(svc_stats, opc + EXTRA_MAX_OPCODES, amount); -} - -void ptlrpc_lprocfs_brw(struct ptlrpc_request *req, int bytes) -{ - struct lprocfs_stats *svc_stats; - int idx; - - if (!req->rq_import) - return; - svc_stats = req->rq_import->imp_obd->obd_svc_stats; - if (!svc_stats) - return; - idx = lustre_msg_get_opc(req->rq_reqmsg); - switch (idx) { - case OST_READ: - idx = BRW_READ_BYTES + PTLRPC_LAST_CNTR; - break; - case OST_WRITE: - idx = BRW_WRITE_BYTES + PTLRPC_LAST_CNTR; - break; - default: - LASSERTF(0, "unsupported opcode %u\n", idx); - break; - } - - lprocfs_counter_add(svc_stats, idx, bytes); -} -EXPORT_SYMBOL(ptlrpc_lprocfs_brw); - -void ptlrpc_lprocfs_unregister_service(struct ptlrpc_service *svc) -{ - if (!IS_ERR_OR_NULL(svc->srv_debugfs_entry)) - ldebugfs_remove(&svc->srv_debugfs_entry); - - if (svc->srv_stats) - lprocfs_free_stats(&svc->srv_stats); -} - -void ptlrpc_lprocfs_unregister_obd(struct obd_device *obd) -{ - if (!IS_ERR_OR_NULL(obd->obd_svc_debugfs_entry)) - ldebugfs_remove(&obd->obd_svc_debugfs_entry); - - if (obd->obd_svc_stats) - lprocfs_free_stats(&obd->obd_svc_stats); -} -EXPORT_SYMBOL(ptlrpc_lprocfs_unregister_obd); - -#undef BUFLEN - -int lprocfs_wr_ping(struct file *file, const char __user *buffer, - size_t count, loff_t *off) -{ - struct obd_device *obd = ((struct seq_file *)file->private_data)->private; - struct ptlrpc_request *req; - int rc; - - rc = lprocfs_climp_check(obd); - if (rc) - return rc; - - req = ptlrpc_prep_ping(obd->u.cli.cl_import); - up_read(&obd->u.cli.cl_sem); - if (!req) - return -ENOMEM; - - req->rq_send_state = LUSTRE_IMP_FULL; - - rc = ptlrpc_queue_wait(req); - - ptlrpc_req_finished(req); - if (rc >= 0) - return count; - return rc; -} -EXPORT_SYMBOL(lprocfs_wr_ping); - -/* Write the connection UUID to this file to attempt to connect to that node. - * The connection UUID is a node's primary NID. For example, - * "echo connection=192.168.0.1@tcp0::instance > .../import". - */ -int lprocfs_wr_import(struct file *file, const char __user *buffer, - size_t count, loff_t *off) -{ - struct obd_device *obd = ((struct seq_file *)file->private_data)->private; - struct obd_import *imp = obd->u.cli.cl_import; - char *kbuf = NULL; - char *uuid; - char *ptr; - int do_reconn = 1; - const char prefix[] = "connection="; - const int prefix_len = sizeof(prefix) - 1; - - if (count > PAGE_SIZE - 1 || count <= prefix_len) - return -EINVAL; - - kbuf = kzalloc(count + 1, GFP_NOFS); - if (!kbuf) - return -ENOMEM; - - if (copy_from_user(kbuf, buffer, count)) { - count = -EFAULT; - goto out; - } - - kbuf[count] = 0; - - /* only support connection=uuid::instance now */ - if (strncmp(prefix, kbuf, prefix_len) != 0) { - count = -EINVAL; - goto out; - } - - uuid = kbuf + prefix_len; - ptr = strstr(uuid, "::"); - if (ptr) { - __u32 inst; - char *endptr; - - *ptr = 0; - do_reconn = 0; - ptr += strlen("::"); - inst = simple_strtoul(ptr, &endptr, 10); - if (*endptr) { - CERROR("config: wrong instance # %s\n", ptr); - } else if (inst != imp->imp_connect_data.ocd_instance) { - CDEBUG(D_INFO, "IR: %s is connecting to an obsoleted target(%u/%u), reconnecting...\n", - imp->imp_obd->obd_name, - imp->imp_connect_data.ocd_instance, inst); - do_reconn = 1; - } else { - CDEBUG(D_INFO, "IR: %s has already been connecting to new target(%u)\n", - imp->imp_obd->obd_name, inst); - } - } - - if (do_reconn) - ptlrpc_recover_import(imp, uuid, 1); - -out: - kfree(kbuf); - return count; -} -EXPORT_SYMBOL(lprocfs_wr_import); - -int lprocfs_rd_pinger_recov(struct seq_file *m, void *n) -{ - struct obd_device *obd = m->private; - struct obd_import *imp = obd->u.cli.cl_import; - int rc; - - rc = lprocfs_climp_check(obd); - if (rc) - return rc; - - seq_printf(m, "%d\n", !imp->imp_no_pinger_recover); - up_read(&obd->u.cli.cl_sem); - - return 0; -} -EXPORT_SYMBOL(lprocfs_rd_pinger_recov); - -int lprocfs_wr_pinger_recov(struct file *file, const char __user *buffer, - size_t count, loff_t *off) -{ - struct obd_device *obd = ((struct seq_file *)file->private_data)->private; - struct client_obd *cli = &obd->u.cli; - struct obd_import *imp = cli->cl_import; - int rc, val; - - rc = lprocfs_write_helper(buffer, count, &val); - if (rc < 0) - return rc; - - if (val != 0 && val != 1) - return -ERANGE; - - rc = lprocfs_climp_check(obd); - if (rc) - return rc; - - spin_lock(&imp->imp_lock); - imp->imp_no_pinger_recover = !val; - spin_unlock(&imp->imp_lock); - up_read(&obd->u.cli.cl_sem); - - return count; -} -EXPORT_SYMBOL(lprocfs_wr_pinger_recov); |