/* * 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) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. * * Copyright (c) 2012, 2017, Intel Corporation. */ /* * This file is part of Lustre, http://www.lustre.org/ * * lustre/osp/lproc_osp.c * * Lustre OST Proxy Device (OSP), procfs functions * * Author: Alex Zhuravlev */ #define DEBUG_SUBSYSTEM S_CLASS #include "osp_internal.h" /** * Show OSP active status * * \param[in] m seq_file handle * \param[in] data unused for single entry * \retval 0 on success * \retval negative number on error */ static ssize_t active_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct lu_device *lu = dt2lu_dev(dt); struct obd_device *obd = lu->ld_obd; struct obd_import *imp; int rc; with_imp_locked(obd, imp, rc) rc = sprintf(buf, "%d\n", !imp->imp_deactive); return rc; } /** * Activate/Deactivate OSP * * \param[in] file proc file * \param[in] buffer string, which is "1" or "0" to activate/deactivate OSP * \param[in] count \a buffer length * \param[in] off unused for single entry * \retval \a count on success * \retval negative number on error */ static ssize_t active_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct lu_device *lu = dt2lu_dev(dt); struct obd_device *obd = lu->ld_obd; struct obd_import *imp, *imp0; bool val; int rc; rc = kstrtobool(buffer, &val); if (rc) return rc; with_imp_locked(obd, imp0, rc) imp = class_import_get(imp0); if (rc) return rc; /* opposite senses */ if (imp->imp_deactive == val) rc = ptlrpc_set_import_active(imp, val); else CDEBUG(D_CONFIG, "activate %u: ignoring repeat request\n", (unsigned int)val); class_import_put(imp); return rc ?: count; } LUSTRE_RW_ATTR(active); /** * Show number of RPCs in flight * * \param[in] m seq_file handle * \param[in] data unused for single entry * \retval 0 on success * \retval negative number on error */ static ssize_t sync_in_flight_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); return sprintf(buf, "%u\n", atomic_read(&osp->opd_sync_rpcs_in_flight)); } LUSTRE_RO_ATTR(sync_in_flight); /** * Show number of RPCs in processing (including uncommitted by OST) * * \param[in] m seq_file handle * \param[in] data unused for single entry * \retval 0 on success * \retval negative number on error */ static ssize_t sync_in_progress_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); return sprintf(buf, "%u\n", atomic_read(&osp->opd_sync_rpcs_in_progress)); } LUSTRE_RO_ATTR(sync_in_progress); /** * Show number of changes to sync * * \param[in] m seq_file handle * \param[in] data unused for single entry * \retval 0 on success * \retval negative number on error */ static ssize_t sync_changes_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); return sprintf(buf, "%u\n", atomic_read(&osp->opd_sync_changes)); } /** * Sync changes * * \param[in] file proc file * \param[in] buffer unused because any input will do * \param[in] count \a buffer length * \param[in] off unused for single entry * \retval \a count on success * \retval negative number on error */ static ssize_t sync_changes_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); struct lu_env env; int rc; rc = lu_env_init(&env, LCT_LOCAL); if (rc != 0) return rc; rc = dt_sync(&env, &osp->opd_dt_dev); lu_env_fini(&env); return rc == 0 ? count : rc; } LUSTRE_RW_ATTR(sync_changes); static ssize_t max_sync_changes_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); return sprintf(buf, "%u\n", osp->opd_sync_max_changes); } static ssize_t max_sync_changes_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); int val; int rc; rc = kstrtoint(buffer, 0, &val); if (rc) return rc; if (val <= 0) return -ERANGE; osp->opd_sync_max_changes = val; return count; } LUSTRE_RW_ATTR(max_sync_changes); /** * Show maximum number of RPCs in flight allowed * * \param[in] m seq_file handle * \param[in] data unused for single entry * \retval 0 on success * \retval negative number on error */ static ssize_t max_rpcs_in_flight_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); return sprintf(buf, "%u\n", osp->opd_sync_max_rpcs_in_flight); } /** * Change maximum number of RPCs in flight allowed * * \param[in] file proc file * \param[in] buffer string which represents maximum number * \param[in] count \a buffer length * \param[in] off unused for single entry * \retval \a count on success * \retval negative number on error */ static ssize_t max_rpcs_in_flight_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); unsigned int val; int rc; rc = kstrtouint(buffer, 0, &val); if (rc) return rc; if (val == 0) return -ERANGE; osp->opd_sync_max_rpcs_in_flight = val; return count; } LUSTRE_RW_ATTR(max_rpcs_in_flight); static ssize_t max_mod_rpcs_in_flight_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct lu_device *lu = dt2lu_dev(dt); struct obd_device *obd = lu->ld_obd; u16 max; max = obd_get_max_mod_rpcs_in_flight(&obd->u.cli); return scnprintf(buf, PAGE_SIZE, "%hu\n", max); } static ssize_t max_mod_rpcs_in_flight_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct lu_device *lu = dt2lu_dev(dt); struct obd_device *obd = lu->ld_obd; u16 val; int rc; rc = kstrtou16(buffer, 10, &val); if (rc) return rc; rc = obd_set_max_mod_rpcs_in_flight(&obd->u.cli, val); if (rc) count = rc; return count; } LUSTRE_RW_ATTR(max_mod_rpcs_in_flight); /** * Show maximum number of RPCs in processing allowed * * \param[in] m seq_file handle * \param[in] data unused * \retval 0 on success * \retval negative number on error */ static ssize_t max_rpcs_in_progress_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); return sprintf(buf, "%u\n", osp->opd_sync_max_rpcs_in_progress); } /** * Change maximum number of RPCs in processing allowed * * \param[in] file proc file * \param[in] buffer string which represents maximum number * \param[in] count \a buffer length * \param[in] off unused for single entry * \retval \a count on success * \retval negative number on error */ static ssize_t max_rpcs_in_progress_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); unsigned int val; int rc; rc = kstrtouint(buffer, 0, &val); if (rc) return rc; if (val == 0) return -ERANGE; osp->opd_sync_max_rpcs_in_progress = val; return count; } LUSTRE_RW_ATTR(max_rpcs_in_progress); /** * Show number of objects to precreate next time * * \param[in] m seq_file handle * \param[in] data unused for single entry * \retval 0 on success * \retval negative number on error */ static ssize_t create_count_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); if (!osp->opd_pre) return -EINVAL; return sprintf(buf, "%d\n", osp->opd_pre_create_count); } /** * Change number of objects to precreate next time * * \param[in] file proc file * \param[in] buffer string which represents number of objects to precreate * \param[in] count \a buffer length * \param[in] off unused for single entry * \retval \a count on success * \retval negative number on error */ static ssize_t create_count_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); unsigned int val; int rc; if (!osp->opd_pre) return -EINVAL; rc = kstrtouint(buffer, 0, &val); if (rc) return rc; /* The MDT ALWAYS needs to limit the precreate count to * OST_MAX_PRECREATE, and the constant cannot be changed * because it is a value shared between the OSP and OST * that is the maximum possible number of objects that will * ever be handled by MDT->OST recovery processing. * * The OSP enforces the pre_create_count to amaximum of * one half of opd_pre_max_create_count. * * If the OST ever gets a request to delete more orphans, * this implies that something has gone badly on the MDT * and the OST will refuse to delete so much data from the * filesystem as a safety measure. */ if (val < OST_MIN_PRECREATE) return -ERANGE; if (val > osp->opd_pre_max_create_count / 2) val = osp->opd_pre_max_create_count / 2; /* set to largest value <= 32, 64, 128 or a multiple of 256 */ if (val > 256) osp->opd_pre_create_count = val & 0xffffff00; else osp->opd_pre_create_count = rounddown_pow_of_two(val); if (osp->opd_pre_create_count + osp->opd_pre_reserved > osp_objs_precreated(osp)) wake_up(&osp->opd_pre_waitq); return count; } LUSTRE_RW_ATTR(create_count); /** * Show maximum number of objects to precreate * * \param[in] m seq_file handle * \param[in] data unused for single entry * \retval 0 on success * \retval negative number on error */ static ssize_t max_create_count_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); if (!osp->opd_pre) return -EINVAL; return sprintf(buf, "%d\n", osp->opd_pre_max_create_count); } /** * Change maximum number of objects to precreate * * \param[in] file proc file * \param[in] buffer string which represents maximum number * \param[in] count \a buffer length * \param[in] off unused for single entry * \retval \a count on success * \retval negative number on error */ static ssize_t max_create_count_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); unsigned int val; int rc; if (!osp->opd_pre) return -EINVAL; rc = kstrtouint(buffer, 0, &val); if (rc) return rc; if (val && (val < OST_MIN_PRECREATE || val > OST_MAX_PRECREATE)) return -ERANGE; if (osp->opd_pre_create_count > val) osp->opd_pre_create_count = val; /* Can be 0 after setting max_create_count to 0 */ if (osp->opd_pre_create_count == 0 && val != 0) osp->opd_pre_create_count = OST_MIN_PRECREATE; osp->opd_pre_max_create_count = val; return count; } LUSTRE_RW_ATTR(max_create_count); /** * Show last id to assign in creation * * \param[in] m seq_file handle * \param[in] data unused for single entry * \retval 0 on success * \retval negative number on error */ static ssize_t prealloc_next_id_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); struct lu_fid *fid; u64 id; __u64 seq_width; if (!osp->opd_pre) return -EINVAL; fid = &osp->opd_pre_used_fid; seq_width = osp->opd_pre_seq_width; if (fid_is_idif(fid)) { id = fid_idif_id(fid_seq(fid), fid_oid(fid), fid_ver(fid)); if (unlikely(id >= min(IDIF_MAX_OID, seq_width))) id = 1; else id++; } else { id = unlikely(fid_oid(fid) >= min(OBIF_MAX_OID, seq_width)) ? 1 : fid_oid(fid) + 1; } return sprintf(buf, "%llu\n", id); } LUSTRE_RO_ATTR(prealloc_next_id); /** * Show last created id OST reported * * \param[in] m seq_file handle * \param[in] data unused for single entry * \retval 0 on success * \retval negative number on error */ static ssize_t prealloc_last_id_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); struct lu_fid *fid; u64 id; if (!osp->opd_pre) return -EINVAL; fid = &osp->opd_pre_last_created_fid; id = fid_is_idif(fid) ? fid_idif_id(fid_seq(fid), fid_oid(fid), fid_ver(fid)) : fid_oid(fid); return sprintf(buf, "%llu\n", id); } LUSTRE_RO_ATTR(prealloc_last_id); /** * Show next FID sequence to precreate * * \param[in] m seq_file handle * \param[in] data unused for single entry * \retval 0 on success * \retval negative number on error */ static ssize_t prealloc_next_seq_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); struct lu_fid *fid; if (!osp->opd_pre) return -EINVAL; fid = &osp->opd_pre_used_fid; return sprintf(buf, "%#llx\n", fid_is_idif(fid) ? fid_seq(fid) & (~0xffff) : fid_seq(fid)); } LUSTRE_RO_ATTR(prealloc_next_seq); /** * Show last created FID sequence OST reported * * \param[in] m seq_file handle * \param[in] data unused for single entry * \retval 0 on success * \retval negative number on error */ static ssize_t prealloc_last_seq_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); struct lu_fid *fid; if (!osp->opd_pre) return -EINVAL; fid = &osp->opd_pre_last_created_fid; return sprintf(buf, "%#llx\n", fid_is_idif(fid) ? fid_seq(fid) & (~0xffff) : fid_seq(fid)); } LUSTRE_RO_ATTR(prealloc_last_seq); /** * Show the number of ids reserved by declare * * \param[in] m seq_file handle * \param[in] data unused for single entry * \retval 0 on success * \retval negative number on error */ static ssize_t prealloc_reserved_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); if (!osp->opd_pre) return -EINVAL; return sprintf(buf, "%llu\n", osp->opd_pre_reserved); } LUSTRE_RO_ATTR(prealloc_reserved); /** * Show interval (in seconds) to update statfs data * * \param[in] m seq_file handle * \param[in] data unused for single entry * \retval 0 on success * \retval negative number on error */ static ssize_t maxage_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); return sprintf(buf, "%lld\n", osp->opd_statfs_maxage); } /** * Change interval to update statfs data * * \param[in] file proc file * \param[in] buffer string which represents statfs interval (in seconds) * \param[in] count \a buffer length * \param[in] off unused for single entry * \retval \a count on success * \retval negative number on error */ static ssize_t maxage_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); unsigned int val; int rc; rc = kstrtouint(buffer, 0, &val); if (rc) return rc; if (val == 0) return -ERANGE; osp->opd_statfs_maxage = val; return count; } LUSTRE_RW_ATTR(maxage); /** * Show current precreation status: output 0 means success, otherwise negative * number is printed * * \param[in] m seq_file handle * \param[in] data unused for single entry * \retval 0 on success * \retval negative number on error */ static ssize_t prealloc_status_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); if (!osp->opd_pre) return -EINVAL; return sprintf(buf, "%d\n", osp->opd_pre_status); } LUSTRE_RO_ATTR(prealloc_status); static ssize_t prealloc_force_new_seq_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); if (!osp->opd_pre) return -EINVAL; return scnprintf(buf, PAGE_SIZE, "%d\n", osp->opd_pre_force_new_seq); } static ssize_t prealloc_force_new_seq_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); bool val; int rc; if (!osp->opd_pre) return -EINVAL; rc = kstrtobool(buffer, &val); if (rc) return rc; osp->opd_pre_force_new_seq = val; return count; } LUSTRE_RW_ATTR(prealloc_force_new_seq); /** * Show the number of RPCs in processing (including uncommitted by OST) plus * changes to sync, i.e. this is the total number of changes OST needs to apply * and commit. * * This counter is used to determine if OST has space returned. A zero value * indicates that OST storage space consumed by destroyed objects has been freed * on disk, the associated llog records have been cleared, and no synchronous * RPC are being processed. * * \param[in] m seq_file handle * \param[in] data unused for single entry * \retval 0 on success * \retval negative number on error */ static ssize_t destroys_in_flight_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); return sprintf(buf, "%u\n", atomic_read(&osp->opd_sync_rpcs_in_progress) + atomic_read(&osp->opd_sync_changes)); } LUSTRE_RO_ATTR(destroys_in_flight); /** * Show changes synced from previous mount * * \param[in] m seq_file handle * \param[in] data unused for single entry * \retval 0 on success * \retval negative number on error */ static ssize_t old_sync_processed_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); return sprintf(buf, "%d\n", osp->opd_sync_prev_done); } LUSTRE_RO_ATTR(old_sync_processed); /** * Show maximum number of RPCs in flight * * \param[in] m seq_file handle * \param[in] data unused for single entry * \retval 0 on success * \retval negative number on error */ static ssize_t lfsck_max_rpcs_in_flight_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct lu_device *lu = dt2lu_dev(dt); struct obd_device *obd = lu->ld_obd; u32 max; max = obd_get_max_rpcs_in_flight(&obd->u.cli); return sprintf(buf, "%u\n", max); } /** * Change maximum number of RPCs in flight * * \param[in] file proc file * \param[in] buffer string which represents maximum number of RPCs in flight * \param[in] count \a buffer length * \param[in] off unused for single entry * \retval \a count on success * \retval negative number on error */ static ssize_t lfsck_max_rpcs_in_flight_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct lu_device *lu = dt2lu_dev(dt); struct obd_device *obd = lu->ld_obd; unsigned int val; int rc; rc = kstrtouint(buffer, 0, &val); if (rc) return rc; rc = obd_set_max_rpcs_in_flight(&obd->u.cli, val); return rc ? rc : count; } LUSTRE_RW_ATTR(lfsck_max_rpcs_in_flight); ssize_t ping_show(struct kobject *kobj, struct attribute *attr, char *buffer) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct lu_device *lu = dt2lu_dev(dt); struct obd_device *obd = lu->ld_obd; int rc; rc = ptlrpc_obd_ping(obd); return rc; } LUSTRE_RO_ATTR(ping); static ssize_t osp_conn_uuid_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct lu_device *lu = dt2lu_dev(dt); struct obd_device *obd = lu->ld_obd; struct obd_import *imp; struct ptlrpc_connection *conn; ssize_t count; with_imp_locked(obd, imp, count) { conn = imp->imp_connection; if (conn) count = sprintf(buf, "%s\n", conn->c_remote_uuid.uuid); else count = sprintf(buf, "%s\n", ""); } return count; } LUSTRE_ATTR(ost_conn_uuid, 0444, osp_conn_uuid_show, NULL); LUSTRE_ATTR(mdt_conn_uuid, 0444, osp_conn_uuid_show, NULL); LDEBUGFS_SEQ_FOPS_RO_TYPE(osp, connect_flags); LDEBUGFS_SEQ_FOPS_RO_TYPE(osp, server_uuid); LDEBUGFS_SEQ_FOPS_RO_TYPE(osp, timeouts); LDEBUGFS_SEQ_FOPS_RW_TYPE(osp, import); LDEBUGFS_SEQ_FOPS_RO_TYPE(osp, state); static int osp_rpc_stats_seq_show(struct seq_file *seq, void *v) { struct obd_device *dev = seq->private; return obd_mod_rpc_stats_seq_show(&dev->u.cli, seq); } static ssize_t osp_rpc_stats_seq_write(struct file *file, const char __user *buf, size_t len, loff_t *off) { struct seq_file *seq = file->private_data; struct obd_device *dev = seq->private; struct client_obd *cli = &dev->u.cli; lprocfs_oh_clear(&cli->cl_mod_rpcs_hist); cli->cl_mod_rpcs_init = ktime_get_real(); return len; } LDEBUGFS_SEQ_FOPS(osp_rpc_stats); /** * Show high watermark (in megabytes). If available free space at OST is greater * than high watermark and object allocation for OST is disabled, enable it. */ static ssize_t reserved_mb_high_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); return snprintf(buf, PAGE_SIZE, "%u\n", osp->opd_reserved_mb_high); } /** * Change high watermark */ static ssize_t reserved_mb_high_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); u64 val; int rc; rc = sysfs_memparse(buffer, count, &val, "MiB"); if (rc < 0) return rc; val >>= 20; if (val < 1) return -ERANGE; spin_lock(&osp->opd_pre_lock); osp->opd_reserved_mb_high = val; if (val <= osp->opd_reserved_mb_low) osp->opd_reserved_mb_low = val - 1; spin_unlock(&osp->opd_pre_lock); return count; } LUSTRE_RW_ATTR(reserved_mb_high); /** * Show low watermark (in megabytes). If available free space at OST is less * than low watermark, object allocation for OST is disabled. */ static ssize_t reserved_mb_low_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); return snprintf(buf, PAGE_SIZE, "%u\n", osp->opd_reserved_mb_low); } /** * Change low watermark */ static ssize_t reserved_mb_low_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); u64 val; int rc; rc = sysfs_memparse(buffer, count, &val, "MiB"); if (rc < 0) return rc; val >>= 20; spin_lock(&osp->opd_pre_lock); osp->opd_reserved_mb_low = val; if (val >= osp->opd_reserved_mb_high) osp->opd_reserved_mb_high = val + 1; spin_unlock(&osp->opd_pre_lock); return count; } LUSTRE_RW_ATTR(reserved_mb_low); /** * Show high watermark of inode. */ static ssize_t reserved_ino_high_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); return snprintf(buf, PAGE_SIZE, "%u\n", osp->opd_reserved_ino_high); } /** * Change high watermark of inode. */ static ssize_t reserved_ino_high_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); unsigned int val; int rc; rc = kstrtouint(buffer, 0, &val); if (rc < 0) return rc; if (val < 1) return -ERANGE; spin_lock(&osp->opd_pre_lock); osp->opd_reserved_ino_high = val; if (val <= osp->opd_reserved_ino_low) osp->opd_reserved_ino_low = val >> 1; spin_unlock(&osp->opd_pre_lock); return count; } LUSTRE_RW_ATTR(reserved_ino_high); /** * Show low watermark. */ static ssize_t reserved_ino_low_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); return snprintf(buf, PAGE_SIZE, "%u\n", osp->opd_reserved_ino_low); } /** * Change low watermark */ static ssize_t reserved_ino_low_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct osp_device *osp = dt2osp_dev(dt); unsigned int val; int rc; rc = kstrtouint(buffer, 0, &val); if (rc < 0) return rc; if (val & (1UL << 31)) return -EOVERFLOW; spin_lock(&osp->opd_pre_lock); osp->opd_reserved_ino_low = val; if (val >= osp->opd_reserved_ino_high) osp->opd_reserved_ino_high = val << 1; spin_unlock(&osp->opd_pre_lock); return count; } LUSTRE_RW_ATTR(reserved_ino_low); static ssize_t force_sync_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) { struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct lu_env env; int rc; rc = lu_env_init(&env, LCT_LOCAL); if (rc) return rc; rc = dt_sync(&env, dt); lu_env_fini(&env); return rc == 0 ? count : rc; } LUSTRE_WO_ATTR(force_sync); static struct ldebugfs_vars ldebugfs_osp_obd_vars[] = { { .name = "connect_flags", .fops = &osp_connect_flags_fops }, { .name = "ost_server_uuid", .fops = &osp_server_uuid_fops }, { .name = "timeouts", .fops = &osp_timeouts_fops }, { .name = "import", .fops = &osp_import_fops }, { .name = "state", .fops = &osp_state_fops }, { NULL } }; static struct ldebugfs_vars ldebugfs_osp_md_vars[] = { { .name = "connect_flags", .fops = &osp_connect_flags_fops }, { .name = "mdt_server_uuid", .fops = &osp_server_uuid_fops }, { .name = "timeouts", .fops = &osp_timeouts_fops }, { .name = "import", .fops = &osp_import_fops }, { .name = "state", .fops = &osp_state_fops }, { .name = "rpc_stats", .fops = &osp_rpc_stats_fops }, { NULL } }; static struct attribute *osp_obd_attrs[] = { /* First two for compatiability reasons */ &lustre_attr_lfsck_max_rpcs_in_flight.attr, &lustre_attr_destroys_in_flight.attr, &lustre_attr_active.attr, &lustre_attr_max_rpcs_in_flight.attr, &lustre_attr_max_rpcs_in_progress.attr, &lustre_attr_maxage.attr, &lustre_attr_ost_conn_uuid.attr, &lustre_attr_ping.attr, &lustre_attr_prealloc_status.attr, &lustre_attr_prealloc_next_id.attr, &lustre_attr_prealloc_last_id.attr, &lustre_attr_prealloc_next_seq.attr, &lustre_attr_prealloc_last_seq.attr, &lustre_attr_prealloc_reserved.attr, &lustre_attr_prealloc_force_new_seq.attr, &lustre_attr_sync_in_flight.attr, &lustre_attr_sync_in_progress.attr, &lustre_attr_sync_changes.attr, &lustre_attr_max_sync_changes.attr, &lustre_attr_force_sync.attr, &lustre_attr_old_sync_processed.attr, &lustre_attr_create_count.attr, &lustre_attr_max_create_count.attr, &lustre_attr_reserved_mb_high.attr, &lustre_attr_reserved_mb_low.attr, &lustre_attr_reserved_ino_high.attr, &lustre_attr_reserved_ino_low.attr, NULL, }; KOBJ_ATTRIBUTE_GROUPS(osp_obd); /* creates osp_obd_groups from osp_obd_attrs */ static struct attribute *osp_md_attrs[] = { /* First two for compatiability reasons */ &lustre_attr_lfsck_max_rpcs_in_flight.attr, &lustre_attr_destroys_in_flight.attr, &lustre_attr_active.attr, &lustre_attr_max_rpcs_in_flight.attr, &lustre_attr_max_mod_rpcs_in_flight.attr, &lustre_attr_max_rpcs_in_progress.attr, &lustre_attr_maxage.attr, &lustre_attr_mdt_conn_uuid.attr, &lustre_attr_ping.attr, &lustre_attr_prealloc_status.attr, &lustre_attr_reserved_mb_high.attr, &lustre_attr_reserved_mb_low.attr, &lustre_attr_reserved_ino_high.attr, &lustre_attr_reserved_ino_low.attr, NULL, }; KOBJ_ATTRIBUTE_GROUPS(osp_md); /* creates osp_md_groups from osp_md_attrs */ void osp_tunables_fini(struct osp_device *osp) { struct obd_device *obd = osp->opd_obd; struct kobject *osc; osc = kset_find_obj(lustre_kset, "osc"); if (osc) { sysfs_remove_link(osc, obd->obd_name); kobject_put(osc); } debugfs_remove_recursive(osp->opd_debugfs); osp->opd_debugfs = NULL; ptlrpc_lprocfs_unregister_obd(obd); debugfs_remove_recursive(obd->obd_debugfs_entry); obd->obd_debugfs_entry = NULL; dt_tunables_fini(&osp->opd_dt_dev); } /** * Initialize OSP sysfs / debugfs * * param[in] osp OSP device */ void osp_tunables_init(struct osp_device *osp) { struct obd_device *obd = osp->opd_obd; struct kobject *osc; int rc; if (osp->opd_connect_mdt) { osp->opd_dt_dev.dd_ktype.default_groups = KOBJ_ATTR_GROUPS(osp_md); obd->obd_debugfs_vars = ldebugfs_osp_md_vars; } else { osp->opd_dt_dev.dd_ktype.default_groups = KOBJ_ATTR_GROUPS(osp_obd); obd->obd_debugfs_vars = ldebugfs_osp_obd_vars; } rc = dt_tunables_init(&osp->opd_dt_dev, obd->obd_type, obd->obd_name, NULL); if (rc) { CERROR("%s: failed to setup DT tunables: %d\n", obd->obd_name, rc); return; } /* Since we register the obd device with ptlrpc / sptlrpc we * have to register debugfs with obd_device */ obd->obd_debugfs_entry = debugfs_create_dir( obd->obd_name, obd->obd_type->typ_debugfs_entry); ldebugfs_add_vars(obd->obd_debugfs_entry, obd->obd_debugfs_vars, obd); sptlrpc_lprocfs_cliobd_attach(obd); ptlrpc_lprocfs_register_obd(obd); if (osp->opd_connect_mdt || !strstr(obd->obd_name, "osc")) return; /* If the real OSC is present which is the case for setups * with both server and clients on the same node then use * the OSC's proc root */ osc = kset_find_obj(lustre_kset, "osc"); if (osc) { rc = sysfs_create_link(osc, &osp->opd_dt_dev.dd_kobj, obd->obd_name); kobject_put(osc); } osp->opd_debugfs = ldebugfs_add_symlink(obd->obd_name, "osc", "../osp/%s", obd->obd_name); if (!osp->opd_debugfs) CERROR("%s: failed to create OSC debugfs symlink\n", obd->obd_name); }