diff options
Diffstat (limited to 'drivers/staging/lustre/lustre/obdclass')
29 files changed, 0 insertions, 16032 deletions
diff --git a/drivers/staging/lustre/lustre/obdclass/Makefile b/drivers/staging/lustre/lustre/obdclass/Makefile deleted file mode 100644 index e3fa9acff4c4..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/include -subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include - -obj-$(CONFIG_LUSTRE_FS) += obdclass.o - -obdclass-y := linux/linux-module.o linux/linux-sysctl.o \ - llog.o llog_cat.o llog_obd.o llog_swab.o class_obd.o debug.o \ - genops.o uuid.o lprocfs_status.o lprocfs_counters.o \ - lustre_handles.o lustre_peer.o statfs_pack.o linkea.o \ - obdo.o obd_config.o obd_mount.o lu_object.o lu_ref.o \ - cl_object.o cl_page.o cl_lock.o cl_io.o kernelcomm.o diff --git a/drivers/staging/lustre/lustre/obdclass/cl_internal.h b/drivers/staging/lustre/lustre/obdclass/cl_internal.h deleted file mode 100644 index a0db830ca841..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/cl_internal.h +++ /dev/null @@ -1,95 +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) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * Internal cl interfaces. - * - * Author: Nikita Danilov <nikita.danilov@sun.com> - */ -#ifndef _CL_INTERNAL_H -#define _CL_INTERNAL_H - -#define CLT_PVEC_SIZE (14) - -/** - * Possible levels of the nesting. Currently this is 2: there are "top" - * entities (files, extent locks), and "sub" entities (stripes and stripe - * locks). This is used only for debugging counters right now. - */ -enum clt_nesting_level { - CNL_TOP, - CNL_SUB, - CNL_NR -}; - -/** - * Thread local state internal for generic cl-code. - */ -struct cl_thread_info { - /* - * Common fields. - */ - struct cl_io clt_io; - struct cl_2queue clt_queue; - - /* - * Fields used by cl_lock.c - */ - struct cl_lock_descr clt_descr; - struct cl_page_list clt_list; - /** @} debugging */ - - /* - * Fields used by cl_page.c - */ - struct cl_page *clt_pvec[CLT_PVEC_SIZE]; - - /* - * Fields used by cl_io.c - */ - /** - * Pointer to the topmost ongoing IO in this thread. - */ - struct cl_io *clt_current_io; - /** - * Used for submitting a sync io. - */ - struct cl_sync_io clt_anchor; - /** - * Fields used by cl_lock_discard_pages(). - */ - pgoff_t clt_next_index; - pgoff_t clt_fn_index; /* first non-overlapped index */ -}; - -struct cl_thread_info *cl_env_info(const struct lu_env *env); - -#endif /* _CL_INTERNAL_H */ diff --git a/drivers/staging/lustre/lustre/obdclass/cl_io.c b/drivers/staging/lustre/lustre/obdclass/cl_io.c deleted file mode 100644 index ab84e011b560..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/cl_io.c +++ /dev/null @@ -1,1152 +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) 2008, 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. - * - * Client IO. - * - * Author: Nikita Danilov <nikita.danilov@sun.com> - * Author: Jinshan Xiong <jinshan.xiong@intel.com> - */ - -#define DEBUG_SUBSYSTEM S_CLASS - -#include <obd_class.h> -#include <obd_support.h> -#include <lustre_fid.h> -#include <linux/list.h> -#include <linux/sched.h> -#include <cl_object.h> -#include "cl_internal.h" - -/***************************************************************************** - * - * cl_io interface. - * - */ - -#define cl_io_for_each(slice, io) \ - list_for_each_entry((slice), &io->ci_layers, cis_linkage) -#define cl_io_for_each_reverse(slice, io) \ - list_for_each_entry_reverse((slice), &io->ci_layers, cis_linkage) - -static inline int cl_io_type_is_valid(enum cl_io_type type) -{ - return CIT_READ <= type && type < CIT_OP_NR; -} - -static inline int cl_io_is_loopable(const struct cl_io *io) -{ - return cl_io_type_is_valid(io->ci_type) && io->ci_type != CIT_MISC; -} - -/** - * Returns true iff there is an IO ongoing in the given environment. - */ -int cl_io_is_going(const struct lu_env *env) -{ - return cl_env_info(env)->clt_current_io != NULL; -} - -/** - * cl_io invariant that holds at all times when exported cl_io_*() functions - * are entered and left. - */ -static int cl_io_invariant(const struct cl_io *io) -{ - struct cl_io *up; - - up = io->ci_parent; - return - /* - * io can own pages only when it is ongoing. Sub-io might - * still be in CIS_LOCKED state when top-io is in - * CIS_IO_GOING. - */ - ergo(io->ci_owned_nr > 0, io->ci_state == CIS_IO_GOING || - (io->ci_state == CIS_LOCKED && up)); -} - -/** - * Finalize \a io, by calling cl_io_operations::cio_fini() bottom-to-top. - */ -void cl_io_fini(const struct lu_env *env, struct cl_io *io) -{ - struct cl_io_slice *slice; - struct cl_thread_info *info; - - LINVRNT(cl_io_type_is_valid(io->ci_type)); - LINVRNT(cl_io_invariant(io)); - - while (!list_empty(&io->ci_layers)) { - slice = container_of(io->ci_layers.prev, struct cl_io_slice, - cis_linkage); - list_del_init(&slice->cis_linkage); - if (slice->cis_iop->op[io->ci_type].cio_fini) - slice->cis_iop->op[io->ci_type].cio_fini(env, slice); - /* - * Invalidate slice to catch use after free. This assumes that - * slices are allocated within session and can be touched - * after ->cio_fini() returns. - */ - slice->cis_io = NULL; - } - io->ci_state = CIS_FINI; - info = cl_env_info(env); - if (info->clt_current_io == io) - info->clt_current_io = NULL; - - /* sanity check for layout change */ - switch (io->ci_type) { - case CIT_READ: - case CIT_WRITE: - case CIT_DATA_VERSION: - break; - case CIT_FAULT: - break; - case CIT_FSYNC: - LASSERT(!io->ci_need_restart); - break; - case CIT_SETATTR: - case CIT_MISC: - /* Check ignore layout change conf */ - LASSERT(ergo(io->ci_ignore_layout || !io->ci_verify_layout, - !io->ci_need_restart)); - break; - default: - LBUG(); - } -} -EXPORT_SYMBOL(cl_io_fini); - -static int cl_io_init0(const struct lu_env *env, struct cl_io *io, - enum cl_io_type iot, struct cl_object *obj) -{ - struct cl_object *scan; - int result; - - LINVRNT(io->ci_state == CIS_ZERO || io->ci_state == CIS_FINI); - LINVRNT(cl_io_type_is_valid(iot)); - LINVRNT(cl_io_invariant(io)); - - io->ci_type = iot; - INIT_LIST_HEAD(&io->ci_lockset.cls_todo); - INIT_LIST_HEAD(&io->ci_lockset.cls_done); - INIT_LIST_HEAD(&io->ci_layers); - - result = 0; - cl_object_for_each(scan, obj) { - if (scan->co_ops->coo_io_init) { - result = scan->co_ops->coo_io_init(env, scan, io); - if (result != 0) - break; - } - } - if (result == 0) - io->ci_state = CIS_INIT; - return result; -} - -/** - * Initialize sub-io, by calling cl_io_operations::cio_init() top-to-bottom. - * - * \pre obj != cl_object_top(obj) - */ -int cl_io_sub_init(const struct lu_env *env, struct cl_io *io, - enum cl_io_type iot, struct cl_object *obj) -{ - struct cl_thread_info *info = cl_env_info(env); - - LASSERT(obj != cl_object_top(obj)); - if (!info->clt_current_io) - info->clt_current_io = io; - return cl_io_init0(env, io, iot, obj); -} -EXPORT_SYMBOL(cl_io_sub_init); - -/** - * Initialize \a io, by calling cl_io_operations::cio_init() top-to-bottom. - * - * Caller has to call cl_io_fini() after a call to cl_io_init(), no matter - * what the latter returned. - * - * \pre obj == cl_object_top(obj) - * \pre cl_io_type_is_valid(iot) - * \post cl_io_type_is_valid(io->ci_type) && io->ci_type == iot - */ -int cl_io_init(const struct lu_env *env, struct cl_io *io, - enum cl_io_type iot, struct cl_object *obj) -{ - struct cl_thread_info *info = cl_env_info(env); - - LASSERT(obj == cl_object_top(obj)); - LASSERT(!info->clt_current_io); - - info->clt_current_io = io; - return cl_io_init0(env, io, iot, obj); -} -EXPORT_SYMBOL(cl_io_init); - -/** - * Initialize read or write io. - * - * \pre iot == CIT_READ || iot == CIT_WRITE - */ -int cl_io_rw_init(const struct lu_env *env, struct cl_io *io, - enum cl_io_type iot, loff_t pos, size_t count) -{ - LINVRNT(iot == CIT_READ || iot == CIT_WRITE); - LINVRNT(io->ci_obj); - - LU_OBJECT_HEADER(D_VFSTRACE, env, &io->ci_obj->co_lu, - "io range: %u [%llu, %llu) %u %u\n", - iot, (__u64)pos, (__u64)pos + count, - io->u.ci_rw.crw_nonblock, io->u.ci_wr.wr_append); - io->u.ci_rw.crw_pos = pos; - io->u.ci_rw.crw_count = count; - return cl_io_init(env, io, iot, io->ci_obj); -} -EXPORT_SYMBOL(cl_io_rw_init); - -static int cl_lock_descr_sort(const struct cl_lock_descr *d0, - const struct cl_lock_descr *d1) -{ - return lu_fid_cmp(lu_object_fid(&d0->cld_obj->co_lu), - lu_object_fid(&d1->cld_obj->co_lu)); -} - -/* - * Sort locks in lexicographical order of their (fid, start-offset) pairs. - */ -static void cl_io_locks_sort(struct cl_io *io) -{ - int done = 0; - - /* hidden treasure: bubble sort for now. */ - do { - struct cl_io_lock_link *curr; - struct cl_io_lock_link *prev; - struct cl_io_lock_link *temp; - - done = 1; - prev = NULL; - - list_for_each_entry_safe(curr, temp, - &io->ci_lockset.cls_todo, - cill_linkage) { - if (prev) { - switch (cl_lock_descr_sort(&prev->cill_descr, - &curr->cill_descr)) { - case 0: - /* - * IMPOSSIBLE: Identical locks are - * already removed at - * this point. - */ - default: - LBUG(); - case 1: - list_move_tail(&curr->cill_linkage, - &prev->cill_linkage); - done = 0; - continue; /* don't change prev: it's - * still "previous" - */ - case -1: /* already in order */ - break; - } - } - prev = curr; - } - } while (!done); -} - -static void cl_lock_descr_merge(struct cl_lock_descr *d0, - const struct cl_lock_descr *d1) -{ - d0->cld_start = min(d0->cld_start, d1->cld_start); - d0->cld_end = max(d0->cld_end, d1->cld_end); - - if (d1->cld_mode == CLM_WRITE && d0->cld_mode != CLM_WRITE) - d0->cld_mode = CLM_WRITE; - - if (d1->cld_mode == CLM_GROUP && d0->cld_mode != CLM_GROUP) - d0->cld_mode = CLM_GROUP; -} - -static int cl_lockset_merge(const struct cl_lockset *set, - const struct cl_lock_descr *need) -{ - struct cl_io_lock_link *scan; - - list_for_each_entry(scan, &set->cls_todo, cill_linkage) { - if (!cl_object_same(scan->cill_descr.cld_obj, need->cld_obj)) - continue; - - /* Merge locks for the same object because ldlm lock server - * may expand the lock extent, otherwise there is a deadlock - * case if two conflicted locks are queueud for the same object - * and lock server expands one lock to overlap the another. - * The side effect is that it can generate a multi-stripe lock - * that may cause casacading problem - */ - cl_lock_descr_merge(&scan->cill_descr, need); - CDEBUG(D_VFSTRACE, "lock: %d: [%lu, %lu]\n", - scan->cill_descr.cld_mode, scan->cill_descr.cld_start, - scan->cill_descr.cld_end); - return 1; - } - return 0; -} - -static int cl_lockset_lock(const struct lu_env *env, struct cl_io *io, - struct cl_lockset *set) -{ - struct cl_io_lock_link *link; - struct cl_io_lock_link *temp; - int result; - - result = 0; - list_for_each_entry_safe(link, temp, &set->cls_todo, cill_linkage) { - result = cl_lock_request(env, io, &link->cill_lock); - if (result < 0) - break; - - list_move(&link->cill_linkage, &set->cls_done); - } - return result; -} - -/** - * Takes locks necessary for the current iteration of io. - * - * Calls cl_io_operations::cio_lock() top-to-bottom to collect locks required - * by layers for the current iteration. Then sort locks (to avoid dead-locks), - * and acquire them. - */ -int cl_io_lock(const struct lu_env *env, struct cl_io *io) -{ - const struct cl_io_slice *scan; - int result = 0; - - LINVRNT(cl_io_is_loopable(io)); - LINVRNT(io->ci_state == CIS_IT_STARTED); - LINVRNT(cl_io_invariant(io)); - - cl_io_for_each(scan, io) { - if (!scan->cis_iop->op[io->ci_type].cio_lock) - continue; - result = scan->cis_iop->op[io->ci_type].cio_lock(env, scan); - if (result != 0) - break; - } - if (result == 0) { - cl_io_locks_sort(io); - result = cl_lockset_lock(env, io, &io->ci_lockset); - } - if (result != 0) - cl_io_unlock(env, io); - else - io->ci_state = CIS_LOCKED; - return result; -} -EXPORT_SYMBOL(cl_io_lock); - -/** - * Release locks takes by io. - */ -void cl_io_unlock(const struct lu_env *env, struct cl_io *io) -{ - struct cl_lockset *set; - struct cl_io_lock_link *link; - struct cl_io_lock_link *temp; - const struct cl_io_slice *scan; - - LASSERT(cl_io_is_loopable(io)); - LASSERT(CIS_IT_STARTED <= io->ci_state && io->ci_state < CIS_UNLOCKED); - LINVRNT(cl_io_invariant(io)); - - set = &io->ci_lockset; - - list_for_each_entry_safe(link, temp, &set->cls_todo, cill_linkage) { - list_del_init(&link->cill_linkage); - if (link->cill_fini) - link->cill_fini(env, link); - } - - list_for_each_entry_safe(link, temp, &set->cls_done, cill_linkage) { - list_del_init(&link->cill_linkage); - cl_lock_release(env, &link->cill_lock); - if (link->cill_fini) - link->cill_fini(env, link); - } - - cl_io_for_each_reverse(scan, io) { - if (scan->cis_iop->op[io->ci_type].cio_unlock) - scan->cis_iop->op[io->ci_type].cio_unlock(env, scan); - } - io->ci_state = CIS_UNLOCKED; -} -EXPORT_SYMBOL(cl_io_unlock); - -/** - * Prepares next iteration of io. - * - * Calls cl_io_operations::cio_iter_init() top-to-bottom. This exists to give - * layers a chance to modify io parameters, e.g., so that lov can restrict io - * to a single stripe. - */ -int cl_io_iter_init(const struct lu_env *env, struct cl_io *io) -{ - const struct cl_io_slice *scan; - int result; - - LINVRNT(cl_io_is_loopable(io)); - LINVRNT(io->ci_state == CIS_INIT || io->ci_state == CIS_IT_ENDED); - LINVRNT(cl_io_invariant(io)); - - result = 0; - cl_io_for_each(scan, io) { - if (!scan->cis_iop->op[io->ci_type].cio_iter_init) - continue; - result = scan->cis_iop->op[io->ci_type].cio_iter_init(env, - scan); - if (result != 0) - break; - } - if (result == 0) - io->ci_state = CIS_IT_STARTED; - return result; -} -EXPORT_SYMBOL(cl_io_iter_init); - -/** - * Finalizes io iteration. - * - * Calls cl_io_operations::cio_iter_fini() bottom-to-top. - */ -void cl_io_iter_fini(const struct lu_env *env, struct cl_io *io) -{ - const struct cl_io_slice *scan; - - LINVRNT(cl_io_is_loopable(io)); - LINVRNT(io->ci_state == CIS_UNLOCKED); - LINVRNT(cl_io_invariant(io)); - - cl_io_for_each_reverse(scan, io) { - if (scan->cis_iop->op[io->ci_type].cio_iter_fini) - scan->cis_iop->op[io->ci_type].cio_iter_fini(env, scan); - } - io->ci_state = CIS_IT_ENDED; -} -EXPORT_SYMBOL(cl_io_iter_fini); - -/** - * Records that read or write io progressed \a nob bytes forward. - */ -static void cl_io_rw_advance(const struct lu_env *env, struct cl_io *io, - size_t nob) -{ - const struct cl_io_slice *scan; - - LINVRNT(io->ci_type == CIT_READ || io->ci_type == CIT_WRITE || - nob == 0); - LINVRNT(cl_io_is_loopable(io)); - LINVRNT(cl_io_invariant(io)); - - io->u.ci_rw.crw_pos += nob; - io->u.ci_rw.crw_count -= nob; - - /* layers have to be notified. */ - cl_io_for_each_reverse(scan, io) { - if (scan->cis_iop->op[io->ci_type].cio_advance) - scan->cis_iop->op[io->ci_type].cio_advance(env, scan, - nob); - } -} - -/** - * Adds a lock to a lockset. - */ -int cl_io_lock_add(const struct lu_env *env, struct cl_io *io, - struct cl_io_lock_link *link) -{ - int result; - - if (cl_lockset_merge(&io->ci_lockset, &link->cill_descr)) { - result = 1; - } else { - list_add(&link->cill_linkage, &io->ci_lockset.cls_todo); - result = 0; - } - return result; -} -EXPORT_SYMBOL(cl_io_lock_add); - -static void cl_free_io_lock_link(const struct lu_env *env, - struct cl_io_lock_link *link) -{ - kfree(link); -} - -/** - * Allocates new lock link, and uses it to add a lock to a lockset. - */ -int cl_io_lock_alloc_add(const struct lu_env *env, struct cl_io *io, - struct cl_lock_descr *descr) -{ - struct cl_io_lock_link *link; - int result; - - link = kzalloc(sizeof(*link), GFP_NOFS); - if (link) { - link->cill_descr = *descr; - link->cill_fini = cl_free_io_lock_link; - result = cl_io_lock_add(env, io, link); - if (result) /* lock match */ - link->cill_fini(env, link); - } else { - result = -ENOMEM; - } - - return result; -} -EXPORT_SYMBOL(cl_io_lock_alloc_add); - -/** - * Starts io by calling cl_io_operations::cio_start() top-to-bottom. - */ -int cl_io_start(const struct lu_env *env, struct cl_io *io) -{ - const struct cl_io_slice *scan; - int result = 0; - - LINVRNT(cl_io_is_loopable(io)); - LINVRNT(io->ci_state == CIS_LOCKED); - LINVRNT(cl_io_invariant(io)); - - io->ci_state = CIS_IO_GOING; - cl_io_for_each(scan, io) { - if (!scan->cis_iop->op[io->ci_type].cio_start) - continue; - result = scan->cis_iop->op[io->ci_type].cio_start(env, scan); - if (result != 0) - break; - } - if (result >= 0) - result = 0; - return result; -} -EXPORT_SYMBOL(cl_io_start); - -/** - * Wait until current io iteration is finished by calling - * cl_io_operations::cio_end() bottom-to-top. - */ -void cl_io_end(const struct lu_env *env, struct cl_io *io) -{ - const struct cl_io_slice *scan; - - LINVRNT(cl_io_is_loopable(io)); - LINVRNT(io->ci_state == CIS_IO_GOING); - LINVRNT(cl_io_invariant(io)); - - cl_io_for_each_reverse(scan, io) { - if (scan->cis_iop->op[io->ci_type].cio_end) - scan->cis_iop->op[io->ci_type].cio_end(env, scan); - /* TODO: error handling. */ - } - io->ci_state = CIS_IO_FINISHED; -} -EXPORT_SYMBOL(cl_io_end); - -/** - * Called by read io, to decide the readahead extent - * - * \see cl_io_operations::cio_read_ahead() - */ -int cl_io_read_ahead(const struct lu_env *env, struct cl_io *io, - pgoff_t start, struct cl_read_ahead *ra) -{ - const struct cl_io_slice *scan; - int result = 0; - - LINVRNT(io->ci_type == CIT_READ || io->ci_type == CIT_FAULT); - LINVRNT(io->ci_state == CIS_IO_GOING || io->ci_state == CIS_LOCKED); - LINVRNT(cl_io_invariant(io)); - - cl_io_for_each(scan, io) { - if (!scan->cis_iop->cio_read_ahead) - continue; - - result = scan->cis_iop->cio_read_ahead(env, scan, start, ra); - if (result) - break; - } - return result > 0 ? 0 : result; -} -EXPORT_SYMBOL(cl_io_read_ahead); - -/** - * Commit a list of contiguous pages into writeback cache. - * - * \returns 0 if all pages committed, or errcode if error occurred. - * \see cl_io_operations::cio_commit_async() - */ -int cl_io_commit_async(const struct lu_env *env, struct cl_io *io, - struct cl_page_list *queue, int from, int to, - cl_commit_cbt cb) -{ - const struct cl_io_slice *scan; - int result = 0; - - cl_io_for_each(scan, io) { - if (!scan->cis_iop->cio_commit_async) - continue; - result = scan->cis_iop->cio_commit_async(env, scan, queue, - from, to, cb); - if (result != 0) - break; - } - return result; -} -EXPORT_SYMBOL(cl_io_commit_async); - -/** - * Submits a list of pages for immediate io. - * - * After the function gets returned, The submitted pages are moved to - * queue->c2_qout queue, and queue->c2_qin contain both the pages don't need - * to be submitted, and the pages are errant to submit. - * - * \returns 0 if at least one page was submitted, error code otherwise. - * \see cl_io_operations::cio_submit() - */ -int cl_io_submit_rw(const struct lu_env *env, struct cl_io *io, - enum cl_req_type crt, struct cl_2queue *queue) -{ - const struct cl_io_slice *scan; - int result = 0; - - cl_io_for_each(scan, io) { - if (!scan->cis_iop->cio_submit) - continue; - result = scan->cis_iop->cio_submit(env, scan, crt, queue); - if (result != 0) - break; - } - /* - * If ->cio_submit() failed, no pages were sent. - */ - LASSERT(ergo(result != 0, list_empty(&queue->c2_qout.pl_pages))); - return result; -} -EXPORT_SYMBOL(cl_io_submit_rw); - -static void cl_page_list_assume(const struct lu_env *env, - struct cl_io *io, struct cl_page_list *plist); - -/** - * Submit a sync_io and wait for the IO to be finished, or error happens. - * If \a timeout is zero, it means to wait for the IO unconditionally. - */ -int cl_io_submit_sync(const struct lu_env *env, struct cl_io *io, - enum cl_req_type iot, struct cl_2queue *queue, - long timeout) -{ - struct cl_sync_io *anchor = &cl_env_info(env)->clt_anchor; - struct cl_page *pg; - int rc; - - cl_page_list_for_each(pg, &queue->c2_qin) { - LASSERT(!pg->cp_sync_io); - pg->cp_sync_io = anchor; - } - - cl_sync_io_init(anchor, queue->c2_qin.pl_nr, &cl_sync_io_end); - rc = cl_io_submit_rw(env, io, iot, queue); - if (rc == 0) { - /* - * If some pages weren't sent for any reason (e.g., - * read found up-to-date pages in the cache, or write found - * clean pages), count them as completed to avoid infinite - * wait. - */ - cl_page_list_for_each(pg, &queue->c2_qin) { - pg->cp_sync_io = NULL; - cl_sync_io_note(env, anchor, 1); - } - - /* wait for the IO to be finished. */ - rc = cl_sync_io_wait(env, anchor, timeout); - cl_page_list_assume(env, io, &queue->c2_qout); - } else { - LASSERT(list_empty(&queue->c2_qout.pl_pages)); - cl_page_list_for_each(pg, &queue->c2_qin) - pg->cp_sync_io = NULL; - } - return rc; -} -EXPORT_SYMBOL(cl_io_submit_sync); - -/** - * Main io loop. - * - * Pumps io through iterations calling - * - * - cl_io_iter_init() - * - * - cl_io_lock() - * - * - cl_io_start() - * - * - cl_io_end() - * - * - cl_io_unlock() - * - * - cl_io_iter_fini() - * - * repeatedly until there is no more io to do. - */ -int cl_io_loop(const struct lu_env *env, struct cl_io *io) -{ - int result = 0; - - LINVRNT(cl_io_is_loopable(io)); - - do { - size_t nob; - - io->ci_continue = 0; - result = cl_io_iter_init(env, io); - if (result == 0) { - nob = io->ci_nob; - result = cl_io_lock(env, io); - if (result == 0) { - /* - * Notify layers that locks has been taken, - * and do actual i/o. - * - * - llite: kms, short read; - * - llite: generic_file_read(); - */ - result = cl_io_start(env, io); - /* - * Send any remaining pending - * io, etc. - * - * - llite: ll_rw_stats_tally. - */ - cl_io_end(env, io); - cl_io_unlock(env, io); - cl_io_rw_advance(env, io, io->ci_nob - nob); - } - } - cl_io_iter_fini(env, io); - } while (result == 0 && io->ci_continue); - if (result == 0) - result = io->ci_result; - return result < 0 ? result : 0; -} -EXPORT_SYMBOL(cl_io_loop); - -/** - * Adds io slice to the cl_io. - * - * This is called by cl_object_operations::coo_io_init() methods to add a - * per-layer state to the io. New state is added at the end of - * cl_io::ci_layers list, that is, it is at the bottom of the stack. - * - * \see cl_lock_slice_add(), cl_req_slice_add(), cl_page_slice_add() - */ -void cl_io_slice_add(struct cl_io *io, struct cl_io_slice *slice, - struct cl_object *obj, - const struct cl_io_operations *ops) -{ - struct list_head *linkage = &slice->cis_linkage; - - LASSERT((!linkage->prev && !linkage->next) || - list_empty(linkage)); - - list_add_tail(linkage, &io->ci_layers); - slice->cis_io = io; - slice->cis_obj = obj; - slice->cis_iop = ops; -} -EXPORT_SYMBOL(cl_io_slice_add); - -/** - * Initializes page list. - */ -void cl_page_list_init(struct cl_page_list *plist) -{ - plist->pl_nr = 0; - INIT_LIST_HEAD(&plist->pl_pages); - plist->pl_owner = current; -} -EXPORT_SYMBOL(cl_page_list_init); - -/** - * Adds a page to a page list. - */ -void cl_page_list_add(struct cl_page_list *plist, struct cl_page *page) -{ - /* it would be better to check that page is owned by "current" io, but - * it is not passed here. - */ - LASSERT(page->cp_owner); - LINVRNT(plist->pl_owner == current); - - LASSERT(list_empty(&page->cp_batch)); - list_add_tail(&page->cp_batch, &plist->pl_pages); - ++plist->pl_nr; - lu_ref_add_at(&page->cp_reference, &page->cp_queue_ref, "queue", plist); - cl_page_get(page); -} -EXPORT_SYMBOL(cl_page_list_add); - -/** - * Removes a page from a page list. - */ -void cl_page_list_del(const struct lu_env *env, struct cl_page_list *plist, - struct cl_page *page) -{ - LASSERT(plist->pl_nr > 0); - LASSERT(cl_page_is_vmlocked(env, page)); - LINVRNT(plist->pl_owner == current); - - list_del_init(&page->cp_batch); - --plist->pl_nr; - lu_ref_del_at(&page->cp_reference, &page->cp_queue_ref, "queue", plist); - cl_page_put(env, page); -} -EXPORT_SYMBOL(cl_page_list_del); - -/** - * Moves a page from one page list to another. - */ -void cl_page_list_move(struct cl_page_list *dst, struct cl_page_list *src, - struct cl_page *page) -{ - LASSERT(src->pl_nr > 0); - LINVRNT(dst->pl_owner == current); - LINVRNT(src->pl_owner == current); - - list_move_tail(&page->cp_batch, &dst->pl_pages); - --src->pl_nr; - ++dst->pl_nr; - lu_ref_set_at(&page->cp_reference, &page->cp_queue_ref, "queue", - src, dst); -} -EXPORT_SYMBOL(cl_page_list_move); - -/** - * Moves a page from one page list to the head of another list. - */ -void cl_page_list_move_head(struct cl_page_list *dst, struct cl_page_list *src, - struct cl_page *page) -{ - LASSERT(src->pl_nr > 0); - LINVRNT(dst->pl_owner == current); - LINVRNT(src->pl_owner == current); - - list_move(&page->cp_batch, &dst->pl_pages); - --src->pl_nr; - ++dst->pl_nr; - lu_ref_set_at(&page->cp_reference, &page->cp_queue_ref, "queue", - src, dst); -} -EXPORT_SYMBOL(cl_page_list_move_head); - -/** - * splice the cl_page_list, just as list head does - */ -void cl_page_list_splice(struct cl_page_list *list, struct cl_page_list *head) -{ - struct cl_page *page; - struct cl_page *tmp; - - LINVRNT(list->pl_owner == current); - LINVRNT(head->pl_owner == current); - - cl_page_list_for_each_safe(page, tmp, list) - cl_page_list_move(head, list, page); -} -EXPORT_SYMBOL(cl_page_list_splice); - - -/** - * Disowns pages in a queue. - */ -void cl_page_list_disown(const struct lu_env *env, - struct cl_io *io, struct cl_page_list *plist) -{ - struct cl_page *page; - struct cl_page *temp; - - LINVRNT(plist->pl_owner == current); - - cl_page_list_for_each_safe(page, temp, plist) { - LASSERT(plist->pl_nr > 0); - - list_del_init(&page->cp_batch); - --plist->pl_nr; - /* - * cl_page_disown0 rather than usual cl_page_disown() is used, - * because pages are possibly in CPS_FREEING state already due - * to the call to cl_page_list_discard(). - */ - /* - * XXX cl_page_disown0() will fail if page is not locked. - */ - cl_page_disown0(env, io, page); - lu_ref_del_at(&page->cp_reference, &page->cp_queue_ref, "queue", - plist); - cl_page_put(env, page); - } -} -EXPORT_SYMBOL(cl_page_list_disown); - -/** - * Releases pages from queue. - */ -void cl_page_list_fini(const struct lu_env *env, struct cl_page_list *plist) -{ - struct cl_page *page; - struct cl_page *temp; - - LINVRNT(plist->pl_owner == current); - - cl_page_list_for_each_safe(page, temp, plist) - cl_page_list_del(env, plist, page); - LASSERT(plist->pl_nr == 0); -} -EXPORT_SYMBOL(cl_page_list_fini); - -/** - * Assumes all pages in a queue. - */ -static void cl_page_list_assume(const struct lu_env *env, - struct cl_io *io, struct cl_page_list *plist) -{ - struct cl_page *page; - - LINVRNT(plist->pl_owner == current); - - cl_page_list_for_each(page, plist) - cl_page_assume(env, io, page); -} - -/** - * Discards all pages in a queue. - */ -static void cl_page_list_discard(const struct lu_env *env, struct cl_io *io, - struct cl_page_list *plist) -{ - struct cl_page *page; - - LINVRNT(plist->pl_owner == current); - cl_page_list_for_each(page, plist) - cl_page_discard(env, io, page); -} - -/** - * Initialize dual page queue. - */ -void cl_2queue_init(struct cl_2queue *queue) -{ - cl_page_list_init(&queue->c2_qin); - cl_page_list_init(&queue->c2_qout); -} -EXPORT_SYMBOL(cl_2queue_init); - -/** - * Disown pages in both lists of a 2-queue. - */ -void cl_2queue_disown(const struct lu_env *env, - struct cl_io *io, struct cl_2queue *queue) -{ - cl_page_list_disown(env, io, &queue->c2_qin); - cl_page_list_disown(env, io, &queue->c2_qout); -} -EXPORT_SYMBOL(cl_2queue_disown); - -/** - * Discard (truncate) pages in both lists of a 2-queue. - */ -void cl_2queue_discard(const struct lu_env *env, - struct cl_io *io, struct cl_2queue *queue) -{ - cl_page_list_discard(env, io, &queue->c2_qin); - cl_page_list_discard(env, io, &queue->c2_qout); -} -EXPORT_SYMBOL(cl_2queue_discard); - -/** - * Finalize both page lists of a 2-queue. - */ -void cl_2queue_fini(const struct lu_env *env, struct cl_2queue *queue) -{ - cl_page_list_fini(env, &queue->c2_qout); - cl_page_list_fini(env, &queue->c2_qin); -} -EXPORT_SYMBOL(cl_2queue_fini); - -/** - * Initialize a 2-queue to contain \a page in its incoming page list. - */ -void cl_2queue_init_page(struct cl_2queue *queue, struct cl_page *page) -{ - cl_2queue_init(queue); - /* - * Add a page to the incoming page list of 2-queue. - */ - cl_page_list_add(&queue->c2_qin, page); -} -EXPORT_SYMBOL(cl_2queue_init_page); - -/** - * Returns top-level io. - * - * \see cl_object_top() - */ -struct cl_io *cl_io_top(struct cl_io *io) -{ - while (io->ci_parent) - io = io->ci_parent; - return io; -} -EXPORT_SYMBOL(cl_io_top); - -/** - * Fills in attributes that are passed to server together with transfer. Only - * attributes from \a flags may be touched. This can be called multiple times - * for the same request. - */ -void cl_req_attr_set(const struct lu_env *env, struct cl_object *obj, - struct cl_req_attr *attr) -{ - struct cl_object *scan; - - cl_object_for_each(scan, obj) { - if (scan->co_ops->coo_req_attr_set) - scan->co_ops->coo_req_attr_set(env, scan, attr); - } -} -EXPORT_SYMBOL(cl_req_attr_set); - -/* cl_sync_io_callback assumes the caller must call cl_sync_io_wait() to - * wait for the IO to finish. - */ -void cl_sync_io_end(const struct lu_env *env, struct cl_sync_io *anchor) -{ - wake_up_all(&anchor->csi_waitq); - - /* it's safe to nuke or reuse anchor now */ - atomic_set(&anchor->csi_barrier, 0); -} -EXPORT_SYMBOL(cl_sync_io_end); - -/** - * Initialize synchronous io wait anchor - */ -void cl_sync_io_init(struct cl_sync_io *anchor, int nr, - void (*end)(const struct lu_env *, struct cl_sync_io *)) -{ - memset(anchor, 0, sizeof(*anchor)); - init_waitqueue_head(&anchor->csi_waitq); - atomic_set(&anchor->csi_sync_nr, nr); - atomic_set(&anchor->csi_barrier, nr > 0); - anchor->csi_sync_rc = 0; - anchor->csi_end_io = end; - LASSERT(end); -} -EXPORT_SYMBOL(cl_sync_io_init); - -/** - * Wait until all IO completes. Transfer completion routine has to call - * cl_sync_io_note() for every entity. - */ -int cl_sync_io_wait(const struct lu_env *env, struct cl_sync_io *anchor, - long timeout) -{ - int rc = 1; - - LASSERT(timeout >= 0); - - if (timeout == 0) - wait_event_idle(anchor->csi_waitq, - atomic_read(&anchor->csi_sync_nr) == 0); - else - rc = wait_event_idle_timeout(anchor->csi_waitq, - atomic_read(&anchor->csi_sync_nr) == 0, - timeout * HZ); - if (rc == 0) { - rc = -ETIMEDOUT; - CERROR("IO failed: %d, still wait for %d remaining entries\n", - rc, atomic_read(&anchor->csi_sync_nr)); - - wait_event_idle(anchor->csi_waitq, - atomic_read(&anchor->csi_sync_nr) == 0); - } else { - rc = anchor->csi_sync_rc; - } - LASSERT(atomic_read(&anchor->csi_sync_nr) == 0); - - /* wait until cl_sync_io_note() has done wakeup */ - while (unlikely(atomic_read(&anchor->csi_barrier) != 0)) - cpu_relax(); - - - return rc; -} -EXPORT_SYMBOL(cl_sync_io_wait); - -/** - * Indicate that transfer of a single page completed. - */ -void cl_sync_io_note(const struct lu_env *env, struct cl_sync_io *anchor, - int ioret) -{ - if (anchor->csi_sync_rc == 0 && ioret < 0) - anchor->csi_sync_rc = ioret; - /* - * Synchronous IO done without releasing page lock (e.g., as a part of - * ->{prepare,commit}_write(). Completion is used to signal the end of - * IO. - */ - LASSERT(atomic_read(&anchor->csi_sync_nr) > 0); - if (atomic_dec_and_test(&anchor->csi_sync_nr)) { - LASSERT(anchor->csi_end_io); - anchor->csi_end_io(env, anchor); - /* Can't access anchor any more */ - } -} -EXPORT_SYMBOL(cl_sync_io_note); diff --git a/drivers/staging/lustre/lustre/obdclass/cl_lock.c b/drivers/staging/lustre/lustre/obdclass/cl_lock.c deleted file mode 100644 index 9ca29a26a38b..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/cl_lock.c +++ /dev/null @@ -1,275 +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) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2011, 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * Client Extent Lock. - * - * Author: Nikita Danilov <nikita.danilov@sun.com> - * Author: Jinshan Xiong <jinshan.xiong@intel.com> - */ - -#define DEBUG_SUBSYSTEM S_CLASS - -#include <obd_class.h> -#include <obd_support.h> -#include <lustre_fid.h> -#include <linux/list.h> -#include <cl_object.h> -#include "cl_internal.h" - -static void cl_lock_trace0(int level, const struct lu_env *env, - const char *prefix, const struct cl_lock *lock, - const char *func, const int line) -{ - struct cl_object_header *h = cl_object_header(lock->cll_descr.cld_obj); - - CDEBUG(level, "%s: %p (%p/%d) at %s():%d\n", - prefix, lock, env, h->coh_nesting, func, line); -} -#define cl_lock_trace(level, env, prefix, lock) \ - cl_lock_trace0(level, env, prefix, lock, __func__, __LINE__) - -/** - * Adds lock slice to the compound lock. - * - * This is called by cl_object_operations::coo_lock_init() methods to add a - * per-layer state to the lock. New state is added at the end of - * cl_lock::cll_layers list, that is, it is at the bottom of the stack. - * - * \see cl_req_slice_add(), cl_page_slice_add(), cl_io_slice_add() - */ -void cl_lock_slice_add(struct cl_lock *lock, struct cl_lock_slice *slice, - struct cl_object *obj, - const struct cl_lock_operations *ops) -{ - slice->cls_lock = lock; - list_add_tail(&slice->cls_linkage, &lock->cll_layers); - slice->cls_obj = obj; - slice->cls_ops = ops; -} -EXPORT_SYMBOL(cl_lock_slice_add); - -void cl_lock_fini(const struct lu_env *env, struct cl_lock *lock) -{ - struct cl_lock_slice *slice; - cl_lock_trace(D_DLMTRACE, env, "destroy lock", lock); - - while ((slice = list_first_entry_or_null(&lock->cll_layers, - struct cl_lock_slice, - cls_linkage)) != NULL) { - list_del_init(lock->cll_layers.next); - slice->cls_ops->clo_fini(env, slice); - } - POISON(lock, 0x5a, sizeof(*lock)); -} -EXPORT_SYMBOL(cl_lock_fini); - -int cl_lock_init(const struct lu_env *env, struct cl_lock *lock, - const struct cl_io *io) -{ - struct cl_object *obj = lock->cll_descr.cld_obj; - struct cl_object *scan; - int result = 0; - - /* Make sure cl_lock::cll_descr is initialized. */ - LASSERT(obj); - - INIT_LIST_HEAD(&lock->cll_layers); - list_for_each_entry(scan, &obj->co_lu.lo_header->loh_layers, - co_lu.lo_linkage) { - result = scan->co_ops->coo_lock_init(env, scan, lock, io); - if (result != 0) { - cl_lock_fini(env, lock); - break; - } - } - - return result; -} -EXPORT_SYMBOL(cl_lock_init); - -/** - * Returns a slice with a lock, corresponding to the given layer in the - * device stack. - * - * \see cl_page_at() - */ -const struct cl_lock_slice *cl_lock_at(const struct cl_lock *lock, - const struct lu_device_type *dtype) -{ - const struct cl_lock_slice *slice; - - list_for_each_entry(slice, &lock->cll_layers, cls_linkage) { - if (slice->cls_obj->co_lu.lo_dev->ld_type == dtype) - return slice; - } - return NULL; -} -EXPORT_SYMBOL(cl_lock_at); - -void cl_lock_cancel(const struct lu_env *env, struct cl_lock *lock) -{ - const struct cl_lock_slice *slice; - - cl_lock_trace(D_DLMTRACE, env, "cancel lock", lock); - list_for_each_entry_reverse(slice, &lock->cll_layers, cls_linkage) { - if (slice->cls_ops->clo_cancel) - slice->cls_ops->clo_cancel(env, slice); - } -} -EXPORT_SYMBOL(cl_lock_cancel); - -/** - * Enqueue a lock. - * \param anchor: if we need to wait for resources before getting the lock, - * use @anchor for the purpose. - * \retval 0 enqueue successfully - * \retval <0 error code - */ -int cl_lock_enqueue(const struct lu_env *env, struct cl_io *io, - struct cl_lock *lock, struct cl_sync_io *anchor) -{ - const struct cl_lock_slice *slice; - int rc = -ENOSYS; - - list_for_each_entry(slice, &lock->cll_layers, cls_linkage) { - if (!slice->cls_ops->clo_enqueue) - continue; - - rc = slice->cls_ops->clo_enqueue(env, slice, io, anchor); - if (rc != 0) - break; - } - return rc; -} -EXPORT_SYMBOL(cl_lock_enqueue); - -/** - * Main high-level entry point of cl_lock interface that finds existing or - * enqueues new lock matching given description. - */ -int cl_lock_request(const struct lu_env *env, struct cl_io *io, - struct cl_lock *lock) -{ - struct cl_sync_io *anchor = NULL; - __u32 enq_flags = lock->cll_descr.cld_enq_flags; - int rc; - - rc = cl_lock_init(env, lock, io); - if (rc < 0) - return rc; - - if ((enq_flags & CEF_ASYNC) && !(enq_flags & CEF_AGL)) { - anchor = &cl_env_info(env)->clt_anchor; - cl_sync_io_init(anchor, 1, cl_sync_io_end); - } - - rc = cl_lock_enqueue(env, io, lock, anchor); - - if (anchor) { - int rc2; - - /* drop the reference count held at initialization time */ - cl_sync_io_note(env, anchor, 0); - rc2 = cl_sync_io_wait(env, anchor, 0); - if (rc2 < 0 && rc == 0) - rc = rc2; - } - - if (rc < 0) - cl_lock_release(env, lock); - - return rc; -} -EXPORT_SYMBOL(cl_lock_request); - -/** - * Releases a hold and a reference on a lock, obtained by cl_lock_hold(). - */ -void cl_lock_release(const struct lu_env *env, struct cl_lock *lock) -{ - cl_lock_trace(D_DLMTRACE, env, "release lock", lock); - cl_lock_cancel(env, lock); - cl_lock_fini(env, lock); -} -EXPORT_SYMBOL(cl_lock_release); - -const char *cl_lock_mode_name(const enum cl_lock_mode mode) -{ - static const char * const names[] = { - [CLM_READ] = "R", - [CLM_WRITE] = "W", - [CLM_GROUP] = "G" - }; - if (0 <= mode && mode < ARRAY_SIZE(names)) - return names[mode]; - else - return "U"; -} -EXPORT_SYMBOL(cl_lock_mode_name); - -/** - * Prints human readable representation of a lock description. - */ -void cl_lock_descr_print(const struct lu_env *env, void *cookie, - lu_printer_t printer, - const struct cl_lock_descr *descr) -{ - const struct lu_fid *fid; - - fid = lu_object_fid(&descr->cld_obj->co_lu); - (*printer)(env, cookie, DDESCR "@" DFID, PDESCR(descr), PFID(fid)); -} -EXPORT_SYMBOL(cl_lock_descr_print); - -/** - * Prints human readable representation of \a lock to the \a f. - */ -void cl_lock_print(const struct lu_env *env, void *cookie, - lu_printer_t printer, const struct cl_lock *lock) -{ - const struct cl_lock_slice *slice; - - (*printer)(env, cookie, "lock@%p", lock); - cl_lock_descr_print(env, cookie, printer, &lock->cll_descr); - (*printer)(env, cookie, " {\n"); - - list_for_each_entry(slice, &lock->cll_layers, cls_linkage) { - (*printer)(env, cookie, " %s@%p: ", - slice->cls_obj->co_lu.lo_dev->ld_type->ldt_name, - slice); - if (slice->cls_ops->clo_print) - slice->cls_ops->clo_print(env, cookie, printer, slice); - (*printer)(env, cookie, "\n"); - } - (*printer)(env, cookie, "} lock@%p\n", lock); -} -EXPORT_SYMBOL(cl_lock_print); diff --git a/drivers/staging/lustre/lustre/obdclass/cl_object.c b/drivers/staging/lustre/lustre/obdclass/cl_object.c deleted file mode 100644 index 7809f6ae1809..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/cl_object.c +++ /dev/null @@ -1,1061 +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) 2008, 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. - * - * Client Lustre Object. - * - * Author: Nikita Danilov <nikita.danilov@sun.com> - * Author: Jinshan Xiong <jinshan.xiong@intel.com> - */ - -/* - * Locking. - * - * i_mutex - * PG_locked - * ->coh_attr_guard - * ->ls_guard - */ - -#define DEBUG_SUBSYSTEM S_CLASS - -#include <linux/libcfs/libcfs.h> -/* class_put_type() */ -#include <obd_class.h> -#include <obd_support.h> -#include <lustre_fid.h> -#include <linux/list.h> -#include <linux/libcfs/libcfs_hash.h> /* for cfs_hash stuff */ -#include <cl_object.h> -#include <lu_object.h> -#include "cl_internal.h" - -static struct kmem_cache *cl_env_kmem; - -/** Lock class of cl_object_header::coh_attr_guard */ -static struct lock_class_key cl_attr_guard_class; - -/** - * Initialize cl_object_header. - */ -int cl_object_header_init(struct cl_object_header *h) -{ - int result; - - result = lu_object_header_init(&h->coh_lu); - if (result == 0) { - spin_lock_init(&h->coh_attr_guard); - lockdep_set_class(&h->coh_attr_guard, &cl_attr_guard_class); - h->coh_page_bufsize = 0; - } - return result; -} -EXPORT_SYMBOL(cl_object_header_init); - -/** - * Returns a cl_object with a given \a fid. - * - * Returns either cached or newly created object. Additional reference on the - * returned object is acquired. - * - * \see lu_object_find(), cl_page_find(), cl_lock_find() - */ -struct cl_object *cl_object_find(const struct lu_env *env, - struct cl_device *cd, const struct lu_fid *fid, - const struct cl_object_conf *c) -{ - might_sleep(); - return lu2cl(lu_object_find_slice(env, cl2lu_dev(cd), fid, &c->coc_lu)); -} -EXPORT_SYMBOL(cl_object_find); - -/** - * Releases a reference on \a o. - * - * When last reference is released object is returned to the cache, unless - * lu_object_header_flags::LU_OBJECT_HEARD_BANSHEE bit is set in its header. - * - * \see cl_page_put(), cl_lock_put(). - */ -void cl_object_put(const struct lu_env *env, struct cl_object *o) -{ - lu_object_put(env, &o->co_lu); -} -EXPORT_SYMBOL(cl_object_put); - -/** - * Acquire an additional reference to the object \a o. - * - * This can only be used to acquire _additional_ reference, i.e., caller - * already has to possess at least one reference to \a o before calling this. - * - * \see cl_page_get(), cl_lock_get(). - */ -void cl_object_get(struct cl_object *o) -{ - lu_object_get(&o->co_lu); -} -EXPORT_SYMBOL(cl_object_get); - -/** - * Returns the top-object for a given \a o. - * - * \see cl_io_top() - */ -struct cl_object *cl_object_top(struct cl_object *o) -{ - struct cl_object_header *hdr = cl_object_header(o); - struct cl_object *top; - - while (hdr->coh_parent) - hdr = hdr->coh_parent; - - top = lu2cl(lu_object_top(&hdr->coh_lu)); - CDEBUG(D_TRACE, "%p -> %p\n", o, top); - return top; -} -EXPORT_SYMBOL(cl_object_top); - -/** - * Returns pointer to the lock protecting data-attributes for the given object - * \a o. - * - * Data-attributes are protected by the cl_object_header::coh_attr_guard - * spin-lock in the top-object. - * - * \see cl_attr, cl_object_attr_lock(), cl_object_operations::coo_attr_get(). - */ -static spinlock_t *cl_object_attr_guard(struct cl_object *o) -{ - return &cl_object_header(cl_object_top(o))->coh_attr_guard; -} - -/** - * Locks data-attributes. - * - * Prevents data-attributes from changing, until lock is released by - * cl_object_attr_unlock(). This has to be called before calls to - * cl_object_attr_get(), cl_object_attr_update(). - */ -void cl_object_attr_lock(struct cl_object *o) - __acquires(cl_object_attr_guard(o)) -{ - spin_lock(cl_object_attr_guard(o)); -} -EXPORT_SYMBOL(cl_object_attr_lock); - -/** - * Releases data-attributes lock, acquired by cl_object_attr_lock(). - */ -void cl_object_attr_unlock(struct cl_object *o) - __releases(cl_object_attr_guard(o)) -{ - spin_unlock(cl_object_attr_guard(o)); -} -EXPORT_SYMBOL(cl_object_attr_unlock); - -/** - * Returns data-attributes of an object \a obj. - * - * Every layer is asked (by calling cl_object_operations::coo_attr_get()) - * top-to-bottom to fill in parts of \a attr that this layer is responsible - * for. - */ -int cl_object_attr_get(const struct lu_env *env, struct cl_object *obj, - struct cl_attr *attr) -{ - struct lu_object_header *top; - int result; - - assert_spin_locked(cl_object_attr_guard(obj)); - - top = obj->co_lu.lo_header; - result = 0; - list_for_each_entry(obj, &top->loh_layers, co_lu.lo_linkage) { - if (obj->co_ops->coo_attr_get) { - result = obj->co_ops->coo_attr_get(env, obj, attr); - if (result != 0) { - if (result > 0) - result = 0; - break; - } - } - } - return result; -} -EXPORT_SYMBOL(cl_object_attr_get); - -/** - * Updates data-attributes of an object \a obj. - * - * Only attributes, mentioned in a validness bit-mask \a v are - * updated. Calls cl_object_operations::coo_attr_update() on every layer, - * bottom to top. - */ -int cl_object_attr_update(const struct lu_env *env, struct cl_object *obj, - const struct cl_attr *attr, unsigned int v) -{ - struct lu_object_header *top; - int result; - - assert_spin_locked(cl_object_attr_guard(obj)); - - top = obj->co_lu.lo_header; - result = 0; - list_for_each_entry_reverse(obj, &top->loh_layers, co_lu.lo_linkage) { - if (obj->co_ops->coo_attr_update) { - result = obj->co_ops->coo_attr_update(env, obj, attr, - v); - if (result != 0) { - if (result > 0) - result = 0; - break; - } - } - } - return result; -} -EXPORT_SYMBOL(cl_object_attr_update); - -/** - * Notifies layers (bottom-to-top) that glimpse AST was received. - * - * Layers have to fill \a lvb fields with information that will be shipped - * back to glimpse issuer. - * - * \see cl_lock_operations::clo_glimpse() - */ -int cl_object_glimpse(const struct lu_env *env, struct cl_object *obj, - struct ost_lvb *lvb) -{ - struct lu_object_header *top; - int result; - - top = obj->co_lu.lo_header; - result = 0; - list_for_each_entry_reverse(obj, &top->loh_layers, co_lu.lo_linkage) { - if (obj->co_ops->coo_glimpse) { - result = obj->co_ops->coo_glimpse(env, obj, lvb); - if (result != 0) - break; - } - } - LU_OBJECT_HEADER(D_DLMTRACE, env, lu_object_top(top), - "size: %llu mtime: %llu atime: %llu ctime: %llu blocks: %llu\n", - lvb->lvb_size, lvb->lvb_mtime, lvb->lvb_atime, - lvb->lvb_ctime, lvb->lvb_blocks); - return result; -} -EXPORT_SYMBOL(cl_object_glimpse); - -/** - * Updates a configuration of an object \a obj. - */ -int cl_conf_set(const struct lu_env *env, struct cl_object *obj, - const struct cl_object_conf *conf) -{ - struct lu_object_header *top; - int result; - - top = obj->co_lu.lo_header; - result = 0; - list_for_each_entry(obj, &top->loh_layers, co_lu.lo_linkage) { - if (obj->co_ops->coo_conf_set) { - result = obj->co_ops->coo_conf_set(env, obj, conf); - if (result != 0) - break; - } - } - return result; -} -EXPORT_SYMBOL(cl_conf_set); - -/** - * Prunes caches of pages and locks for this object. - */ -int cl_object_prune(const struct lu_env *env, struct cl_object *obj) -{ - struct lu_object_header *top; - struct cl_object *o; - int result; - - top = obj->co_lu.lo_header; - result = 0; - list_for_each_entry(o, &top->loh_layers, co_lu.lo_linkage) { - if (o->co_ops->coo_prune) { - result = o->co_ops->coo_prune(env, o); - if (result != 0) - break; - } - } - - return result; -} -EXPORT_SYMBOL(cl_object_prune); - -/** - * Get stripe information of this object. - */ -int cl_object_getstripe(const struct lu_env *env, struct cl_object *obj, - struct lov_user_md __user *uarg) -{ - struct lu_object_header *top; - int result = 0; - - top = obj->co_lu.lo_header; - list_for_each_entry(obj, &top->loh_layers, co_lu.lo_linkage) { - if (obj->co_ops->coo_getstripe) { - result = obj->co_ops->coo_getstripe(env, obj, uarg); - if (result) - break; - } - } - return result; -} -EXPORT_SYMBOL(cl_object_getstripe); - -/** - * Get fiemap extents from file object. - * - * \param env [in] lustre environment - * \param obj [in] file object - * \param key [in] fiemap request argument - * \param fiemap [out] fiemap extents mapping retrived - * \param buflen [in] max buffer length of @fiemap - * - * \retval 0 success - * \retval < 0 error - */ -int cl_object_fiemap(const struct lu_env *env, struct cl_object *obj, - struct ll_fiemap_info_key *key, - struct fiemap *fiemap, size_t *buflen) -{ - struct lu_object_header *top; - int result = 0; - - top = obj->co_lu.lo_header; - list_for_each_entry(obj, &top->loh_layers, co_lu.lo_linkage) { - if (obj->co_ops->coo_fiemap) { - result = obj->co_ops->coo_fiemap(env, obj, key, fiemap, - buflen); - if (result) - break; - } - } - return result; -} -EXPORT_SYMBOL(cl_object_fiemap); - -int cl_object_layout_get(const struct lu_env *env, struct cl_object *obj, - struct cl_layout *cl) -{ - struct lu_object_header *top = obj->co_lu.lo_header; - - list_for_each_entry(obj, &top->loh_layers, co_lu.lo_linkage) { - if (obj->co_ops->coo_layout_get) - return obj->co_ops->coo_layout_get(env, obj, cl); - } - - return -EOPNOTSUPP; -} -EXPORT_SYMBOL(cl_object_layout_get); - -loff_t cl_object_maxbytes(struct cl_object *obj) -{ - struct lu_object_header *top = obj->co_lu.lo_header; - loff_t maxbytes = LLONG_MAX; - - list_for_each_entry(obj, &top->loh_layers, co_lu.lo_linkage) { - if (obj->co_ops->coo_maxbytes) - maxbytes = min_t(loff_t, obj->co_ops->coo_maxbytes(obj), - maxbytes); - } - - return maxbytes; -} -EXPORT_SYMBOL(cl_object_maxbytes); - -/** - * Helper function removing all object locks, and marking object for - * deletion. All object pages must have been deleted at this point. - * - * This is called by cl_inode_fini() and lov_object_delete() to destroy top- - * and sub- objects respectively. - */ -void cl_object_kill(const struct lu_env *env, struct cl_object *obj) -{ - struct cl_object_header *hdr = cl_object_header(obj); - - set_bit(LU_OBJECT_HEARD_BANSHEE, &hdr->coh_lu.loh_flags); -} -EXPORT_SYMBOL(cl_object_kill); - -void cache_stats_init(struct cache_stats *cs, const char *name) -{ - int i; - - cs->cs_name = name; - for (i = 0; i < CS_NR; i++) - atomic_set(&cs->cs_stats[i], 0); -} - -static int cache_stats_print(const struct cache_stats *cs, - struct seq_file *m, int h) -{ - int i; - /* - * lookup hit total cached create - * env: ...... ...... ...... ...... ...... - */ - if (h) { - const char *names[CS_NR] = CS_NAMES; - - seq_printf(m, "%6s", " "); - for (i = 0; i < CS_NR; i++) - seq_printf(m, "%8s", names[i]); - seq_printf(m, "\n"); - } - - seq_printf(m, "%5.5s:", cs->cs_name); - for (i = 0; i < CS_NR; i++) - seq_printf(m, "%8u", atomic_read(&cs->cs_stats[i])); - return 0; -} - -static void cl_env_percpu_refill(void); - -/** - * Initialize client site. - * - * Perform common initialization (lu_site_init()), and initialize statistical - * counters. Also perform global initializations on the first call. - */ -int cl_site_init(struct cl_site *s, struct cl_device *d) -{ - size_t i; - int result; - - result = lu_site_init(&s->cs_lu, &d->cd_lu_dev); - if (result == 0) { - cache_stats_init(&s->cs_pages, "pages"); - for (i = 0; i < ARRAY_SIZE(s->cs_pages_state); ++i) - atomic_set(&s->cs_pages_state[0], 0); - cl_env_percpu_refill(); - } - return result; -} -EXPORT_SYMBOL(cl_site_init); - -/** - * Finalize client site. Dual to cl_site_init(). - */ -void cl_site_fini(struct cl_site *s) -{ - lu_site_fini(&s->cs_lu); -} -EXPORT_SYMBOL(cl_site_fini); - -static struct cache_stats cl_env_stats = { - .cs_name = "envs", - .cs_stats = { ATOMIC_INIT(0), } -}; - -/** - * Outputs client site statistical counters into a buffer. Suitable for - * ll_rd_*()-style functions. - */ -int cl_site_stats_print(const struct cl_site *site, struct seq_file *m) -{ - size_t i; - static const char * const pstate[] = { - [CPS_CACHED] = "c", - [CPS_OWNED] = "o", - [CPS_PAGEOUT] = "w", - [CPS_PAGEIN] = "r", - [CPS_FREEING] = "f" - }; -/* - lookup hit total busy create -pages: ...... ...... ...... ...... ...... [...... ...... ...... ......] -locks: ...... ...... ...... ...... ...... [...... ...... ...... ...... ......] - env: ...... ...... ...... ...... ...... - */ - lu_site_stats_print(&site->cs_lu, m); - cache_stats_print(&site->cs_pages, m, 1); - seq_puts(m, " ["); - for (i = 0; i < ARRAY_SIZE(site->cs_pages_state); ++i) - seq_printf(m, "%s: %u ", pstate[i], - atomic_read(&site->cs_pages_state[i])); - seq_puts(m, "]\n"); - cache_stats_print(&cl_env_stats, m, 0); - seq_puts(m, "\n"); - return 0; -} -EXPORT_SYMBOL(cl_site_stats_print); - -/***************************************************************************** - * - * lu_env handling on client. - * - */ - -/** - * The most efficient way is to store cl_env pointer in task specific - * structures. On Linux, it wont' be easy to use task_struct->journal_info - * because Lustre code may call into other fs which has certain assumptions - * about journal_info. Currently following fields in task_struct are identified - * can be used for this purpose: - * - tux_info: only on RedHat kernel. - * - ... - * \note As long as we use task_struct to store cl_env, we assume that once - * called into Lustre, we'll never call into the other part of the kernel - * which will use those fields in task_struct without explicitly exiting - * Lustre. - * - * If there's no space in task_struct is available, hash will be used. - * bz20044, bz22683. - */ - -static unsigned int cl_envs_cached_max = 32; /* XXX: prototype: arbitrary limit - * for now. - */ -static struct cl_env_cache { - rwlock_t cec_guard; - unsigned int cec_count; - struct list_head cec_envs; -} *cl_envs = NULL; - -struct cl_env { - void *ce_magic; - struct lu_env ce_lu; - struct lu_context ce_ses; - - /* - * Linkage into global list of all client environments. Used for - * garbage collection. - */ - struct list_head ce_linkage; - /* - * - */ - int ce_ref; - /* - * Debugging field: address of the caller who made original - * allocation. - */ - void *ce_debug; -}; - -#define CL_ENV_INC(counter) -#define CL_ENV_DEC(counter) - -static void cl_env_init0(struct cl_env *cle, void *debug) -{ - LASSERT(cle->ce_ref == 0); - LASSERT(cle->ce_magic == &cl_env_init0); - LASSERT(!cle->ce_debug); - - cle->ce_ref = 1; - cle->ce_debug = debug; - CL_ENV_INC(busy); -} - -static struct lu_env *cl_env_new(__u32 ctx_tags, __u32 ses_tags, void *debug) -{ - struct lu_env *env; - struct cl_env *cle; - - cle = kmem_cache_zalloc(cl_env_kmem, GFP_NOFS); - if (cle) { - int rc; - - INIT_LIST_HEAD(&cle->ce_linkage); - cle->ce_magic = &cl_env_init0; - env = &cle->ce_lu; - rc = lu_env_init(env, ctx_tags | LCT_CL_THREAD); - if (rc == 0) { - rc = lu_context_init(&cle->ce_ses, - ses_tags | LCT_SESSION); - if (rc == 0) { - lu_context_enter(&cle->ce_ses); - env->le_ses = &cle->ce_ses; - cl_env_init0(cle, debug); - } else { - lu_env_fini(env); - } - } - if (rc != 0) { - kmem_cache_free(cl_env_kmem, cle); - env = ERR_PTR(rc); - } else { - CL_ENV_INC(create); - CL_ENV_INC(total); - } - } else { - env = ERR_PTR(-ENOMEM); - } - return env; -} - -static void cl_env_fini(struct cl_env *cle) -{ - CL_ENV_DEC(total); - lu_context_fini(&cle->ce_lu.le_ctx); - lu_context_fini(&cle->ce_ses); - kmem_cache_free(cl_env_kmem, cle); -} - -static struct lu_env *cl_env_obtain(void *debug) -{ - struct cl_env *cle; - struct lu_env *env; - int cpu = get_cpu(); - - read_lock(&cl_envs[cpu].cec_guard); - LASSERT(equi(cl_envs[cpu].cec_count == 0, - list_empty(&cl_envs[cpu].cec_envs))); - if (cl_envs[cpu].cec_count > 0) { - int rc; - - cle = container_of(cl_envs[cpu].cec_envs.next, struct cl_env, - ce_linkage); - list_del_init(&cle->ce_linkage); - cl_envs[cpu].cec_count--; - read_unlock(&cl_envs[cpu].cec_guard); - put_cpu(); - - env = &cle->ce_lu; - rc = lu_env_refill(env); - if (rc == 0) { - cl_env_init0(cle, debug); - lu_context_enter(&env->le_ctx); - lu_context_enter(&cle->ce_ses); - } else { - cl_env_fini(cle); - env = ERR_PTR(rc); - } - } else { - read_unlock(&cl_envs[cpu].cec_guard); - put_cpu(); - env = cl_env_new(lu_context_tags_default, - lu_session_tags_default, debug); - } - return env; -} - -static inline struct cl_env *cl_env_container(struct lu_env *env) -{ - return container_of(env, struct cl_env, ce_lu); -} - -/** - * Returns lu_env: if there already is an environment associated with the - * current thread, it is returned, otherwise, new environment is allocated. - * - * Allocations are amortized through the global cache of environments. - * - * \param refcheck pointer to a counter used to detect environment leaks. In - * the usual case cl_env_get() and cl_env_put() are called in the same lexical - * scope and pointer to the same integer is passed as \a refcheck. This is - * used to detect missed cl_env_put(). - * - * \see cl_env_put() - */ -struct lu_env *cl_env_get(u16 *refcheck) -{ - struct lu_env *env; - - env = cl_env_obtain(__builtin_return_address(0)); - if (!IS_ERR(env)) { - struct cl_env *cle; - - cle = cl_env_container(env); - *refcheck = cle->ce_ref; - CDEBUG(D_OTHER, "%d@%p\n", cle->ce_ref, cle); - } - return env; -} -EXPORT_SYMBOL(cl_env_get); - -/** - * Forces an allocation of a fresh environment with given tags. - * - * \see cl_env_get() - */ -struct lu_env *cl_env_alloc(u16 *refcheck, u32 tags) -{ - struct lu_env *env; - - env = cl_env_new(tags, tags, __builtin_return_address(0)); - if (!IS_ERR(env)) { - struct cl_env *cle; - - cle = cl_env_container(env); - *refcheck = cle->ce_ref; - CDEBUG(D_OTHER, "%d@%p\n", cle->ce_ref, cle); - } - return env; -} -EXPORT_SYMBOL(cl_env_alloc); - -static void cl_env_exit(struct cl_env *cle) -{ - lu_context_exit(&cle->ce_lu.le_ctx); - lu_context_exit(&cle->ce_ses); -} - -/** - * Finalizes and frees a given number of cached environments. This is done to - * (1) free some memory (not currently hooked into VM), or (2) release - * references to modules. - */ -unsigned int cl_env_cache_purge(unsigned int nr) -{ - struct cl_env *cle; - unsigned int i; - - for_each_possible_cpu(i) { - write_lock(&cl_envs[i].cec_guard); - for (; !list_empty(&cl_envs[i].cec_envs) && nr > 0; --nr) { - cle = container_of(cl_envs[i].cec_envs.next, - struct cl_env, ce_linkage); - list_del_init(&cle->ce_linkage); - LASSERT(cl_envs[i].cec_count > 0); - cl_envs[i].cec_count--; - write_unlock(&cl_envs[i].cec_guard); - - cl_env_fini(cle); - write_lock(&cl_envs[i].cec_guard); - } - LASSERT(equi(cl_envs[i].cec_count == 0, - list_empty(&cl_envs[i].cec_envs))); - write_unlock(&cl_envs[i].cec_guard); - } - return nr; -} -EXPORT_SYMBOL(cl_env_cache_purge); - -/** - * Release an environment. - * - * Decrement \a env reference counter. When counter drops to 0, nothing in - * this thread is using environment and it is returned to the allocation - * cache, or freed straight away, if cache is large enough. - */ -void cl_env_put(struct lu_env *env, u16 *refcheck) -{ - struct cl_env *cle; - - cle = cl_env_container(env); - - LASSERT(cle->ce_ref > 0); - LASSERT(ergo(refcheck, cle->ce_ref == *refcheck)); - - CDEBUG(D_OTHER, "%d@%p\n", cle->ce_ref, cle); - if (--cle->ce_ref == 0) { - int cpu = get_cpu(); - - CL_ENV_DEC(busy); - cle->ce_debug = NULL; - cl_env_exit(cle); - /* - * Don't bother to take a lock here. - * - * Return environment to the cache only when it was allocated - * with the standard tags. - */ - if (cl_envs[cpu].cec_count < cl_envs_cached_max && - (env->le_ctx.lc_tags & ~LCT_HAS_EXIT) == LCT_CL_THREAD && - (env->le_ses->lc_tags & ~LCT_HAS_EXIT) == LCT_SESSION) { - read_lock(&cl_envs[cpu].cec_guard); - list_add(&cle->ce_linkage, &cl_envs[cpu].cec_envs); - cl_envs[cpu].cec_count++; - read_unlock(&cl_envs[cpu].cec_guard); - } else { - cl_env_fini(cle); - } - put_cpu(); - } -} -EXPORT_SYMBOL(cl_env_put); - -/** - * Converts struct ost_lvb to struct cl_attr. - * - * \see cl_attr2lvb - */ -void cl_lvb2attr(struct cl_attr *attr, const struct ost_lvb *lvb) -{ - attr->cat_size = lvb->lvb_size; - attr->cat_mtime = lvb->lvb_mtime; - attr->cat_atime = lvb->lvb_atime; - attr->cat_ctime = lvb->lvb_ctime; - attr->cat_blocks = lvb->lvb_blocks; -} -EXPORT_SYMBOL(cl_lvb2attr); - -static struct cl_env cl_env_percpu[NR_CPUS]; - -static int cl_env_percpu_init(void) -{ - struct cl_env *cle; - int tags = LCT_REMEMBER | LCT_NOREF; - int i, j; - int rc = 0; - - for_each_possible_cpu(i) { - struct lu_env *env; - - rwlock_init(&cl_envs[i].cec_guard); - INIT_LIST_HEAD(&cl_envs[i].cec_envs); - cl_envs[i].cec_count = 0; - - cle = &cl_env_percpu[i]; - env = &cle->ce_lu; - - INIT_LIST_HEAD(&cle->ce_linkage); - cle->ce_magic = &cl_env_init0; - rc = lu_env_init(env, LCT_CL_THREAD | tags); - if (rc == 0) { - rc = lu_context_init(&cle->ce_ses, LCT_SESSION | tags); - if (rc == 0) { - lu_context_enter(&cle->ce_ses); - env->le_ses = &cle->ce_ses; - } else { - lu_env_fini(env); - } - } - if (rc != 0) - break; - } - if (rc != 0) { - /* Indices 0 to i (excluding i) were correctly initialized, - * thus we must uninitialize up to i, the rest are undefined. - */ - for (j = 0; j < i; j++) { - cle = &cl_env_percpu[j]; - lu_context_exit(&cle->ce_ses); - lu_context_fini(&cle->ce_ses); - lu_env_fini(&cle->ce_lu); - } - } - - return rc; -} - -static void cl_env_percpu_fini(void) -{ - int i; - - for_each_possible_cpu(i) { - struct cl_env *cle = &cl_env_percpu[i]; - - lu_context_exit(&cle->ce_ses); - lu_context_fini(&cle->ce_ses); - lu_env_fini(&cle->ce_lu); - } -} - -static void cl_env_percpu_refill(void) -{ - int i; - - for_each_possible_cpu(i) - lu_env_refill(&cl_env_percpu[i].ce_lu); -} - -void cl_env_percpu_put(struct lu_env *env) -{ - struct cl_env *cle; - int cpu; - - cpu = smp_processor_id(); - cle = cl_env_container(env); - LASSERT(cle == &cl_env_percpu[cpu]); - - cle->ce_ref--; - LASSERT(cle->ce_ref == 0); - - CL_ENV_DEC(busy); - cle->ce_debug = NULL; - - put_cpu(); -} -EXPORT_SYMBOL(cl_env_percpu_put); - -struct lu_env *cl_env_percpu_get(void) -{ - struct cl_env *cle; - - cle = &cl_env_percpu[get_cpu()]; - cl_env_init0(cle, __builtin_return_address(0)); - - return &cle->ce_lu; -} -EXPORT_SYMBOL(cl_env_percpu_get); - -/***************************************************************************** - * - * Temporary prototype thing: mirror obd-devices into cl devices. - * - */ - -struct cl_device *cl_type_setup(const struct lu_env *env, struct lu_site *site, - struct lu_device_type *ldt, - struct lu_device *next) -{ - const char *typename; - struct lu_device *d; - - typename = ldt->ldt_name; - d = ldt->ldt_ops->ldto_device_alloc(env, ldt, NULL); - if (!IS_ERR(d)) { - int rc; - - if (site) - d->ld_site = site; - rc = ldt->ldt_ops->ldto_device_init(env, d, typename, next); - if (rc == 0) { - lu_device_get(d); - lu_ref_add(&d->ld_reference, - "lu-stack", &lu_site_init); - } else { - ldt->ldt_ops->ldto_device_free(env, d); - CERROR("can't init device '%s', %d\n", typename, rc); - d = ERR_PTR(rc); - } - } else { - CERROR("Cannot allocate device: '%s'\n", typename); - } - return lu2cl_dev(d); -} -EXPORT_SYMBOL(cl_type_setup); - -/** - * Finalize device stack by calling lu_stack_fini(). - */ -void cl_stack_fini(const struct lu_env *env, struct cl_device *cl) -{ - lu_stack_fini(env, cl2lu_dev(cl)); -} -EXPORT_SYMBOL(cl_stack_fini); - -static struct lu_context_key cl_key; - -struct cl_thread_info *cl_env_info(const struct lu_env *env) -{ - return lu_context_key_get(&env->le_ctx, &cl_key); -} - -/* defines cl0_key_{init,fini}() */ -LU_KEY_INIT_FINI(cl0, struct cl_thread_info); - -static void *cl_key_init(const struct lu_context *ctx, - struct lu_context_key *key) -{ - return cl0_key_init(ctx, key); -} - -static void cl_key_fini(const struct lu_context *ctx, - struct lu_context_key *key, void *data) -{ - cl0_key_fini(ctx, key, data); -} - -static struct lu_context_key cl_key = { - .lct_tags = LCT_CL_THREAD, - .lct_init = cl_key_init, - .lct_fini = cl_key_fini, -}; - -static struct lu_kmem_descr cl_object_caches[] = { - { - .ckd_cache = &cl_env_kmem, - .ckd_name = "cl_env_kmem", - .ckd_size = sizeof(struct cl_env) - }, - { - .ckd_cache = NULL - } -}; - -/** - * Global initialization of cl-data. Create kmem caches, register - * lu_context_key's, etc. - * - * \see cl_global_fini() - */ -int cl_global_init(void) -{ - int result; - - cl_envs = kcalloc(num_possible_cpus(), sizeof(*cl_envs), GFP_KERNEL); - if (!cl_envs) { - result = -ENOMEM; - goto out; - } - - result = lu_kmem_init(cl_object_caches); - if (result) - goto out_envs; - - LU_CONTEXT_KEY_INIT(&cl_key); - result = lu_context_key_register(&cl_key); - if (result) - goto out_kmem; - - result = cl_env_percpu_init(); - if (result) - /* no cl_env_percpu_fini on error */ - goto out_keys; - - return 0; - -out_keys: - lu_context_key_degister(&cl_key); -out_kmem: - lu_kmem_fini(cl_object_caches); -out_envs: - kfree(cl_envs); -out: - return result; -} - -/** - * Finalization of global cl-data. Dual to cl_global_init(). - */ -void cl_global_fini(void) -{ - cl_env_percpu_fini(); - lu_context_key_degister(&cl_key); - lu_kmem_fini(cl_object_caches); - kfree(cl_envs); -} diff --git a/drivers/staging/lustre/lustre/obdclass/cl_page.c b/drivers/staging/lustre/lustre/obdclass/cl_page.c deleted file mode 100644 index d3b25667bc3a..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/cl_page.c +++ /dev/null @@ -1,1046 +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) 2008, 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. - * - * Client Lustre Page. - * - * Author: Nikita Danilov <nikita.danilov@sun.com> - * Author: Jinshan Xiong <jinshan.xiong@intel.com> - */ - -#define DEBUG_SUBSYSTEM S_CLASS - -#include <linux/libcfs/libcfs.h> -#include <obd_class.h> -#include <obd_support.h> -#include <linux/list.h> - -#include <cl_object.h> -#include "cl_internal.h" - -static void cl_page_delete0(const struct lu_env *env, struct cl_page *pg); - -# define PASSERT(env, page, expr) \ - do { \ - if (unlikely(!(expr))) { \ - CL_PAGE_DEBUG(D_ERROR, (env), (page), #expr "\n"); \ - LASSERT(0); \ - } \ - } while (0) - -# define PINVRNT(env, page, exp) \ - ((void)sizeof(env), (void)sizeof(page), (void)sizeof !!(exp)) - -/** - * Internal version of cl_page_get(). - * - * This function can be used to obtain initial reference to previously - * unreferenced cached object. It can be called only if concurrent page - * reclamation is somehow prevented, e.g., by keeping a lock on a VM page, - * associated with \a page. - * - * Use with care! Not exported. - */ -static void cl_page_get_trust(struct cl_page *page) -{ - LASSERT(atomic_read(&page->cp_ref) > 0); - atomic_inc(&page->cp_ref); -} - -/** - * Returns a slice within a page, corresponding to the given layer in the - * device stack. - * - * \see cl_lock_at() - */ -static const struct cl_page_slice * -cl_page_at_trusted(const struct cl_page *page, - const struct lu_device_type *dtype) -{ - const struct cl_page_slice *slice; - - list_for_each_entry(slice, &page->cp_layers, cpl_linkage) { - if (slice->cpl_obj->co_lu.lo_dev->ld_type == dtype) - return slice; - } - return NULL; -} - -static void cl_page_free(const struct lu_env *env, struct cl_page *page) -{ - struct cl_object *obj = page->cp_obj; - - PASSERT(env, page, list_empty(&page->cp_batch)); - PASSERT(env, page, !page->cp_owner); - PASSERT(env, page, page->cp_state == CPS_FREEING); - - while (!list_empty(&page->cp_layers)) { - struct cl_page_slice *slice; - - slice = list_entry(page->cp_layers.next, - struct cl_page_slice, cpl_linkage); - list_del_init(page->cp_layers.next); - if (unlikely(slice->cpl_ops->cpo_fini)) - slice->cpl_ops->cpo_fini(env, slice); - } - lu_object_ref_del_at(&obj->co_lu, &page->cp_obj_ref, "cl_page", page); - cl_object_put(env, obj); - lu_ref_fini(&page->cp_reference); - kfree(page); -} - -/** - * Helper function updating page state. This is the only place in the code - * where cl_page::cp_state field is mutated. - */ -static inline void cl_page_state_set_trust(struct cl_page *page, - enum cl_page_state state) -{ - /* bypass const. */ - *(enum cl_page_state *)&page->cp_state = state; -} - -struct cl_page *cl_page_alloc(const struct lu_env *env, - struct cl_object *o, pgoff_t ind, - struct page *vmpage, - enum cl_page_type type) -{ - struct cl_page *page; - struct lu_object_header *head; - - page = kzalloc(cl_object_header(o)->coh_page_bufsize, GFP_NOFS); - if (page) { - int result = 0; - - atomic_set(&page->cp_ref, 1); - page->cp_obj = o; - cl_object_get(o); - lu_object_ref_add_at(&o->co_lu, &page->cp_obj_ref, "cl_page", - page); - page->cp_vmpage = vmpage; - cl_page_state_set_trust(page, CPS_CACHED); - page->cp_type = type; - INIT_LIST_HEAD(&page->cp_layers); - INIT_LIST_HEAD(&page->cp_batch); - lu_ref_init(&page->cp_reference); - head = o->co_lu.lo_header; - list_for_each_entry(o, &head->loh_layers, co_lu.lo_linkage) { - if (o->co_ops->coo_page_init) { - result = o->co_ops->coo_page_init(env, o, page, - ind); - if (result != 0) { - cl_page_delete0(env, page); - cl_page_free(env, page); - page = ERR_PTR(result); - break; - } - } - } - } else { - page = ERR_PTR(-ENOMEM); - } - return page; -} - -/** - * Returns a cl_page with index \a idx at the object \a o, and associated with - * the VM page \a vmpage. - * - * This is the main entry point into the cl_page caching interface. First, a - * cache (implemented as a per-object radix tree) is consulted. If page is - * found there, it is returned immediately. Otherwise new page is allocated - * and returned. In any case, additional reference to page is acquired. - * - * \see cl_object_find(), cl_lock_find() - */ -struct cl_page *cl_page_find(const struct lu_env *env, - struct cl_object *o, - pgoff_t idx, struct page *vmpage, - enum cl_page_type type) -{ - struct cl_page *page = NULL; - struct cl_object_header *hdr; - - LASSERT(type == CPT_CACHEABLE || type == CPT_TRANSIENT); - might_sleep(); - - hdr = cl_object_header(o); - - CDEBUG(D_PAGE, "%lu@" DFID " %p %lx %d\n", - idx, PFID(&hdr->coh_lu.loh_fid), vmpage, vmpage->private, type); - /* fast path. */ - if (type == CPT_CACHEABLE) { - /* - * vmpage lock is used to protect the child/parent - * relationship - */ - LASSERT(PageLocked(vmpage)); - /* - * cl_vmpage_page() can be called here without any locks as - * - * - "vmpage" is locked (which prevents ->private from - * concurrent updates), and - * - * - "o" cannot be destroyed while current thread holds a - * reference on it. - */ - page = cl_vmpage_page(vmpage, o); - - if (page) - return page; - } - - /* allocate and initialize cl_page */ - page = cl_page_alloc(env, o, idx, vmpage, type); - return page; -} -EXPORT_SYMBOL(cl_page_find); - -static inline int cl_page_invariant(const struct cl_page *pg) -{ - return cl_page_in_use_noref(pg); -} - -static void cl_page_state_set0(const struct lu_env *env, - struct cl_page *page, enum cl_page_state state) -{ - enum cl_page_state old; - - /* - * Matrix of allowed state transitions [old][new], for sanity - * checking. - */ - static const int allowed_transitions[CPS_NR][CPS_NR] = { - [CPS_CACHED] = { - [CPS_CACHED] = 0, - [CPS_OWNED] = 1, /* io finds existing cached page */ - [CPS_PAGEIN] = 0, - [CPS_PAGEOUT] = 1, /* write-out from the cache */ - [CPS_FREEING] = 1, /* eviction on the memory pressure */ - }, - [CPS_OWNED] = { - [CPS_CACHED] = 1, /* release to the cache */ - [CPS_OWNED] = 0, - [CPS_PAGEIN] = 1, /* start read immediately */ - [CPS_PAGEOUT] = 1, /* start write immediately */ - [CPS_FREEING] = 1, /* lock invalidation or truncate */ - }, - [CPS_PAGEIN] = { - [CPS_CACHED] = 1, /* io completion */ - [CPS_OWNED] = 0, - [CPS_PAGEIN] = 0, - [CPS_PAGEOUT] = 0, - [CPS_FREEING] = 0, - }, - [CPS_PAGEOUT] = { - [CPS_CACHED] = 1, /* io completion */ - [CPS_OWNED] = 0, - [CPS_PAGEIN] = 0, - [CPS_PAGEOUT] = 0, - [CPS_FREEING] = 0, - }, - [CPS_FREEING] = { - [CPS_CACHED] = 0, - [CPS_OWNED] = 0, - [CPS_PAGEIN] = 0, - [CPS_PAGEOUT] = 0, - [CPS_FREEING] = 0, - } - }; - - old = page->cp_state; - PASSERT(env, page, allowed_transitions[old][state]); - CL_PAGE_HEADER(D_TRACE, env, page, "%d -> %d\n", old, state); - PASSERT(env, page, page->cp_state == old); - PASSERT(env, page, equi(state == CPS_OWNED, page->cp_owner)); - cl_page_state_set_trust(page, state); -} - -static void cl_page_state_set(const struct lu_env *env, - struct cl_page *page, enum cl_page_state state) -{ - cl_page_state_set0(env, page, state); -} - -/** - * Acquires an additional reference to a page. - * - * This can be called only by caller already possessing a reference to \a - * page. - * - * \see cl_object_get(), cl_lock_get(). - */ -void cl_page_get(struct cl_page *page) -{ - cl_page_get_trust(page); -} -EXPORT_SYMBOL(cl_page_get); - -/** - * Releases a reference to a page. - * - * When last reference is released, page is returned to the cache, unless it - * is in cl_page_state::CPS_FREEING state, in which case it is immediately - * destroyed. - * - * \see cl_object_put(), cl_lock_put(). - */ -void cl_page_put(const struct lu_env *env, struct cl_page *page) -{ - CL_PAGE_HEADER(D_TRACE, env, page, "%d\n", - atomic_read(&page->cp_ref)); - - if (atomic_dec_and_test(&page->cp_ref)) { - LASSERT(page->cp_state == CPS_FREEING); - - LASSERT(atomic_read(&page->cp_ref) == 0); - PASSERT(env, page, !page->cp_owner); - PASSERT(env, page, list_empty(&page->cp_batch)); - /* - * Page is no longer reachable by other threads. Tear - * it down. - */ - cl_page_free(env, page); - } -} -EXPORT_SYMBOL(cl_page_put); - -/** - * Returns a cl_page associated with a VM page, and given cl_object. - */ -struct cl_page *cl_vmpage_page(struct page *vmpage, struct cl_object *obj) -{ - struct cl_page *page; - - LASSERT(PageLocked(vmpage)); - - /* - * NOTE: absence of races and liveness of data are guaranteed by page - * lock on a "vmpage". That works because object destruction has - * bottom-to-top pass. - */ - - page = (struct cl_page *)vmpage->private; - if (page) { - cl_page_get_trust(page); - LASSERT(page->cp_type == CPT_CACHEABLE); - } - return page; -} -EXPORT_SYMBOL(cl_vmpage_page); - -const struct cl_page_slice *cl_page_at(const struct cl_page *page, - const struct lu_device_type *dtype) -{ - return cl_page_at_trusted(page, dtype); -} -EXPORT_SYMBOL(cl_page_at); - -#define CL_PAGE_OP(opname) offsetof(struct cl_page_operations, opname) - -#define CL_PAGE_INVOKE(_env, _page, _op, _proto, ...) \ -({ \ - const struct lu_env *__env = (_env); \ - struct cl_page *__page = (_page); \ - const struct cl_page_slice *__scan; \ - int __result; \ - ptrdiff_t __op = (_op); \ - int (*__method)_proto; \ - \ - __result = 0; \ - list_for_each_entry(__scan, &__page->cp_layers, cpl_linkage) { \ - __method = *(void **)((char *)__scan->cpl_ops + __op); \ - if (__method) { \ - __result = (*__method)(__env, __scan, ## __VA_ARGS__); \ - if (__result != 0) \ - break; \ - } \ - } \ - if (__result > 0) \ - __result = 0; \ - __result; \ -}) - -#define CL_PAGE_INVOID(_env, _page, _op, _proto, ...) \ -do { \ - const struct lu_env *__env = (_env); \ - struct cl_page *__page = (_page); \ - const struct cl_page_slice *__scan; \ - ptrdiff_t __op = (_op); \ - void (*__method)_proto; \ - \ - list_for_each_entry(__scan, &__page->cp_layers, cpl_linkage) { \ - __method = *(void **)((char *)__scan->cpl_ops + __op); \ - if (__method) \ - (*__method)(__env, __scan, ## __VA_ARGS__); \ - } \ -} while (0) - -#define CL_PAGE_INVOID_REVERSE(_env, _page, _op, _proto, ...) \ -do { \ - const struct lu_env *__env = (_env); \ - struct cl_page *__page = (_page); \ - const struct cl_page_slice *__scan; \ - ptrdiff_t __op = (_op); \ - void (*__method)_proto; \ - \ - list_for_each_entry_reverse(__scan, &__page->cp_layers, cpl_linkage) { \ - __method = *(void **)((char *)__scan->cpl_ops + __op); \ - if (__method) \ - (*__method)(__env, __scan, ## __VA_ARGS__); \ - } \ -} while (0) - -static int cl_page_invoke(const struct lu_env *env, - struct cl_io *io, struct cl_page *page, ptrdiff_t op) - -{ - PINVRNT(env, page, cl_object_same(page->cp_obj, io->ci_obj)); - return CL_PAGE_INVOKE(env, page, op, - (const struct lu_env *, - const struct cl_page_slice *, struct cl_io *), - io); -} - -static void cl_page_invoid(const struct lu_env *env, - struct cl_io *io, struct cl_page *page, ptrdiff_t op) - -{ - PINVRNT(env, page, cl_object_same(page->cp_obj, io->ci_obj)); - CL_PAGE_INVOID(env, page, op, - (const struct lu_env *, - const struct cl_page_slice *, struct cl_io *), io); -} - -static void cl_page_owner_clear(struct cl_page *page) -{ - if (page->cp_owner) { - LASSERT(page->cp_owner->ci_owned_nr > 0); - page->cp_owner->ci_owned_nr--; - page->cp_owner = NULL; - } -} - -static void cl_page_owner_set(struct cl_page *page) -{ - page->cp_owner->ci_owned_nr++; -} - -void cl_page_disown0(const struct lu_env *env, - struct cl_io *io, struct cl_page *pg) -{ - enum cl_page_state state; - - state = pg->cp_state; - PINVRNT(env, pg, state == CPS_OWNED || state == CPS_FREEING); - PINVRNT(env, pg, cl_page_invariant(pg) || state == CPS_FREEING); - cl_page_owner_clear(pg); - - if (state == CPS_OWNED) - cl_page_state_set(env, pg, CPS_CACHED); - /* - * Completion call-backs are executed in the bottom-up order, so that - * uppermost layer (llite), responsible for VFS/VM interaction runs - * last and can release locks safely. - */ - CL_PAGE_INVOID_REVERSE(env, pg, CL_PAGE_OP(cpo_disown), - (const struct lu_env *, - const struct cl_page_slice *, struct cl_io *), - io); -} - -/** - * returns true, iff page is owned by the given io. - */ -int cl_page_is_owned(const struct cl_page *pg, const struct cl_io *io) -{ - struct cl_io *top = cl_io_top((struct cl_io *)io); - - LINVRNT(cl_object_same(pg->cp_obj, io->ci_obj)); - return pg->cp_state == CPS_OWNED && pg->cp_owner == top; -} -EXPORT_SYMBOL(cl_page_is_owned); - -/** - * Try to own a page by IO. - * - * Waits until page is in cl_page_state::CPS_CACHED state, and then switch it - * into cl_page_state::CPS_OWNED state. - * - * \pre !cl_page_is_owned(pg, io) - * \post result == 0 iff cl_page_is_owned(pg, io) - * - * \retval 0 success - * - * \retval -ve failure, e.g., page was destroyed (and landed in - * cl_page_state::CPS_FREEING instead of cl_page_state::CPS_CACHED). - * or, page was owned by another thread, or in IO. - * - * \see cl_page_disown() - * \see cl_page_operations::cpo_own() - * \see cl_page_own_try() - * \see cl_page_own - */ -static int cl_page_own0(const struct lu_env *env, struct cl_io *io, - struct cl_page *pg, int nonblock) -{ - int result; - - PINVRNT(env, pg, !cl_page_is_owned(pg, io)); - - io = cl_io_top(io); - - if (pg->cp_state == CPS_FREEING) { - result = -ENOENT; - } else { - result = CL_PAGE_INVOKE(env, pg, CL_PAGE_OP(cpo_own), - (const struct lu_env *, - const struct cl_page_slice *, - struct cl_io *, int), - io, nonblock); - if (result == 0) { - PASSERT(env, pg, !pg->cp_owner); - pg->cp_owner = cl_io_top(io); - cl_page_owner_set(pg); - if (pg->cp_state != CPS_FREEING) { - cl_page_state_set(env, pg, CPS_OWNED); - } else { - cl_page_disown0(env, io, pg); - result = -ENOENT; - } - } - } - PINVRNT(env, pg, ergo(result == 0, cl_page_invariant(pg))); - return result; -} - -/** - * Own a page, might be blocked. - * - * \see cl_page_own0() - */ -int cl_page_own(const struct lu_env *env, struct cl_io *io, struct cl_page *pg) -{ - return cl_page_own0(env, io, pg, 0); -} -EXPORT_SYMBOL(cl_page_own); - -/** - * Nonblock version of cl_page_own(). - * - * \see cl_page_own0() - */ -int cl_page_own_try(const struct lu_env *env, struct cl_io *io, - struct cl_page *pg) -{ - return cl_page_own0(env, io, pg, 1); -} -EXPORT_SYMBOL(cl_page_own_try); - -/** - * Assume page ownership. - * - * Called when page is already locked by the hosting VM. - * - * \pre !cl_page_is_owned(pg, io) - * \post cl_page_is_owned(pg, io) - * - * \see cl_page_operations::cpo_assume() - */ -void cl_page_assume(const struct lu_env *env, - struct cl_io *io, struct cl_page *pg) -{ - PINVRNT(env, pg, cl_object_same(pg->cp_obj, io->ci_obj)); - - io = cl_io_top(io); - - cl_page_invoid(env, io, pg, CL_PAGE_OP(cpo_assume)); - PASSERT(env, pg, !pg->cp_owner); - pg->cp_owner = cl_io_top(io); - cl_page_owner_set(pg); - cl_page_state_set(env, pg, CPS_OWNED); -} -EXPORT_SYMBOL(cl_page_assume); - -/** - * Releases page ownership without unlocking the page. - * - * Moves page into cl_page_state::CPS_CACHED without releasing a lock on the - * underlying VM page (as VM is supposed to do this itself). - * - * \pre cl_page_is_owned(pg, io) - * \post !cl_page_is_owned(pg, io) - * - * \see cl_page_assume() - */ -void cl_page_unassume(const struct lu_env *env, - struct cl_io *io, struct cl_page *pg) -{ - PINVRNT(env, pg, cl_page_is_owned(pg, io)); - PINVRNT(env, pg, cl_page_invariant(pg)); - - io = cl_io_top(io); - cl_page_owner_clear(pg); - cl_page_state_set(env, pg, CPS_CACHED); - CL_PAGE_INVOID_REVERSE(env, pg, CL_PAGE_OP(cpo_unassume), - (const struct lu_env *, - const struct cl_page_slice *, struct cl_io *), - io); -} -EXPORT_SYMBOL(cl_page_unassume); - -/** - * Releases page ownership. - * - * Moves page into cl_page_state::CPS_CACHED. - * - * \pre cl_page_is_owned(pg, io) - * \post !cl_page_is_owned(pg, io) - * - * \see cl_page_own() - * \see cl_page_operations::cpo_disown() - */ -void cl_page_disown(const struct lu_env *env, - struct cl_io *io, struct cl_page *pg) -{ - PINVRNT(env, pg, cl_page_is_owned(pg, io) || - pg->cp_state == CPS_FREEING); - - io = cl_io_top(io); - cl_page_disown0(env, io, pg); -} -EXPORT_SYMBOL(cl_page_disown); - -/** - * Called when page is to be removed from the object, e.g., as a result of - * truncate. - * - * Calls cl_page_operations::cpo_discard() top-to-bottom. - * - * \pre cl_page_is_owned(pg, io) - * - * \see cl_page_operations::cpo_discard() - */ -void cl_page_discard(const struct lu_env *env, - struct cl_io *io, struct cl_page *pg) -{ - PINVRNT(env, pg, cl_page_is_owned(pg, io)); - PINVRNT(env, pg, cl_page_invariant(pg)); - - cl_page_invoid(env, io, pg, CL_PAGE_OP(cpo_discard)); -} -EXPORT_SYMBOL(cl_page_discard); - -/** - * Version of cl_page_delete() that can be called for not fully constructed - * pages, e.g,. in a error handling cl_page_find()->cl_page_delete0() - * path. Doesn't check page invariant. - */ -static void cl_page_delete0(const struct lu_env *env, struct cl_page *pg) -{ - PASSERT(env, pg, pg->cp_state != CPS_FREEING); - - /* - * Sever all ways to obtain new pointers to @pg. - */ - cl_page_owner_clear(pg); - - cl_page_state_set0(env, pg, CPS_FREEING); - - CL_PAGE_INVOID_REVERSE(env, pg, CL_PAGE_OP(cpo_delete), - (const struct lu_env *, - const struct cl_page_slice *)); -} - -/** - * Called when a decision is made to throw page out of memory. - * - * Notifies all layers about page destruction by calling - * cl_page_operations::cpo_delete() method top-to-bottom. - * - * Moves page into cl_page_state::CPS_FREEING state (this is the only place - * where transition to this state happens). - * - * Eliminates all venues through which new references to the page can be - * obtained: - * - * - removes page from the radix trees, - * - * - breaks linkage from VM page to cl_page. - * - * Once page reaches cl_page_state::CPS_FREEING, all remaining references will - * drain after some time, at which point page will be recycled. - * - * \pre VM page is locked - * \post pg->cp_state == CPS_FREEING - * - * \see cl_page_operations::cpo_delete() - */ -void cl_page_delete(const struct lu_env *env, struct cl_page *pg) -{ - PINVRNT(env, pg, cl_page_invariant(pg)); - cl_page_delete0(env, pg); -} -EXPORT_SYMBOL(cl_page_delete); - -/** - * Marks page up-to-date. - * - * Call cl_page_operations::cpo_export() through all layers top-to-bottom. The - * layer responsible for VM interaction has to mark/clear page as up-to-date - * by the \a uptodate argument. - * - * \see cl_page_operations::cpo_export() - */ -void cl_page_export(const struct lu_env *env, struct cl_page *pg, int uptodate) -{ - PINVRNT(env, pg, cl_page_invariant(pg)); - CL_PAGE_INVOID(env, pg, CL_PAGE_OP(cpo_export), - (const struct lu_env *, - const struct cl_page_slice *, int), uptodate); -} -EXPORT_SYMBOL(cl_page_export); - -/** - * Returns true, iff \a pg is VM locked in a suitable sense by the calling - * thread. - */ -int cl_page_is_vmlocked(const struct lu_env *env, const struct cl_page *pg) -{ - int result; - const struct cl_page_slice *slice; - - slice = container_of(pg->cp_layers.next, - const struct cl_page_slice, cpl_linkage); - PASSERT(env, pg, slice->cpl_ops->cpo_is_vmlocked); - /* - * Call ->cpo_is_vmlocked() directly instead of going through - * CL_PAGE_INVOKE(), because cl_page_is_vmlocked() is used by - * cl_page_invariant(). - */ - result = slice->cpl_ops->cpo_is_vmlocked(env, slice); - PASSERT(env, pg, result == -EBUSY || result == -ENODATA); - return result == -EBUSY; -} -EXPORT_SYMBOL(cl_page_is_vmlocked); - -static enum cl_page_state cl_req_type_state(enum cl_req_type crt) -{ - return crt == CRT_WRITE ? CPS_PAGEOUT : CPS_PAGEIN; -} - -static void cl_page_io_start(const struct lu_env *env, - struct cl_page *pg, enum cl_req_type crt) -{ - /* - * Page is queued for IO, change its state. - */ - cl_page_owner_clear(pg); - cl_page_state_set(env, pg, cl_req_type_state(crt)); -} - -/** - * Prepares page for immediate transfer. cl_page_operations::cpo_prep() is - * called top-to-bottom. Every layer either agrees to submit this page (by - * returning 0), or requests to omit this page (by returning -EALREADY). Layer - * handling interactions with the VM also has to inform VM that page is under - * transfer now. - */ -int cl_page_prep(const struct lu_env *env, struct cl_io *io, - struct cl_page *pg, enum cl_req_type crt) -{ - int result; - - PINVRNT(env, pg, cl_page_is_owned(pg, io)); - PINVRNT(env, pg, cl_page_invariant(pg)); - PINVRNT(env, pg, crt < CRT_NR); - - /* - * XXX this has to be called bottom-to-top, so that llite can set up - * PG_writeback without risking other layers deciding to skip this - * page. - */ - if (crt >= CRT_NR) - return -EINVAL; - result = cl_page_invoke(env, io, pg, CL_PAGE_OP(io[crt].cpo_prep)); - if (result == 0) - cl_page_io_start(env, pg, crt); - - CL_PAGE_HEADER(D_TRACE, env, pg, "%d %d\n", crt, result); - return result; -} -EXPORT_SYMBOL(cl_page_prep); - -/** - * Notify layers about transfer completion. - * - * Invoked by transfer sub-system (which is a part of osc) to notify layers - * that a transfer, of which this page is a part of has completed. - * - * Completion call-backs are executed in the bottom-up order, so that - * uppermost layer (llite), responsible for the VFS/VM interaction runs last - * and can release locks safely. - * - * \pre pg->cp_state == CPS_PAGEIN || pg->cp_state == CPS_PAGEOUT - * \post pg->cp_state == CPS_CACHED - * - * \see cl_page_operations::cpo_completion() - */ -void cl_page_completion(const struct lu_env *env, - struct cl_page *pg, enum cl_req_type crt, int ioret) -{ - struct cl_sync_io *anchor = pg->cp_sync_io; - - PASSERT(env, pg, crt < CRT_NR); - PASSERT(env, pg, pg->cp_state == cl_req_type_state(crt)); - - CL_PAGE_HEADER(D_TRACE, env, pg, "%d %d\n", crt, ioret); - - cl_page_state_set(env, pg, CPS_CACHED); - if (crt >= CRT_NR) - return; - CL_PAGE_INVOID_REVERSE(env, pg, CL_PAGE_OP(io[crt].cpo_completion), - (const struct lu_env *, - const struct cl_page_slice *, int), ioret); - if (anchor) { - LASSERT(pg->cp_sync_io == anchor); - pg->cp_sync_io = NULL; - cl_sync_io_note(env, anchor, ioret); - } -} -EXPORT_SYMBOL(cl_page_completion); - -/** - * Notify layers that transfer formation engine decided to yank this page from - * the cache and to make it a part of a transfer. - * - * \pre pg->cp_state == CPS_CACHED - * \post pg->cp_state == CPS_PAGEIN || pg->cp_state == CPS_PAGEOUT - * - * \see cl_page_operations::cpo_make_ready() - */ -int cl_page_make_ready(const struct lu_env *env, struct cl_page *pg, - enum cl_req_type crt) -{ - int result; - - PINVRNT(env, pg, crt < CRT_NR); - - if (crt >= CRT_NR) - return -EINVAL; - result = CL_PAGE_INVOKE(env, pg, CL_PAGE_OP(io[crt].cpo_make_ready), - (const struct lu_env *, - const struct cl_page_slice *)); - if (result == 0) { - PASSERT(env, pg, pg->cp_state == CPS_CACHED); - cl_page_io_start(env, pg, crt); - } - CL_PAGE_HEADER(D_TRACE, env, pg, "%d %d\n", crt, result); - return result; -} -EXPORT_SYMBOL(cl_page_make_ready); - -/** - * Called if a pge is being written back by kernel's intention. - * - * \pre cl_page_is_owned(pg, io) - * \post ergo(result == 0, pg->cp_state == CPS_PAGEOUT) - * - * \see cl_page_operations::cpo_flush() - */ -int cl_page_flush(const struct lu_env *env, struct cl_io *io, - struct cl_page *pg) -{ - int result; - - PINVRNT(env, pg, cl_page_is_owned(pg, io)); - PINVRNT(env, pg, cl_page_invariant(pg)); - - result = cl_page_invoke(env, io, pg, CL_PAGE_OP(cpo_flush)); - - CL_PAGE_HEADER(D_TRACE, env, pg, "%d\n", result); - return result; -} -EXPORT_SYMBOL(cl_page_flush); - -/** - * Tells transfer engine that only part of a page is to be transmitted. - * - * \see cl_page_operations::cpo_clip() - */ -void cl_page_clip(const struct lu_env *env, struct cl_page *pg, - int from, int to) -{ - PINVRNT(env, pg, cl_page_invariant(pg)); - - CL_PAGE_HEADER(D_TRACE, env, pg, "%d %d\n", from, to); - CL_PAGE_INVOID(env, pg, CL_PAGE_OP(cpo_clip), - (const struct lu_env *, - const struct cl_page_slice *, int, int), - from, to); -} -EXPORT_SYMBOL(cl_page_clip); - -/** - * Prints human readable representation of \a pg to the \a f. - */ -void cl_page_header_print(const struct lu_env *env, void *cookie, - lu_printer_t printer, const struct cl_page *pg) -{ - (*printer)(env, cookie, - "page@%p[%d %p %d %d %p]\n", - pg, atomic_read(&pg->cp_ref), pg->cp_obj, - pg->cp_state, pg->cp_type, - pg->cp_owner); -} -EXPORT_SYMBOL(cl_page_header_print); - -/** - * Prints human readable representation of \a pg to the \a f. - */ -void cl_page_print(const struct lu_env *env, void *cookie, - lu_printer_t printer, const struct cl_page *pg) -{ - cl_page_header_print(env, cookie, printer, pg); - CL_PAGE_INVOKE(env, (struct cl_page *)pg, CL_PAGE_OP(cpo_print), - (const struct lu_env *env, - const struct cl_page_slice *slice, - void *cookie, lu_printer_t p), cookie, printer); - (*printer)(env, cookie, "end page@%p\n", pg); -} -EXPORT_SYMBOL(cl_page_print); - -/** - * Cancel a page which is still in a transfer. - */ -int cl_page_cancel(const struct lu_env *env, struct cl_page *page) -{ - return CL_PAGE_INVOKE(env, page, CL_PAGE_OP(cpo_cancel), - (const struct lu_env *, - const struct cl_page_slice *)); -} - -/** - * Converts a byte offset within object \a obj into a page index. - */ -loff_t cl_offset(const struct cl_object *obj, pgoff_t idx) -{ - /* - * XXX for now. - */ - return (loff_t)idx << PAGE_SHIFT; -} -EXPORT_SYMBOL(cl_offset); - -/** - * Converts a page index into a byte offset within object \a obj. - */ -pgoff_t cl_index(const struct cl_object *obj, loff_t offset) -{ - /* - * XXX for now. - */ - return offset >> PAGE_SHIFT; -} -EXPORT_SYMBOL(cl_index); - -size_t cl_page_size(const struct cl_object *obj) -{ - return 1UL << PAGE_SHIFT; -} -EXPORT_SYMBOL(cl_page_size); - -/** - * Adds page slice to the compound page. - * - * This is called by cl_object_operations::coo_page_init() methods to add a - * per-layer state to the page. New state is added at the end of - * cl_page::cp_layers list, that is, it is at the bottom of the stack. - * - * \see cl_lock_slice_add(), cl_req_slice_add(), cl_io_slice_add() - */ -void cl_page_slice_add(struct cl_page *page, struct cl_page_slice *slice, - struct cl_object *obj, pgoff_t index, - const struct cl_page_operations *ops) -{ - list_add_tail(&slice->cpl_linkage, &page->cp_layers); - slice->cpl_obj = obj; - slice->cpl_index = index; - slice->cpl_ops = ops; - slice->cpl_page = page; -} -EXPORT_SYMBOL(cl_page_slice_add); - -/** - * Allocate and initialize cl_cache, called by ll_init_sbi(). - */ -struct cl_client_cache *cl_cache_init(unsigned long lru_page_max) -{ - struct cl_client_cache *cache = NULL; - - cache = kzalloc(sizeof(*cache), GFP_KERNEL); - if (!cache) - return NULL; - - /* Initialize cache data */ - atomic_set(&cache->ccc_users, 1); - cache->ccc_lru_max = lru_page_max; - atomic_long_set(&cache->ccc_lru_left, lru_page_max); - spin_lock_init(&cache->ccc_lru_lock); - INIT_LIST_HEAD(&cache->ccc_lru); - - atomic_long_set(&cache->ccc_unstable_nr, 0); - init_waitqueue_head(&cache->ccc_unstable_waitq); - - return cache; -} -EXPORT_SYMBOL(cl_cache_init); - -/** - * Increase cl_cache refcount - */ -void cl_cache_incref(struct cl_client_cache *cache) -{ - atomic_inc(&cache->ccc_users); -} -EXPORT_SYMBOL(cl_cache_incref); - -/** - * Decrease cl_cache refcount and free the cache if refcount=0. - * Since llite, lov and osc all hold cl_cache refcount, - * the free will not cause race. (LU-6173) - */ -void cl_cache_decref(struct cl_client_cache *cache) -{ - if (atomic_dec_and_test(&cache->ccc_users)) - kfree(cache); -} -EXPORT_SYMBOL(cl_cache_decref); diff --git a/drivers/staging/lustre/lustre/obdclass/class_obd.c b/drivers/staging/lustre/lustre/obdclass/class_obd.c deleted file mode 100644 index 3e24b76f6301..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/class_obd.c +++ /dev/null @@ -1,535 +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) 1999, 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 <linux/atomic.h> - -#include <obd_support.h> -#include <obd_class.h> -#include <uapi/linux/lnet/lnetctl.h> -#include <lustre_debug.h> -#include <lprocfs_status.h> -#include <linux/list.h> -#include <cl_object.h> -#include <uapi/linux/lustre/lustre_ioctl.h> -#include "llog_internal.h" - -struct obd_device *obd_devs[MAX_OBD_DEVICES]; -struct list_head obd_types; -DEFINE_RWLOCK(obd_dev_lock); - -/* The following are visible and mutable through /sys/fs/lustre. */ -unsigned int obd_debug_peer_on_timeout; -EXPORT_SYMBOL(obd_debug_peer_on_timeout); -unsigned int obd_dump_on_timeout; -EXPORT_SYMBOL(obd_dump_on_timeout); -unsigned int obd_dump_on_eviction; -EXPORT_SYMBOL(obd_dump_on_eviction); -unsigned long obd_max_dirty_pages; -EXPORT_SYMBOL(obd_max_dirty_pages); -atomic_long_t obd_dirty_pages; -EXPORT_SYMBOL(obd_dirty_pages); -unsigned int obd_timeout = OBD_TIMEOUT_DEFAULT; /* seconds */ -EXPORT_SYMBOL(obd_timeout); -unsigned int obd_timeout_set; -EXPORT_SYMBOL(obd_timeout_set); -/* Adaptive timeout defs here instead of ptlrpc module for /sys/fs/ access */ -unsigned int at_min; -EXPORT_SYMBOL(at_min); -unsigned int at_max = 600; -EXPORT_SYMBOL(at_max); -unsigned int at_history = 600; -EXPORT_SYMBOL(at_history); -int at_early_margin = 5; -EXPORT_SYMBOL(at_early_margin); -int at_extra = 30; -EXPORT_SYMBOL(at_extra); - -atomic_long_t obd_dirty_transit_pages; -EXPORT_SYMBOL(obd_dirty_transit_pages); - -char obd_jobid_var[JOBSTATS_JOBID_VAR_MAX_LEN + 1] = JOBSTATS_DISABLE; -char obd_jobid_node[LUSTRE_JOBID_SIZE + 1]; - -/* Get jobid of current process from stored variable or calculate - * it from pid and user_id. - * - * Historically this was also done by reading the environment variable - * stored in between the "env_start" & "env_end" of task struct. - * This is now deprecated. - */ -int lustre_get_jobid(char *jobid) -{ - memset(jobid, 0, LUSTRE_JOBID_SIZE); - /* Jobstats isn't enabled */ - if (strcmp(obd_jobid_var, JOBSTATS_DISABLE) == 0) - return 0; - - /* Use process name + fsuid as jobid */ - if (strcmp(obd_jobid_var, JOBSTATS_PROCNAME_UID) == 0) { - snprintf(jobid, LUSTRE_JOBID_SIZE, "%s.%u", - current_comm(), - from_kuid(&init_user_ns, current_fsuid())); - return 0; - } - - /* Whole node dedicated to single job */ - if (strcmp(obd_jobid_var, JOBSTATS_NODELOCAL) == 0) { - strcpy(jobid, obd_jobid_node); - return 0; - } - - return -ENOENT; -} -EXPORT_SYMBOL(lustre_get_jobid); - -static int class_resolve_dev_name(__u32 len, const char *name) -{ - int rc; - int dev; - - if (!len || !name) { - CERROR("No name passed,!\n"); - rc = -EINVAL; - goto out; - } - if (name[len - 1] != 0) { - CERROR("Name not nul terminated!\n"); - rc = -EINVAL; - goto out; - } - - CDEBUG(D_IOCTL, "device name %s\n", name); - dev = class_name2dev(name); - if (dev == -1) { - CDEBUG(D_IOCTL, "No device for name %s!\n", name); - rc = -EINVAL; - goto out; - } - - CDEBUG(D_IOCTL, "device name %s, dev %d\n", name, dev); - rc = dev; - -out: - return rc; -} - -int class_handle_ioctl(unsigned int cmd, unsigned long arg) -{ - char *buf = NULL; - struct obd_ioctl_data *data; - struct libcfs_debug_ioctl_data *debug_data; - struct obd_device *obd = NULL; - int err = 0, len = 0; - - /* only for debugging */ - if (cmd == LIBCFS_IOC_DEBUG_MASK) { - debug_data = (struct libcfs_debug_ioctl_data *)arg; - libcfs_subsystem_debug = debug_data->subs; - libcfs_debug = debug_data->debug; - return 0; - } - - CDEBUG(D_IOCTL, "cmd = %x\n", cmd); - if (obd_ioctl_getdata(&buf, &len, (void __user *)arg)) { - CERROR("OBD ioctl: data error\n"); - return -EINVAL; - } - data = (struct obd_ioctl_data *)buf; - - switch (cmd) { - case OBD_IOC_PROCESS_CFG: { - struct lustre_cfg *lcfg; - - if (!data->ioc_plen1 || !data->ioc_pbuf1) { - CERROR("No config buffer passed!\n"); - err = -EINVAL; - goto out; - } - lcfg = kzalloc(data->ioc_plen1, GFP_NOFS); - if (!lcfg) { - err = -ENOMEM; - goto out; - } - if (copy_from_user(lcfg, data->ioc_pbuf1, data->ioc_plen1)) - err = -EFAULT; - if (!err) - err = lustre_cfg_sanity_check(lcfg, data->ioc_plen1); - if (!err) - err = class_process_config(lcfg); - - kfree(lcfg); - goto out; - } - - case OBD_GET_VERSION: - if (!data->ioc_inlbuf1) { - CERROR("No buffer passed in ioctl\n"); - err = -EINVAL; - goto out; - } - - if (strlen(LUSTRE_VERSION_STRING) + 1 > data->ioc_inllen1) { - CERROR("ioctl buffer too small to hold version\n"); - err = -EINVAL; - goto out; - } - - memcpy(data->ioc_bulk, LUSTRE_VERSION_STRING, - strlen(LUSTRE_VERSION_STRING) + 1); - - if (copy_to_user((void __user *)arg, data, len)) - err = -EFAULT; - goto out; - - case OBD_IOC_NAME2DEV: { - /* Resolve a device name. This does not change the - * currently selected device. - */ - int dev; - - dev = class_resolve_dev_name(data->ioc_inllen1, - data->ioc_inlbuf1); - data->ioc_dev = dev; - if (dev < 0) { - err = -EINVAL; - goto out; - } - - if (copy_to_user((void __user *)arg, data, sizeof(*data))) - err = -EFAULT; - goto out; - } - - case OBD_IOC_UUID2DEV: { - /* Resolve a device uuid. This does not change the - * currently selected device. - */ - int dev; - struct obd_uuid uuid; - - if (!data->ioc_inllen1 || !data->ioc_inlbuf1) { - CERROR("No UUID passed!\n"); - err = -EINVAL; - goto out; - } - if (data->ioc_inlbuf1[data->ioc_inllen1 - 1] != 0) { - CERROR("UUID not NUL terminated!\n"); - err = -EINVAL; - goto out; - } - - CDEBUG(D_IOCTL, "device name %s\n", data->ioc_inlbuf1); - obd_str2uuid(&uuid, data->ioc_inlbuf1); - dev = class_uuid2dev(&uuid); - data->ioc_dev = dev; - if (dev == -1) { - CDEBUG(D_IOCTL, "No device for UUID %s!\n", - data->ioc_inlbuf1); - err = -EINVAL; - goto out; - } - - CDEBUG(D_IOCTL, "device name %s, dev %d\n", data->ioc_inlbuf1, - dev); - - if (copy_to_user((void __user *)arg, data, sizeof(*data))) - err = -EFAULT; - goto out; - } - - case OBD_IOC_GETDEVICE: { - int index = data->ioc_count; - char *status, *str; - - if (!data->ioc_inlbuf1) { - CERROR("No buffer passed in ioctl\n"); - err = -EINVAL; - goto out; - } - if (data->ioc_inllen1 < 128) { - CERROR("ioctl buffer too small to hold version\n"); - err = -EINVAL; - goto out; - } - - obd = class_num2obd(index); - if (!obd) { - err = -ENOENT; - goto out; - } - - if (obd->obd_stopping) - status = "ST"; - else if (obd->obd_set_up) - status = "UP"; - else if (obd->obd_attached) - status = "AT"; - else - status = "--"; - str = (char *)data->ioc_bulk; - snprintf(str, len - sizeof(*data), "%3d %s %s %s %s %d", - (int)index, status, obd->obd_type->typ_name, - obd->obd_name, obd->obd_uuid.uuid, - atomic_read(&obd->obd_refcount)); - - if (copy_to_user((void __user *)arg, data, len)) - err = -EFAULT; - goto out; - } - } - - if (data->ioc_dev == OBD_DEV_BY_DEVNAME) { - if (data->ioc_inllen4 <= 0 || !data->ioc_inlbuf4) { - err = -EINVAL; - goto out; - } - if (strnlen(data->ioc_inlbuf4, MAX_OBD_NAME) >= MAX_OBD_NAME) { - err = -EINVAL; - goto out; - } - obd = class_name2obd(data->ioc_inlbuf4); - } else if (data->ioc_dev < class_devno_max()) { - obd = class_num2obd(data->ioc_dev); - } else { - CERROR("OBD ioctl: No device\n"); - err = -EINVAL; - goto out; - } - - if (!obd) { - CERROR("OBD ioctl : No Device %d\n", data->ioc_dev); - err = -EINVAL; - goto out; - } - LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC); - - if (!obd->obd_set_up || obd->obd_stopping) { - CERROR("OBD ioctl: device not setup %d\n", data->ioc_dev); - err = -EINVAL; - goto out; - } - - switch (cmd) { - case OBD_IOC_NO_TRANSNO: { - if (!obd->obd_attached) { - CERROR("Device %d not attached\n", obd->obd_minor); - err = -ENODEV; - goto out; - } - CDEBUG(D_HA, "%s: disabling committed-transno notification\n", - obd->obd_name); - obd->obd_no_transno = 1; - err = 0; - goto out; - } - - default: { - err = obd_iocontrol(cmd, obd->obd_self_export, len, data, NULL); - if (err) - goto out; - - if (copy_to_user((void __user *)arg, data, len)) - err = -EFAULT; - goto out; - } - } - - out: - kvfree(buf); - return err; -} /* class_handle_ioctl */ - -#define OBD_INIT_CHECK -static int obd_init_checks(void) -{ - __u64 u64val, div64val; - char buf[64]; - int len, ret = 0; - - CDEBUG(D_INFO, "LPU64=%s, LPD64=%s, LPX64=%s\n", "%llu", "%lld", - "%#llx"); - - CDEBUG(D_INFO, "OBD_OBJECT_EOF = %#llx\n", (__u64)OBD_OBJECT_EOF); - - u64val = OBD_OBJECT_EOF; - CDEBUG(D_INFO, "u64val OBD_OBJECT_EOF = %#llx\n", u64val); - if (u64val != OBD_OBJECT_EOF) { - CERROR("__u64 %#llx(%d) != 0xffffffffffffffff\n", - u64val, (int)sizeof(u64val)); - ret = -EINVAL; - } - len = snprintf(buf, sizeof(buf), "%#llx", u64val); - if (len != 18) { - CWARN("LPX64 wrong length! strlen(%s)=%d != 18\n", buf, len); - ret = -EINVAL; - } - - div64val = OBD_OBJECT_EOF; - CDEBUG(D_INFO, "u64val OBD_OBJECT_EOF = %#llx\n", u64val); - if (u64val != OBD_OBJECT_EOF) { - CERROR("__u64 %#llx(%d) != 0xffffffffffffffff\n", - u64val, (int)sizeof(u64val)); - ret = -EOVERFLOW; - } - if (u64val >> 8 != OBD_OBJECT_EOF >> 8) { - CERROR("__u64 %#llx(%d) != 0xffffffffffffffff\n", - u64val, (int)sizeof(u64val)); - return -EOVERFLOW; - } - if (do_div(div64val, 256) != (u64val & 255)) { - CERROR("do_div(%#llx,256) != %llu\n", u64val, u64val & 255); - return -EOVERFLOW; - } - if (u64val >> 8 != div64val) { - CERROR("do_div(%#llx,256) %llu != %llu\n", - u64val, div64val, u64val >> 8); - return -EOVERFLOW; - } - len = snprintf(buf, sizeof(buf), "%#llx", u64val); - if (len != 18) { - CWARN("LPX64 wrong length! strlen(%s)=%d != 18\n", buf, len); - ret = -EINVAL; - } - len = snprintf(buf, sizeof(buf), "%llu", u64val); - if (len != 20) { - CWARN("LPU64 wrong length! strlen(%s)=%d != 20\n", buf, len); - ret = -EINVAL; - } - len = snprintf(buf, sizeof(buf), "%lld", u64val); - if (len != 2) { - CWARN("LPD64 wrong length! strlen(%s)=%d != 2\n", buf, len); - ret = -EINVAL; - } - if ((u64val & ~PAGE_MASK) >= PAGE_SIZE) { - CWARN("mask failed: u64val %llu >= %llu\n", u64val, - (__u64)PAGE_SIZE); - ret = -EINVAL; - } - - return ret; -} - -static int __init obdclass_init(void) -{ - int i, err; - - LCONSOLE_INFO("Lustre: Build Version: " LUSTRE_VERSION_STRING "\n"); - - spin_lock_init(&obd_types_lock); - obd_zombie_impexp_init(); - - err = obd_init_checks(); - if (err) - return err; - - class_init_uuidlist(); - err = class_handle_init(); - if (err) - return err; - - INIT_LIST_HEAD(&obd_types); - - err = misc_register(&obd_psdev); - if (err) { - CERROR("cannot register %d err %d\n", OBD_DEV_MINOR, err); - return err; - } - - /* This struct is already zeroed for us (static global) */ - for (i = 0; i < class_devno_max(); i++) - obd_devs[i] = NULL; - - /* Default the dirty page cache cap to 1/2 of system memory. - * For clients with less memory, a larger fraction is needed - * for other purposes (mostly for BGL). - */ - if (totalram_pages <= 512 << (20 - PAGE_SHIFT)) - obd_max_dirty_pages = totalram_pages / 4; - else - obd_max_dirty_pages = totalram_pages / 2; - - err = obd_init_caches(); - if (err) - return err; - - err = class_procfs_init(); - if (err) - return err; - - err = obd_sysctl_init(); - if (err) - return err; - - err = lu_global_init(); - if (err) - return err; - - err = cl_global_init(); - if (err != 0) - return err; - - err = llog_info_init(); - if (err) - return err; - - err = lustre_register_fs(); - - return err; -} - -static void obdclass_exit(void) -{ - lustre_unregister_fs(); - - misc_deregister(&obd_psdev); - llog_info_fini(); - cl_global_fini(); - lu_global_fini(); - - obd_cleanup_caches(); - - class_procfs_clean(); - - class_handle_cleanup(); - class_exit_uuidlist(); - obd_zombie_impexp_stop(); -} - -MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>"); -MODULE_DESCRIPTION("Lustre Class Driver"); -MODULE_VERSION(LUSTRE_VERSION_STRING); -MODULE_LICENSE("GPL"); - -module_init(obdclass_init); -module_exit(obdclass_exit); diff --git a/drivers/staging/lustre/lustre/obdclass/debug.c b/drivers/staging/lustre/lustre/obdclass/debug.c deleted file mode 100644 index 2156a82a613a..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/debug.c +++ /dev/null @@ -1,96 +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, 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lustre/obdclass/debug.c - * - * Helper routines for dumping data structs for debugging. - */ - -#define DEBUG_SUBSYSTEM D_OTHER - -#include <asm/unaligned.h> - -#include <obd_support.h> -#include <lustre_debug.h> -#include <lustre_net.h> - -#define LPDS sizeof(__u64) -int block_debug_setup(void *addr, int len, __u64 off, __u64 id) -{ - LASSERT(addr); - - put_unaligned_le64(off, addr); - put_unaligned_le64(id, addr + LPDS); - addr += len - LPDS - LPDS; - put_unaligned_le64(off, addr); - put_unaligned_le64(id, addr + LPDS); - - return 0; -} -EXPORT_SYMBOL(block_debug_setup); - -int block_debug_check(char *who, void *addr, int end, __u64 off, __u64 id) -{ - __u64 ne_off; - int err = 0; - - LASSERT(addr); - - ne_off = le64_to_cpu(off); - id = le64_to_cpu(id); - if (memcmp(addr, (char *)&ne_off, LPDS)) { - CDEBUG(D_ERROR, "%s: id %#llx offset %llu off: %#llx != %#llx\n", - who, id, off, *(__u64 *)addr, ne_off); - err = -EINVAL; - } - if (memcmp(addr + LPDS, (char *)&id, LPDS)) { - CDEBUG(D_ERROR, "%s: id %#llx offset %llu id: %#llx != %#llx\n", - who, id, off, *(__u64 *)(addr + LPDS), id); - err = -EINVAL; - } - - addr += end - LPDS - LPDS; - if (memcmp(addr, (char *)&ne_off, LPDS)) { - CDEBUG(D_ERROR, "%s: id %#llx offset %llu end off: %#llx != %#llx\n", - who, id, off, *(__u64 *)addr, ne_off); - err = -EINVAL; - } - if (memcmp(addr + LPDS, (char *)&id, LPDS)) { - CDEBUG(D_ERROR, "%s: id %#llx offset %llu end id: %#llx != %#llx\n", - who, id, off, *(__u64 *)(addr + LPDS), id); - err = -EINVAL; - } - - return err; -} -EXPORT_SYMBOL(block_debug_check); -#undef LPDS diff --git a/drivers/staging/lustre/lustre/obdclass/genops.c b/drivers/staging/lustre/lustre/obdclass/genops.c deleted file mode 100644 index 63ccbabb4c5a..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/genops.c +++ /dev/null @@ -1,1514 +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) 1999, 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. - * - * lustre/obdclass/genops.c - * - * These are the only exported functions, they provide some generic - * infrastructure for managing object devices - */ - -#define DEBUG_SUBSYSTEM S_CLASS -#include <obd_class.h> -#include <lprocfs_status.h> -#include <lustre_kernelcomm.h> - -spinlock_t obd_types_lock; - -static struct kmem_cache *obd_device_cachep; -struct kmem_cache *obdo_cachep; -EXPORT_SYMBOL(obdo_cachep); -static struct kmem_cache *import_cachep; - -static struct workqueue_struct *zombie_wq; -static void obd_zombie_export_add(struct obd_export *exp); -static void obd_zombie_import_add(struct obd_import *imp); - -int (*ptlrpc_put_connection_superhack)(struct ptlrpc_connection *c); -EXPORT_SYMBOL(ptlrpc_put_connection_superhack); - -/* - * support functions: we could use inter-module communication, but this - * is more portable to other OS's - */ -static struct obd_device *obd_device_alloc(void) -{ - struct obd_device *obd; - - obd = kmem_cache_zalloc(obd_device_cachep, GFP_NOFS); - if (obd) - obd->obd_magic = OBD_DEVICE_MAGIC; - return obd; -} - -static void obd_device_free(struct obd_device *obd) -{ - LASSERTF(obd->obd_magic == OBD_DEVICE_MAGIC, "obd %p obd_magic %08x != %08x\n", - obd, obd->obd_magic, OBD_DEVICE_MAGIC); - if (obd->obd_namespace) { - CERROR("obd %p: namespace %p was not properly cleaned up (obd_force=%d)!\n", - obd, obd->obd_namespace, obd->obd_force); - LBUG(); - } - lu_ref_fini(&obd->obd_reference); - kmem_cache_free(obd_device_cachep, obd); -} - -static struct obd_type *class_search_type(const char *name) -{ - struct list_head *tmp; - struct obd_type *type; - - spin_lock(&obd_types_lock); - list_for_each(tmp, &obd_types) { - type = list_entry(tmp, struct obd_type, typ_chain); - if (strcmp(type->typ_name, name) == 0) { - spin_unlock(&obd_types_lock); - return type; - } - } - spin_unlock(&obd_types_lock); - return NULL; -} - -static struct obd_type *class_get_type(const char *name) -{ - struct obd_type *type = class_search_type(name); - - if (!type) { - const char *modname = name; - - if (!request_module("%s", modname)) { - CDEBUG(D_INFO, "Loaded module '%s'\n", modname); - type = class_search_type(name); - } else { - LCONSOLE_ERROR_MSG(0x158, "Can't load module '%s'\n", - modname); - } - } - if (type) { - spin_lock(&type->obd_type_lock); - type->typ_refcnt++; - try_module_get(type->typ_dt_ops->owner); - spin_unlock(&type->obd_type_lock); - } - return type; -} - -void class_put_type(struct obd_type *type) -{ - LASSERT(type); - spin_lock(&type->obd_type_lock); - type->typ_refcnt--; - module_put(type->typ_dt_ops->owner); - spin_unlock(&type->obd_type_lock); -} - -#define CLASS_MAX_NAME 1024 - -int class_register_type(struct obd_ops *dt_ops, struct md_ops *md_ops, - const char *name, - struct lu_device_type *ldt) -{ - struct obd_type *type; - int rc; - - /* sanity check */ - LASSERT(strnlen(name, CLASS_MAX_NAME) < CLASS_MAX_NAME); - - if (class_search_type(name)) { - CDEBUG(D_IOCTL, "Type %s already registered\n", name); - return -EEXIST; - } - - rc = -ENOMEM; - type = kzalloc(sizeof(*type), GFP_NOFS); - if (!type) - return rc; - - type->typ_dt_ops = kzalloc(sizeof(*type->typ_dt_ops), GFP_NOFS); - type->typ_md_ops = kzalloc(sizeof(*type->typ_md_ops), GFP_NOFS); - type->typ_name = kzalloc(strlen(name) + 1, GFP_NOFS); - - if (!type->typ_dt_ops || - !type->typ_md_ops || - !type->typ_name) - goto failed; - - *type->typ_dt_ops = *dt_ops; - /* md_ops is optional */ - if (md_ops) - *type->typ_md_ops = *md_ops; - strcpy(type->typ_name, name); - spin_lock_init(&type->obd_type_lock); - - type->typ_debugfs_entry = ldebugfs_register(type->typ_name, - debugfs_lustre_root, - NULL, type); - if (IS_ERR_OR_NULL(type->typ_debugfs_entry)) { - rc = type->typ_debugfs_entry ? PTR_ERR(type->typ_debugfs_entry) - : -ENOMEM; - type->typ_debugfs_entry = NULL; - goto failed; - } - - type->typ_kobj = kobject_create_and_add(type->typ_name, lustre_kobj); - if (!type->typ_kobj) { - rc = -ENOMEM; - goto failed; - } - - if (ldt) { - type->typ_lu = ldt; - rc = lu_device_type_init(ldt); - if (rc != 0) - goto failed; - } - - spin_lock(&obd_types_lock); - list_add(&type->typ_chain, &obd_types); - spin_unlock(&obd_types_lock); - - return 0; - - failed: - if (type->typ_kobj) - kobject_put(type->typ_kobj); - kfree(type->typ_name); - kfree(type->typ_md_ops); - kfree(type->typ_dt_ops); - kfree(type); - return rc; -} -EXPORT_SYMBOL(class_register_type); - -int class_unregister_type(const char *name) -{ - struct obd_type *type = class_search_type(name); - - if (!type) { - CERROR("unknown obd type\n"); - return -EINVAL; - } - - if (type->typ_refcnt) { - CERROR("type %s has refcount (%d)\n", name, type->typ_refcnt); - /* This is a bad situation, let's make the best of it */ - /* Remove ops, but leave the name for debugging */ - kfree(type->typ_dt_ops); - kfree(type->typ_md_ops); - return -EBUSY; - } - - if (type->typ_kobj) - kobject_put(type->typ_kobj); - - if (!IS_ERR_OR_NULL(type->typ_debugfs_entry)) - ldebugfs_remove(&type->typ_debugfs_entry); - - if (type->typ_lu) - lu_device_type_fini(type->typ_lu); - - spin_lock(&obd_types_lock); - list_del(&type->typ_chain); - spin_unlock(&obd_types_lock); - kfree(type->typ_name); - kfree(type->typ_dt_ops); - kfree(type->typ_md_ops); - kfree(type); - return 0; -} /* class_unregister_type */ -EXPORT_SYMBOL(class_unregister_type); - -/** - * Create a new obd device. - * - * Find an empty slot in ::obd_devs[], create a new obd device in it. - * - * \param[in] type_name obd device type string. - * \param[in] name obd device name. - * - * \retval NULL if create fails, otherwise return the obd device - * pointer created. - */ -struct obd_device *class_newdev(const char *type_name, const char *name) -{ - struct obd_device *result = NULL; - struct obd_device *newdev; - struct obd_type *type = NULL; - int i; - int new_obd_minor = 0; - - if (strlen(name) >= MAX_OBD_NAME) { - CERROR("name/uuid must be < %u bytes long\n", MAX_OBD_NAME); - return ERR_PTR(-EINVAL); - } - - type = class_get_type(type_name); - if (!type) { - CERROR("OBD: unknown type: %s\n", type_name); - return ERR_PTR(-ENODEV); - } - - newdev = obd_device_alloc(); - if (!newdev) { - result = ERR_PTR(-ENOMEM); - goto out_type; - } - - LASSERT(newdev->obd_magic == OBD_DEVICE_MAGIC); - - write_lock(&obd_dev_lock); - for (i = 0; i < class_devno_max(); i++) { - struct obd_device *obd = class_num2obd(i); - - if (obd && (strcmp(name, obd->obd_name) == 0)) { - CERROR("Device %s already exists at %d, won't add\n", - name, i); - if (result) { - LASSERTF(result->obd_magic == OBD_DEVICE_MAGIC, - "%p obd_magic %08x != %08x\n", result, - result->obd_magic, OBD_DEVICE_MAGIC); - LASSERTF(result->obd_minor == new_obd_minor, - "%p obd_minor %d != %d\n", result, - result->obd_minor, new_obd_minor); - - obd_devs[result->obd_minor] = NULL; - result->obd_name[0] = '\0'; - } - result = ERR_PTR(-EEXIST); - break; - } - if (!result && !obd) { - result = newdev; - result->obd_minor = i; - new_obd_minor = i; - result->obd_type = type; - strncpy(result->obd_name, name, - sizeof(result->obd_name) - 1); - obd_devs[i] = result; - } - } - write_unlock(&obd_dev_lock); - - if (!result && i >= class_devno_max()) { - CERROR("all %u OBD devices used, increase MAX_OBD_DEVICES\n", - class_devno_max()); - result = ERR_PTR(-EOVERFLOW); - goto out; - } - - if (IS_ERR(result)) - goto out; - - CDEBUG(D_IOCTL, "Adding new device %s (%p)\n", - result->obd_name, result); - - return result; -out: - obd_device_free(newdev); -out_type: - class_put_type(type); - return result; -} - -void class_release_dev(struct obd_device *obd) -{ - struct obd_type *obd_type = obd->obd_type; - - LASSERTF(obd->obd_magic == OBD_DEVICE_MAGIC, "%p obd_magic %08x != %08x\n", - obd, obd->obd_magic, OBD_DEVICE_MAGIC); - LASSERTF(obd == obd_devs[obd->obd_minor], "obd %p != obd_devs[%d] %p\n", - obd, obd->obd_minor, obd_devs[obd->obd_minor]); - LASSERT(obd_type); - - CDEBUG(D_INFO, "Release obd device %s at %d obd_type name =%s\n", - obd->obd_name, obd->obd_minor, obd->obd_type->typ_name); - - write_lock(&obd_dev_lock); - obd_devs[obd->obd_minor] = NULL; - write_unlock(&obd_dev_lock); - obd_device_free(obd); - - class_put_type(obd_type); -} - -int class_name2dev(const char *name) -{ - int i; - - if (!name) - return -1; - - read_lock(&obd_dev_lock); - for (i = 0; i < class_devno_max(); i++) { - struct obd_device *obd = class_num2obd(i); - - if (obd && strcmp(name, obd->obd_name) == 0) { - /* Make sure we finished attaching before we give - * out any references - */ - LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC); - if (obd->obd_attached) { - read_unlock(&obd_dev_lock); - return i; - } - break; - } - } - read_unlock(&obd_dev_lock); - - return -1; -} - -struct obd_device *class_name2obd(const char *name) -{ - int dev = class_name2dev(name); - - if (dev < 0 || dev > class_devno_max()) - return NULL; - return class_num2obd(dev); -} -EXPORT_SYMBOL(class_name2obd); - -int class_uuid2dev(struct obd_uuid *uuid) -{ - int i; - - read_lock(&obd_dev_lock); - for (i = 0; i < class_devno_max(); i++) { - struct obd_device *obd = class_num2obd(i); - - if (obd && obd_uuid_equals(uuid, &obd->obd_uuid)) { - LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC); - read_unlock(&obd_dev_lock); - return i; - } - } - read_unlock(&obd_dev_lock); - - return -1; -} - -/** - * Get obd device from ::obd_devs[] - * - * \param num [in] array index - * - * \retval NULL if ::obd_devs[\a num] does not contains an obd device - * otherwise return the obd device there. - */ -struct obd_device *class_num2obd(int num) -{ - struct obd_device *obd = NULL; - - if (num < class_devno_max()) { - obd = obd_devs[num]; - if (!obd) - return NULL; - - LASSERTF(obd->obd_magic == OBD_DEVICE_MAGIC, - "%p obd_magic %08x != %08x\n", - obd, obd->obd_magic, OBD_DEVICE_MAGIC); - LASSERTF(obd->obd_minor == num, - "%p obd_minor %0d != %0d\n", - obd, obd->obd_minor, num); - } - - return obd; -} - -/* Search for a client OBD connected to tgt_uuid. If grp_uuid is - * specified, then only the client with that uuid is returned, - * otherwise any client connected to the tgt is returned. - */ -struct obd_device *class_find_client_obd(struct obd_uuid *tgt_uuid, - const char *typ_name, - struct obd_uuid *grp_uuid) -{ - int i; - - read_lock(&obd_dev_lock); - for (i = 0; i < class_devno_max(); i++) { - struct obd_device *obd = class_num2obd(i); - - if (!obd) - continue; - if ((strncmp(obd->obd_type->typ_name, typ_name, - strlen(typ_name)) == 0)) { - if (obd_uuid_equals(tgt_uuid, - &obd->u.cli.cl_target_uuid) && - ((grp_uuid) ? obd_uuid_equals(grp_uuid, - &obd->obd_uuid) : 1)) { - read_unlock(&obd_dev_lock); - return obd; - } - } - } - read_unlock(&obd_dev_lock); - - return NULL; -} -EXPORT_SYMBOL(class_find_client_obd); - -/* Iterate the obd_device list looking devices have grp_uuid. Start - * searching at *next, and if a device is found, the next index to look - * at is saved in *next. If next is NULL, then the first matching device - * will always be returned. - */ -struct obd_device *class_devices_in_group(struct obd_uuid *grp_uuid, int *next) -{ - int i; - - if (!next) - i = 0; - else if (*next >= 0 && *next < class_devno_max()) - i = *next; - else - return NULL; - - read_lock(&obd_dev_lock); - for (; i < class_devno_max(); i++) { - struct obd_device *obd = class_num2obd(i); - - if (!obd) - continue; - if (obd_uuid_equals(grp_uuid, &obd->obd_uuid)) { - if (next) - *next = i + 1; - read_unlock(&obd_dev_lock); - return obd; - } - } - read_unlock(&obd_dev_lock); - - return NULL; -} -EXPORT_SYMBOL(class_devices_in_group); - -/** - * to notify sptlrpc log for \a fsname has changed, let every relevant OBD - * adjust sptlrpc settings accordingly. - */ -int class_notify_sptlrpc_conf(const char *fsname, int namelen) -{ - struct obd_device *obd; - const char *type; - int i, rc = 0, rc2; - - LASSERT(namelen > 0); - - read_lock(&obd_dev_lock); - for (i = 0; i < class_devno_max(); i++) { - obd = class_num2obd(i); - - if (!obd || obd->obd_set_up == 0 || obd->obd_stopping) - continue; - - /* only notify mdc, osc, mdt, ost */ - type = obd->obd_type->typ_name; - if (strcmp(type, LUSTRE_MDC_NAME) != 0 && - strcmp(type, LUSTRE_OSC_NAME) != 0 && - strcmp(type, LUSTRE_MDT_NAME) != 0 && - strcmp(type, LUSTRE_OST_NAME) != 0) - continue; - - if (strncmp(obd->obd_name, fsname, namelen)) - continue; - - class_incref(obd, __func__, obd); - read_unlock(&obd_dev_lock); - rc2 = obd_set_info_async(NULL, obd->obd_self_export, - sizeof(KEY_SPTLRPC_CONF), - KEY_SPTLRPC_CONF, 0, NULL, NULL); - rc = rc ? rc : rc2; - class_decref(obd, __func__, obd); - read_lock(&obd_dev_lock); - } - read_unlock(&obd_dev_lock); - return rc; -} -EXPORT_SYMBOL(class_notify_sptlrpc_conf); - -void obd_cleanup_caches(void) -{ - kmem_cache_destroy(obd_device_cachep); - obd_device_cachep = NULL; - kmem_cache_destroy(obdo_cachep); - obdo_cachep = NULL; - kmem_cache_destroy(import_cachep); - import_cachep = NULL; -} - -int obd_init_caches(void) -{ - LASSERT(!obd_device_cachep); - obd_device_cachep = kmem_cache_create("ll_obd_dev_cache", - sizeof(struct obd_device), - 0, 0, NULL); - if (!obd_device_cachep) - goto out; - - LASSERT(!obdo_cachep); - obdo_cachep = kmem_cache_create("ll_obdo_cache", sizeof(struct obdo), - 0, 0, NULL); - if (!obdo_cachep) - goto out; - - LASSERT(!import_cachep); - import_cachep = kmem_cache_create("ll_import_cache", - sizeof(struct obd_import), - 0, 0, NULL); - if (!import_cachep) - goto out; - - return 0; - out: - obd_cleanup_caches(); - return -ENOMEM; -} - -/* map connection to client */ -struct obd_export *class_conn2export(struct lustre_handle *conn) -{ - struct obd_export *export; - - if (!conn) { - CDEBUG(D_CACHE, "looking for null handle\n"); - return NULL; - } - - if (conn->cookie == -1) { /* this means assign a new connection */ - CDEBUG(D_CACHE, "want a new connection\n"); - return NULL; - } - - CDEBUG(D_INFO, "looking for export cookie %#llx\n", conn->cookie); - export = class_handle2object(conn->cookie, NULL); - return export; -} -EXPORT_SYMBOL(class_conn2export); - -struct obd_device *class_exp2obd(struct obd_export *exp) -{ - if (exp) - return exp->exp_obd; - return NULL; -} -EXPORT_SYMBOL(class_exp2obd); - -struct obd_import *class_exp2cliimp(struct obd_export *exp) -{ - struct obd_device *obd = exp->exp_obd; - - if (!obd) - return NULL; - return obd->u.cli.cl_import; -} -EXPORT_SYMBOL(class_exp2cliimp); - -/* Export management functions */ -static void class_export_destroy(struct obd_export *exp) -{ - struct obd_device *obd = exp->exp_obd; - - LASSERT_ATOMIC_ZERO(&exp->exp_refcount); - LASSERT(obd); - - CDEBUG(D_IOCTL, "destroying export %p/%s for %s\n", exp, - exp->exp_client_uuid.uuid, obd->obd_name); - - /* "Local" exports (lctl, LOV->{mdc,osc}) have no connection. */ - if (exp->exp_connection) - ptlrpc_put_connection_superhack(exp->exp_connection); - - LASSERT(list_empty(&exp->exp_outstanding_replies)); - LASSERT(list_empty(&exp->exp_uncommitted_replies)); - LASSERT(list_empty(&exp->exp_req_replay_queue)); - LASSERT(list_empty(&exp->exp_hp_rpcs)); - obd_destroy_export(exp); - class_decref(obd, "export", exp); - - OBD_FREE_RCU(exp, sizeof(*exp), &exp->exp_handle); -} - -static void export_handle_addref(void *export) -{ - class_export_get(export); -} - -static struct portals_handle_ops export_handle_ops = { - .hop_addref = export_handle_addref, - .hop_free = NULL, -}; - -struct obd_export *class_export_get(struct obd_export *exp) -{ - atomic_inc(&exp->exp_refcount); - CDEBUG(D_INFO, "GETting export %p : new refcount %d\n", exp, - atomic_read(&exp->exp_refcount)); - return exp; -} -EXPORT_SYMBOL(class_export_get); - -void class_export_put(struct obd_export *exp) -{ - LASSERT_ATOMIC_GT_LT(&exp->exp_refcount, 0, LI_POISON); - CDEBUG(D_INFO, "PUTting export %p : new refcount %d\n", exp, - atomic_read(&exp->exp_refcount) - 1); - - if (atomic_dec_and_test(&exp->exp_refcount)) { - LASSERT(!list_empty(&exp->exp_obd_chain)); - CDEBUG(D_IOCTL, "final put %p/%s\n", - exp, exp->exp_client_uuid.uuid); - - /* release nid stat refererence */ - lprocfs_exp_cleanup(exp); - - obd_zombie_export_add(exp); - } -} -EXPORT_SYMBOL(class_export_put); - -static void obd_zombie_exp_cull(struct work_struct *ws) -{ - struct obd_export *export = container_of(ws, struct obd_export, exp_zombie_work); - - class_export_destroy(export); -} - -/* Creates a new export, adds it to the hash table, and returns a - * pointer to it. The refcount is 2: one for the hash reference, and - * one for the pointer returned by this function. - */ -struct obd_export *class_new_export(struct obd_device *obd, - struct obd_uuid *cluuid) -{ - struct obd_export *export; - struct cfs_hash *hash = NULL; - int rc = 0; - - export = kzalloc(sizeof(*export), GFP_NOFS); - if (!export) - return ERR_PTR(-ENOMEM); - - export->exp_conn_cnt = 0; - export->exp_lock_hash = NULL; - export->exp_flock_hash = NULL; - atomic_set(&export->exp_refcount, 2); - atomic_set(&export->exp_rpc_count, 0); - atomic_set(&export->exp_cb_count, 0); - atomic_set(&export->exp_locks_count, 0); -#if LUSTRE_TRACKS_LOCK_EXP_REFS - INIT_LIST_HEAD(&export->exp_locks_list); - spin_lock_init(&export->exp_locks_list_guard); -#endif - atomic_set(&export->exp_replay_count, 0); - export->exp_obd = obd; - INIT_LIST_HEAD(&export->exp_outstanding_replies); - spin_lock_init(&export->exp_uncommitted_replies_lock); - INIT_LIST_HEAD(&export->exp_uncommitted_replies); - INIT_LIST_HEAD(&export->exp_req_replay_queue); - INIT_LIST_HEAD(&export->exp_handle.h_link); - INIT_LIST_HEAD(&export->exp_hp_rpcs); - class_handle_hash(&export->exp_handle, &export_handle_ops); - spin_lock_init(&export->exp_lock); - spin_lock_init(&export->exp_rpc_lock); - INIT_HLIST_NODE(&export->exp_uuid_hash); - spin_lock_init(&export->exp_bl_list_lock); - INIT_LIST_HEAD(&export->exp_bl_list); - INIT_WORK(&export->exp_zombie_work, obd_zombie_exp_cull); - - export->exp_sp_peer = LUSTRE_SP_ANY; - export->exp_flvr.sf_rpc = SPTLRPC_FLVR_INVALID; - export->exp_client_uuid = *cluuid; - obd_init_export(export); - - spin_lock(&obd->obd_dev_lock); - /* shouldn't happen, but might race */ - if (obd->obd_stopping) { - rc = -ENODEV; - goto exit_unlock; - } - - hash = cfs_hash_getref(obd->obd_uuid_hash); - if (!hash) { - rc = -ENODEV; - goto exit_unlock; - } - spin_unlock(&obd->obd_dev_lock); - - if (!obd_uuid_equals(cluuid, &obd->obd_uuid)) { - rc = cfs_hash_add_unique(hash, cluuid, &export->exp_uuid_hash); - if (rc != 0) { - LCONSOLE_WARN("%s: denying duplicate export for %s, %d\n", - obd->obd_name, cluuid->uuid, rc); - rc = -EALREADY; - goto exit_err; - } - } - - spin_lock(&obd->obd_dev_lock); - if (obd->obd_stopping) { - cfs_hash_del(hash, cluuid, &export->exp_uuid_hash); - rc = -ENODEV; - goto exit_unlock; - } - - class_incref(obd, "export", export); - list_add(&export->exp_obd_chain, &export->exp_obd->obd_exports); - export->exp_obd->obd_num_exports++; - spin_unlock(&obd->obd_dev_lock); - cfs_hash_putref(hash); - return export; - -exit_unlock: - spin_unlock(&obd->obd_dev_lock); -exit_err: - if (hash) - cfs_hash_putref(hash); - class_handle_unhash(&export->exp_handle); - LASSERT(hlist_unhashed(&export->exp_uuid_hash)); - obd_destroy_export(export); - kfree(export); - return ERR_PTR(rc); -} -EXPORT_SYMBOL(class_new_export); - -void class_unlink_export(struct obd_export *exp) -{ - class_handle_unhash(&exp->exp_handle); - - spin_lock(&exp->exp_obd->obd_dev_lock); - /* delete an uuid-export hashitem from hashtables */ - if (!hlist_unhashed(&exp->exp_uuid_hash)) - cfs_hash_del(exp->exp_obd->obd_uuid_hash, - &exp->exp_client_uuid, - &exp->exp_uuid_hash); - - list_move(&exp->exp_obd_chain, &exp->exp_obd->obd_unlinked_exports); - exp->exp_obd->obd_num_exports--; - spin_unlock(&exp->exp_obd->obd_dev_lock); - class_export_put(exp); -} - -/* Import management functions */ -static void class_import_destroy(struct obd_import *imp) -{ - CDEBUG(D_IOCTL, "destroying import %p for %s\n", imp, - imp->imp_obd->obd_name); - - LASSERT_ATOMIC_ZERO(&imp->imp_refcount); - - ptlrpc_put_connection_superhack(imp->imp_connection); - - while (!list_empty(&imp->imp_conn_list)) { - struct obd_import_conn *imp_conn; - - imp_conn = list_entry(imp->imp_conn_list.next, - struct obd_import_conn, oic_item); - list_del_init(&imp_conn->oic_item); - ptlrpc_put_connection_superhack(imp_conn->oic_conn); - kfree(imp_conn); - } - - LASSERT(!imp->imp_sec); - class_decref(imp->imp_obd, "import", imp); - OBD_FREE_RCU(imp, sizeof(*imp), &imp->imp_handle); -} - -static void import_handle_addref(void *import) -{ - class_import_get(import); -} - -static struct portals_handle_ops import_handle_ops = { - .hop_addref = import_handle_addref, - .hop_free = NULL, -}; - -struct obd_import *class_import_get(struct obd_import *import) -{ - atomic_inc(&import->imp_refcount); - CDEBUG(D_INFO, "import %p refcount=%d obd=%s\n", import, - atomic_read(&import->imp_refcount), - import->imp_obd->obd_name); - return import; -} -EXPORT_SYMBOL(class_import_get); - -void class_import_put(struct obd_import *imp) -{ - LASSERT_ATOMIC_GT_LT(&imp->imp_refcount, 0, LI_POISON); - - CDEBUG(D_INFO, "import %p refcount=%d obd=%s\n", imp, - atomic_read(&imp->imp_refcount) - 1, - imp->imp_obd->obd_name); - - if (atomic_dec_and_test(&imp->imp_refcount)) { - CDEBUG(D_INFO, "final put import %p\n", imp); - obd_zombie_import_add(imp); - } - - /* catch possible import put race */ - LASSERT_ATOMIC_GE_LT(&imp->imp_refcount, 0, LI_POISON); -} -EXPORT_SYMBOL(class_import_put); - -static void init_imp_at(struct imp_at *at) -{ - int i; - - at_init(&at->iat_net_latency, 0, 0); - for (i = 0; i < IMP_AT_MAX_PORTALS; i++) { - /* max service estimates are tracked on the server side, so - * don't use the AT history here, just use the last reported - * val. (But keep hist for proc histogram, worst_ever) - */ - at_init(&at->iat_service_estimate[i], INITIAL_CONNECT_TIMEOUT, - AT_FLG_NOHIST); - } -} - -static void obd_zombie_imp_cull(struct work_struct *ws) -{ - struct obd_import *import = container_of(ws, struct obd_import, imp_zombie_work); - - class_import_destroy(import); -} - -struct obd_import *class_new_import(struct obd_device *obd) -{ - struct obd_import *imp; - - imp = kzalloc(sizeof(*imp), GFP_NOFS); - if (!imp) - return NULL; - - INIT_LIST_HEAD(&imp->imp_pinger_chain); - INIT_LIST_HEAD(&imp->imp_replay_list); - INIT_LIST_HEAD(&imp->imp_sending_list); - INIT_LIST_HEAD(&imp->imp_delayed_list); - INIT_LIST_HEAD(&imp->imp_committed_list); - INIT_LIST_HEAD(&imp->imp_unreplied_list); - imp->imp_known_replied_xid = 0; - imp->imp_replay_cursor = &imp->imp_committed_list; - spin_lock_init(&imp->imp_lock); - imp->imp_last_success_conn = 0; - imp->imp_state = LUSTRE_IMP_NEW; - imp->imp_obd = class_incref(obd, "import", imp); - mutex_init(&imp->imp_sec_mutex); - init_waitqueue_head(&imp->imp_recovery_waitq); - INIT_WORK(&imp->imp_zombie_work, obd_zombie_imp_cull); - - atomic_set(&imp->imp_refcount, 2); - atomic_set(&imp->imp_unregistering, 0); - atomic_set(&imp->imp_inflight, 0); - atomic_set(&imp->imp_replay_inflight, 0); - atomic_set(&imp->imp_inval_count, 0); - INIT_LIST_HEAD(&imp->imp_conn_list); - INIT_LIST_HEAD(&imp->imp_handle.h_link); - class_handle_hash(&imp->imp_handle, &import_handle_ops); - init_imp_at(&imp->imp_at); - - /* the default magic is V2, will be used in connect RPC, and - * then adjusted according to the flags in request/reply. - */ - imp->imp_msg_magic = LUSTRE_MSG_MAGIC_V2; - - return imp; -} -EXPORT_SYMBOL(class_new_import); - -void class_destroy_import(struct obd_import *import) -{ - LASSERT(import); - LASSERT(import != LP_POISON); - - class_handle_unhash(&import->imp_handle); - - spin_lock(&import->imp_lock); - import->imp_generation++; - spin_unlock(&import->imp_lock); - class_import_put(import); -} -EXPORT_SYMBOL(class_destroy_import); - -#if LUSTRE_TRACKS_LOCK_EXP_REFS - -void __class_export_add_lock_ref(struct obd_export *exp, struct ldlm_lock *lock) -{ - spin_lock(&exp->exp_locks_list_guard); - - LASSERT(lock->l_exp_refs_nr >= 0); - - if (lock->l_exp_refs_target && lock->l_exp_refs_target != exp) { - LCONSOLE_WARN("setting export %p for lock %p which already has export %p\n", - exp, lock, lock->l_exp_refs_target); - } - if ((lock->l_exp_refs_nr++) == 0) { - list_add(&lock->l_exp_refs_link, &exp->exp_locks_list); - lock->l_exp_refs_target = exp; - } - CDEBUG(D_INFO, "lock = %p, export = %p, refs = %u\n", - lock, exp, lock->l_exp_refs_nr); - spin_unlock(&exp->exp_locks_list_guard); -} - -void __class_export_del_lock_ref(struct obd_export *exp, struct ldlm_lock *lock) -{ - spin_lock(&exp->exp_locks_list_guard); - LASSERT(lock->l_exp_refs_nr > 0); - if (lock->l_exp_refs_target != exp) { - LCONSOLE_WARN("lock %p, mismatching export pointers: %p, %p\n", - lock, lock->l_exp_refs_target, exp); - } - if (-- lock->l_exp_refs_nr == 0) { - list_del_init(&lock->l_exp_refs_link); - lock->l_exp_refs_target = NULL; - } - CDEBUG(D_INFO, "lock = %p, export = %p, refs = %u\n", - lock, exp, lock->l_exp_refs_nr); - spin_unlock(&exp->exp_locks_list_guard); -} -#endif - -/* A connection defines an export context in which preallocation can - * be managed. This releases the export pointer reference, and returns - * the export handle, so the export refcount is 1 when this function - * returns. - */ -int class_connect(struct lustre_handle *conn, struct obd_device *obd, - struct obd_uuid *cluuid) -{ - struct obd_export *export; - - LASSERT(conn); - LASSERT(obd); - LASSERT(cluuid); - - export = class_new_export(obd, cluuid); - if (IS_ERR(export)) - return PTR_ERR(export); - - conn->cookie = export->exp_handle.h_cookie; - class_export_put(export); - - CDEBUG(D_IOCTL, "connect: client %s, cookie %#llx\n", - cluuid->uuid, conn->cookie); - return 0; -} -EXPORT_SYMBOL(class_connect); - -/* This function removes 1-3 references from the export: - * 1 - for export pointer passed - * and if disconnect really need - * 2 - removing from hash - * 3 - in client_unlink_export - * The export pointer passed to this function can destroyed - */ -int class_disconnect(struct obd_export *export) -{ - int already_disconnected; - - if (!export) { - CWARN("attempting to free NULL export %p\n", export); - return -EINVAL; - } - - spin_lock(&export->exp_lock); - already_disconnected = export->exp_disconnected; - export->exp_disconnected = 1; - spin_unlock(&export->exp_lock); - - /* class_cleanup(), abort_recovery(), and class_fail_export() - * all end up in here, and if any of them race we shouldn't - * call extra class_export_puts(). - */ - if (already_disconnected) - goto no_disconn; - - CDEBUG(D_IOCTL, "disconnect: cookie %#llx\n", - export->exp_handle.h_cookie); - - class_unlink_export(export); -no_disconn: - class_export_put(export); - return 0; -} -EXPORT_SYMBOL(class_disconnect); - -void class_fail_export(struct obd_export *exp) -{ - int rc, already_failed; - - spin_lock(&exp->exp_lock); - already_failed = exp->exp_failed; - exp->exp_failed = 1; - spin_unlock(&exp->exp_lock); - - if (already_failed) { - CDEBUG(D_HA, "disconnecting dead export %p/%s; skipping\n", - exp, exp->exp_client_uuid.uuid); - return; - } - - CDEBUG(D_HA, "disconnecting export %p/%s\n", - exp, exp->exp_client_uuid.uuid); - - if (obd_dump_on_timeout) - libcfs_debug_dumplog(); - - /* need for safe call CDEBUG after obd_disconnect */ - class_export_get(exp); - - /* Most callers into obd_disconnect are removing their own reference - * (request, for example) in addition to the one from the hash table. - * We don't have such a reference here, so make one. - */ - class_export_get(exp); - rc = obd_disconnect(exp); - if (rc) - CERROR("disconnecting export %p failed: %d\n", exp, rc); - else - CDEBUG(D_HA, "disconnected export %p/%s\n", - exp, exp->exp_client_uuid.uuid); - class_export_put(exp); -} -EXPORT_SYMBOL(class_fail_export); - -#if LUSTRE_TRACKS_LOCK_EXP_REFS -void (*class_export_dump_hook)(struct obd_export *) = NULL; -#endif - -/** - * Add export to the obd_zombie thread and notify it. - */ -static void obd_zombie_export_add(struct obd_export *exp) -{ - spin_lock(&exp->exp_obd->obd_dev_lock); - LASSERT(!list_empty(&exp->exp_obd_chain)); - list_del_init(&exp->exp_obd_chain); - spin_unlock(&exp->exp_obd->obd_dev_lock); - queue_work(zombie_wq, &exp->exp_zombie_work); -} - -/** - * Add import to the obd_zombie thread and notify it. - */ -static void obd_zombie_import_add(struct obd_import *imp) -{ - LASSERT(!imp->imp_sec); - queue_work(zombie_wq, &imp->imp_zombie_work); -} - -/** - * wait when obd_zombie import/export queues become empty - */ -void obd_zombie_barrier(void) -{ - flush_workqueue(zombie_wq); -} -EXPORT_SYMBOL(obd_zombie_barrier); - -/** - * start destroy zombie import/export thread - */ -int obd_zombie_impexp_init(void) -{ - zombie_wq = alloc_workqueue("obd_zombid", 0, 0); - if (!zombie_wq) - return -ENOMEM; - - return 0; -} - -/** - * stop destroy zombie import/export thread - */ -void obd_zombie_impexp_stop(void) -{ - destroy_workqueue(zombie_wq); -} - -struct obd_request_slot_waiter { - struct list_head orsw_entry; - wait_queue_head_t orsw_waitq; - bool orsw_signaled; -}; - -static bool obd_request_slot_avail(struct client_obd *cli, - struct obd_request_slot_waiter *orsw) -{ - bool avail; - - spin_lock(&cli->cl_loi_list_lock); - avail = !!list_empty(&orsw->orsw_entry); - spin_unlock(&cli->cl_loi_list_lock); - - return avail; -}; - -/* - * For network flow control, the RPC sponsor needs to acquire a credit - * before sending the RPC. The credits count for a connection is defined - * by the "cl_max_rpcs_in_flight". If all the credits are occpuied, then - * the subsequent RPC sponsors need to wait until others released their - * credits, or the administrator increased the "cl_max_rpcs_in_flight". - */ -int obd_get_request_slot(struct client_obd *cli) -{ - struct obd_request_slot_waiter orsw; - int rc; - - spin_lock(&cli->cl_loi_list_lock); - if (cli->cl_r_in_flight < cli->cl_max_rpcs_in_flight) { - cli->cl_r_in_flight++; - spin_unlock(&cli->cl_loi_list_lock); - return 0; - } - - init_waitqueue_head(&orsw.orsw_waitq); - list_add_tail(&orsw.orsw_entry, &cli->cl_loi_read_list); - orsw.orsw_signaled = false; - spin_unlock(&cli->cl_loi_list_lock); - - rc = l_wait_event_abortable(orsw.orsw_waitq, - obd_request_slot_avail(cli, &orsw) || - orsw.orsw_signaled); - - /* - * Here, we must take the lock to avoid the on-stack 'orsw' to be - * freed but other (such as obd_put_request_slot) is using it. - */ - spin_lock(&cli->cl_loi_list_lock); - if (rc) { - if (!orsw.orsw_signaled) { - if (list_empty(&orsw.orsw_entry)) - cli->cl_r_in_flight--; - else - list_del(&orsw.orsw_entry); - } - } - - if (orsw.orsw_signaled) { - LASSERT(list_empty(&orsw.orsw_entry)); - - rc = -EINTR; - } - spin_unlock(&cli->cl_loi_list_lock); - - return rc; -} -EXPORT_SYMBOL(obd_get_request_slot); - -void obd_put_request_slot(struct client_obd *cli) -{ - struct obd_request_slot_waiter *orsw; - - spin_lock(&cli->cl_loi_list_lock); - cli->cl_r_in_flight--; - - /* If there is free slot, wakeup the first waiter. */ - if (!list_empty(&cli->cl_loi_read_list) && - likely(cli->cl_r_in_flight < cli->cl_max_rpcs_in_flight)) { - orsw = list_entry(cli->cl_loi_read_list.next, - struct obd_request_slot_waiter, orsw_entry); - list_del_init(&orsw->orsw_entry); - cli->cl_r_in_flight++; - wake_up(&orsw->orsw_waitq); - } - spin_unlock(&cli->cl_loi_list_lock); -} -EXPORT_SYMBOL(obd_put_request_slot); - -__u32 obd_get_max_rpcs_in_flight(struct client_obd *cli) -{ - return cli->cl_max_rpcs_in_flight; -} -EXPORT_SYMBOL(obd_get_max_rpcs_in_flight); - -int obd_set_max_rpcs_in_flight(struct client_obd *cli, __u32 max) -{ - struct obd_request_slot_waiter *orsw; - const char *typ_name; - __u32 old; - int diff; - int rc; - int i; - - if (max > OBD_MAX_RIF_MAX || max < 1) - return -ERANGE; - - typ_name = cli->cl_import->imp_obd->obd_type->typ_name; - if (!strcmp(typ_name, LUSTRE_MDC_NAME)) { - /* - * adjust max_mod_rpcs_in_flight to ensure it is always - * strictly lower that max_rpcs_in_flight - */ - if (max < 2) { - CERROR("%s: cannot set max_rpcs_in_flight to 1 because it must be higher than max_mod_rpcs_in_flight value\n", - cli->cl_import->imp_obd->obd_name); - return -ERANGE; - } - if (max <= cli->cl_max_mod_rpcs_in_flight) { - rc = obd_set_max_mod_rpcs_in_flight(cli, max - 1); - if (rc) - return rc; - } - } - - spin_lock(&cli->cl_loi_list_lock); - old = cli->cl_max_rpcs_in_flight; - cli->cl_max_rpcs_in_flight = max; - diff = max - old; - - /* We increase the max_rpcs_in_flight, then wakeup some waiters. */ - for (i = 0; i < diff; i++) { - if (list_empty(&cli->cl_loi_read_list)) - break; - - orsw = list_entry(cli->cl_loi_read_list.next, - struct obd_request_slot_waiter, orsw_entry); - list_del_init(&orsw->orsw_entry); - cli->cl_r_in_flight++; - wake_up(&orsw->orsw_waitq); - } - spin_unlock(&cli->cl_loi_list_lock); - - return 0; -} -EXPORT_SYMBOL(obd_set_max_rpcs_in_flight); - -int obd_set_max_mod_rpcs_in_flight(struct client_obd *cli, __u16 max) -{ - struct obd_connect_data *ocd; - u16 maxmodrpcs; - u16 prev; - - if (max > OBD_MAX_RIF_MAX || max < 1) - return -ERANGE; - - /* cannot exceed or equal max_rpcs_in_flight */ - if (max >= cli->cl_max_rpcs_in_flight) { - CERROR("%s: can't set max_mod_rpcs_in_flight to a value (%hu) higher or equal to max_rpcs_in_flight value (%u)\n", - cli->cl_import->imp_obd->obd_name, - max, cli->cl_max_rpcs_in_flight); - return -ERANGE; - } - - /* cannot exceed max modify RPCs in flight supported by the server */ - ocd = &cli->cl_import->imp_connect_data; - if (ocd->ocd_connect_flags & OBD_CONNECT_MULTIMODRPCS) - maxmodrpcs = ocd->ocd_maxmodrpcs; - else - maxmodrpcs = 1; - if (max > maxmodrpcs) { - CERROR("%s: can't set max_mod_rpcs_in_flight to a value (%hu) higher than max_mod_rpcs_per_client value (%hu) returned by the server at connection\n", - cli->cl_import->imp_obd->obd_name, - max, maxmodrpcs); - return -ERANGE; - } - - spin_lock(&cli->cl_mod_rpcs_lock); - - prev = cli->cl_max_mod_rpcs_in_flight; - cli->cl_max_mod_rpcs_in_flight = max; - - /* wakeup waiters if limit has been increased */ - if (cli->cl_max_mod_rpcs_in_flight > prev) - wake_up(&cli->cl_mod_rpcs_waitq); - - spin_unlock(&cli->cl_mod_rpcs_lock); - - return 0; -} -EXPORT_SYMBOL(obd_set_max_mod_rpcs_in_flight); - -#define pct(a, b) (b ? (a * 100) / b : 0) - -int obd_mod_rpc_stats_seq_show(struct client_obd *cli, struct seq_file *seq) -{ - unsigned long mod_tot = 0, mod_cum; - struct timespec64 now; - int i; - - ktime_get_real_ts64(&now); - - spin_lock(&cli->cl_mod_rpcs_lock); - - seq_printf(seq, "snapshot_time: %llu.%9lu (secs.nsecs)\n", - (s64)now.tv_sec, (unsigned long)now.tv_nsec); - seq_printf(seq, "modify_RPCs_in_flight: %hu\n", - cli->cl_mod_rpcs_in_flight); - - seq_puts(seq, "\n\t\t\tmodify\n"); - seq_puts(seq, "rpcs in flight rpcs %% cum %%\n"); - - mod_tot = lprocfs_oh_sum(&cli->cl_mod_rpcs_hist); - - mod_cum = 0; - for (i = 0; i < OBD_HIST_MAX; i++) { - unsigned long mod = cli->cl_mod_rpcs_hist.oh_buckets[i]; - - mod_cum += mod; - seq_printf(seq, "%d:\t\t%10lu %3lu %3lu\n", - i, mod, pct(mod, mod_tot), - pct(mod_cum, mod_tot)); - if (mod_cum == mod_tot) - break; - } - - spin_unlock(&cli->cl_mod_rpcs_lock); - - return 0; -} -EXPORT_SYMBOL(obd_mod_rpc_stats_seq_show); -#undef pct - -/* - * The number of modify RPCs sent in parallel is limited - * because the server has a finite number of slots per client to - * store request result and ensure reply reconstruction when needed. - * On the client, this limit is stored in cl_max_mod_rpcs_in_flight - * that takes into account server limit and cl_max_rpcs_in_flight - * value. - * On the MDC client, to avoid a potential deadlock (see Bugzilla 3462), - * one close request is allowed above the maximum. - */ -static inline bool obd_mod_rpc_slot_avail_locked(struct client_obd *cli, - bool close_req) -{ - bool avail; - - /* A slot is available if - * - number of modify RPCs in flight is less than the max - * - it's a close RPC and no other close request is in flight - */ - avail = cli->cl_mod_rpcs_in_flight < cli->cl_max_mod_rpcs_in_flight || - (close_req && !cli->cl_close_rpcs_in_flight); - - return avail; -} - -static inline bool obd_mod_rpc_slot_avail(struct client_obd *cli, - bool close_req) -{ - bool avail; - - spin_lock(&cli->cl_mod_rpcs_lock); - avail = obd_mod_rpc_slot_avail_locked(cli, close_req); - spin_unlock(&cli->cl_mod_rpcs_lock); - return avail; -} - -/* Get a modify RPC slot from the obd client @cli according - * to the kind of operation @opc that is going to be sent - * and the intent @it of the operation if it applies. - * If the maximum number of modify RPCs in flight is reached - * the thread is put to sleep. - * Returns the tag to be set in the request message. Tag 0 - * is reserved for non-modifying requests. - */ -u16 obd_get_mod_rpc_slot(struct client_obd *cli, __u32 opc, - struct lookup_intent *it) -{ - bool close_req = false; - u16 i, max; - - /* read-only metadata RPCs don't consume a slot on MDT - * for reply reconstruction - */ - if (it && (it->it_op == IT_GETATTR || it->it_op == IT_LOOKUP || - it->it_op == IT_LAYOUT || it->it_op == IT_READDIR)) - return 0; - - if (opc == MDS_CLOSE) - close_req = true; - - do { - spin_lock(&cli->cl_mod_rpcs_lock); - max = cli->cl_max_mod_rpcs_in_flight; - if (obd_mod_rpc_slot_avail_locked(cli, close_req)) { - /* there is a slot available */ - cli->cl_mod_rpcs_in_flight++; - if (close_req) - cli->cl_close_rpcs_in_flight++; - lprocfs_oh_tally(&cli->cl_mod_rpcs_hist, - cli->cl_mod_rpcs_in_flight); - /* find a free tag */ - i = find_first_zero_bit(cli->cl_mod_tag_bitmap, - max + 1); - LASSERT(i < OBD_MAX_RIF_MAX); - LASSERT(!test_and_set_bit(i, cli->cl_mod_tag_bitmap)); - spin_unlock(&cli->cl_mod_rpcs_lock); - /* tag 0 is reserved for non-modify RPCs */ - return i + 1; - } - spin_unlock(&cli->cl_mod_rpcs_lock); - - CDEBUG(D_RPCTRACE, "%s: sleeping for a modify RPC slot opc %u, max %hu\n", - cli->cl_import->imp_obd->obd_name, opc, max); - - wait_event_idle(cli->cl_mod_rpcs_waitq, - obd_mod_rpc_slot_avail(cli, close_req)); - } while (true); -} -EXPORT_SYMBOL(obd_get_mod_rpc_slot); - -/* - * Put a modify RPC slot from the obd client @cli according - * to the kind of operation @opc that has been sent and the - * intent @it of the operation if it applies. - */ -void obd_put_mod_rpc_slot(struct client_obd *cli, u32 opc, - struct lookup_intent *it, u16 tag) -{ - bool close_req = false; - - if (it && (it->it_op == IT_GETATTR || it->it_op == IT_LOOKUP || - it->it_op == IT_LAYOUT || it->it_op == IT_READDIR)) - return; - - if (opc == MDS_CLOSE) - close_req = true; - - spin_lock(&cli->cl_mod_rpcs_lock); - cli->cl_mod_rpcs_in_flight--; - if (close_req) - cli->cl_close_rpcs_in_flight--; - /* release the tag in the bitmap */ - LASSERT(tag - 1 < OBD_MAX_RIF_MAX); - LASSERT(test_and_clear_bit(tag - 1, cli->cl_mod_tag_bitmap) != 0); - spin_unlock(&cli->cl_mod_rpcs_lock); - wake_up(&cli->cl_mod_rpcs_waitq); -} -EXPORT_SYMBOL(obd_put_mod_rpc_slot); diff --git a/drivers/staging/lustre/lustre/obdclass/kernelcomm.c b/drivers/staging/lustre/lustre/obdclass/kernelcomm.c deleted file mode 100644 index b9bf81607bbf..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/kernelcomm.c +++ /dev/null @@ -1,238 +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) 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * Author: Nathan Rutman <nathan.rutman@sun.com> - * - * Kernel <-> userspace communication routines. - * Using pipes for all arches. - */ - -#define DEBUG_SUBSYSTEM S_CLASS -#define D_KUC D_OTHER - -#include <obd_support.h> -#include <lustre_kernelcomm.h> - -/** - * libcfs_kkuc_msg_put - send an message from kernel to userspace - * @param fp to send the message to - * @param payload Payload data. First field of payload is always - * struct kuc_hdr - */ -int libcfs_kkuc_msg_put(struct file *filp, void *payload) -{ - struct kuc_hdr *kuch = (struct kuc_hdr *)payload; - ssize_t count = kuch->kuc_msglen; - loff_t offset = 0; - int rc = -ENXIO; - - if (IS_ERR_OR_NULL(filp)) - return -EBADF; - - if (kuch->kuc_magic != KUC_MAGIC) { - CERROR("KernelComm: bad magic %x\n", kuch->kuc_magic); - return rc; - } - - while (count > 0) { - rc = kernel_write(filp, payload, count, &offset); - if (rc < 0) - break; - count -= rc; - payload += rc; - rc = 0; - } - - if (rc < 0) - CWARN("message send failed (%d)\n", rc); - else - CDEBUG(D_KUC, "Sent message rc=%d, fp=%p\n", rc, filp); - - return rc; -} -EXPORT_SYMBOL(libcfs_kkuc_msg_put); - -/* - * Broadcast groups are global across all mounted filesystems; - * i.e. registering for a group on 1 fs will get messages for that - * group from any fs - */ -/** A single group registration has a uid and a file pointer */ -struct kkuc_reg { - struct list_head kr_chain; - int kr_uid; - struct file *kr_fp; - char kr_data[0]; -}; - -static struct list_head kkuc_groups[KUC_GRP_MAX + 1] = {}; -/* Protect message sending against remove and adds */ -static DECLARE_RWSEM(kg_sem); - -/** Add a receiver to a broadcast group - * @param filp pipe to write into - * @param uid identifier for this receiver - * @param group group number - * @param data user data - */ -int libcfs_kkuc_group_add(struct file *filp, int uid, unsigned int group, - void *data, size_t data_len) -{ - struct kkuc_reg *reg; - - if (group > KUC_GRP_MAX) { - CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group); - return -EINVAL; - } - - /* fput in group_rem */ - if (!filp) - return -EBADF; - - /* freed in group_rem */ - reg = kmalloc(sizeof(*reg) + data_len, 0); - if (!reg) - return -ENOMEM; - - reg->kr_fp = filp; - reg->kr_uid = uid; - memcpy(reg->kr_data, data, data_len); - - down_write(&kg_sem); - if (!kkuc_groups[group].next) - INIT_LIST_HEAD(&kkuc_groups[group]); - list_add(®->kr_chain, &kkuc_groups[group]); - up_write(&kg_sem); - - CDEBUG(D_KUC, "Added uid=%d fp=%p to group %d\n", uid, filp, group); - - return 0; -} -EXPORT_SYMBOL(libcfs_kkuc_group_add); - -int libcfs_kkuc_group_rem(int uid, unsigned int group) -{ - struct kkuc_reg *reg, *next; - - if (!kkuc_groups[group].next) - return 0; - - if (!uid) { - /* Broadcast a shutdown message */ - struct kuc_hdr lh; - - lh.kuc_magic = KUC_MAGIC; - lh.kuc_transport = KUC_TRANSPORT_GENERIC; - lh.kuc_msgtype = KUC_MSG_SHUTDOWN; - lh.kuc_msglen = sizeof(lh); - libcfs_kkuc_group_put(group, &lh); - } - - down_write(&kg_sem); - list_for_each_entry_safe(reg, next, &kkuc_groups[group], kr_chain) { - if (!uid || (uid == reg->kr_uid)) { - list_del(®->kr_chain); - CDEBUG(D_KUC, "Removed uid=%d fp=%p from group %d\n", - reg->kr_uid, reg->kr_fp, group); - if (reg->kr_fp) - fput(reg->kr_fp); - kfree(reg); - } - } - up_write(&kg_sem); - - return 0; -} -EXPORT_SYMBOL(libcfs_kkuc_group_rem); - -int libcfs_kkuc_group_put(unsigned int group, void *payload) -{ - struct kkuc_reg *reg; - int rc = 0; - int one_success = 0; - - down_write(&kg_sem); - list_for_each_entry(reg, &kkuc_groups[group], kr_chain) { - if (reg->kr_fp) { - rc = libcfs_kkuc_msg_put(reg->kr_fp, payload); - if (!rc) { - one_success = 1; - } else if (rc == -EPIPE) { - fput(reg->kr_fp); - reg->kr_fp = NULL; - } - } - } - up_write(&kg_sem); - - /* - * don't return an error if the message has been delivered - * at least to one agent - */ - if (one_success) - rc = 0; - - return rc; -} -EXPORT_SYMBOL(libcfs_kkuc_group_put); - -/** - * Calls a callback function for each link of the given kuc group. - * @param group the group to call the function on. - * @param cb_func the function to be called. - * @param cb_arg extra argument to be passed to the callback function. - */ -int libcfs_kkuc_group_foreach(unsigned int group, libcfs_kkuc_cb_t cb_func, - void *cb_arg) -{ - struct kkuc_reg *reg; - int rc = 0; - - if (group > KUC_GRP_MAX) { - CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group); - return -EINVAL; - } - - /* no link for this group */ - if (!kkuc_groups[group].next) - return 0; - - down_read(&kg_sem); - list_for_each_entry(reg, &kkuc_groups[group], kr_chain) { - if (reg->kr_fp) - rc = cb_func(reg->kr_data, cb_arg); - } - up_read(&kg_sem); - - return rc; -} -EXPORT_SYMBOL(libcfs_kkuc_group_foreach); diff --git a/drivers/staging/lustre/lustre/obdclass/linkea.c b/drivers/staging/lustre/lustre/obdclass/linkea.c deleted file mode 100644 index 74c99ee216bb..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/linkea.c +++ /dev/null @@ -1,249 +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) 2013, 2014, Intel Corporation. - * Use is subject to license terms. - * - * Author: Di Wang <di.wang@intel.com> - */ - -#include <uapi/linux/lustre/lustre_idl.h> -#include <obd.h> -#include <lustre_linkea.h> - -int linkea_data_new(struct linkea_data *ldata, struct lu_buf *buf) -{ - buf->lb_buf = kzalloc(PAGE_SIZE, GFP_NOFS); - if (!buf->lb_buf) - return -ENOMEM; - buf->lb_len = PAGE_SIZE; - ldata->ld_buf = buf; - ldata->ld_leh = ldata->ld_buf->lb_buf; - ldata->ld_leh->leh_magic = LINK_EA_MAGIC; - ldata->ld_leh->leh_len = sizeof(struct link_ea_header); - ldata->ld_leh->leh_reccount = 0; - ldata->ld_leh->leh_overflow_time = 0; - ldata->ld_leh->leh_padding = 0; - return 0; -} -EXPORT_SYMBOL(linkea_data_new); - -int linkea_init(struct linkea_data *ldata) -{ - struct link_ea_header *leh; - - LASSERT(ldata->ld_buf); - leh = ldata->ld_buf->lb_buf; - if (leh->leh_magic == __swab32(LINK_EA_MAGIC)) { - leh->leh_magic = LINK_EA_MAGIC; - leh->leh_reccount = __swab32(leh->leh_reccount); - leh->leh_len = __swab64(leh->leh_len); - leh->leh_overflow_time = __swab32(leh->leh_overflow_time); - leh->leh_padding = __swab32(leh->leh_padding); - /* individual entries are swabbed by linkea_entry_unpack() */ - } - - if (leh->leh_magic != LINK_EA_MAGIC) - return -EINVAL; - - if (leh->leh_reccount == 0 && leh->leh_overflow_time == 0) - return -ENODATA; - - ldata->ld_leh = leh; - return 0; -} -EXPORT_SYMBOL(linkea_init); - -int linkea_init_with_rec(struct linkea_data *ldata) -{ - int rc; - - rc = linkea_init(ldata); - if (!rc && ldata->ld_leh->leh_reccount == 0) - rc = -ENODATA; - - return rc; -} -EXPORT_SYMBOL(linkea_init_with_rec); - -/** - * Pack a link_ea_entry. - * All elements are stored as chars to avoid alignment issues. - * Numbers are always big-endian - * \retval record length - */ -int linkea_entry_pack(struct link_ea_entry *lee, const struct lu_name *lname, - const struct lu_fid *pfid) -{ - struct lu_fid tmpfid; - int reclen; - - tmpfid = *pfid; - if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_LINKEA_CRASH)) - tmpfid.f_ver = ~0; - fid_cpu_to_be(&tmpfid, &tmpfid); - memcpy(&lee->lee_parent_fid, &tmpfid, sizeof(tmpfid)); - memcpy(lee->lee_name, lname->ln_name, lname->ln_namelen); - reclen = sizeof(struct link_ea_entry) + lname->ln_namelen; - - lee->lee_reclen[0] = (reclen >> 8) & 0xff; - lee->lee_reclen[1] = reclen & 0xff; - return reclen; -} -EXPORT_SYMBOL(linkea_entry_pack); - -void linkea_entry_unpack(const struct link_ea_entry *lee, int *reclen, - struct lu_name *lname, struct lu_fid *pfid) -{ - LASSERT(lee); - - *reclen = (lee->lee_reclen[0] << 8) | lee->lee_reclen[1]; - memcpy(pfid, &lee->lee_parent_fid, sizeof(*pfid)); - fid_be_to_cpu(pfid, pfid); - if (lname) { - lname->ln_name = lee->lee_name; - lname->ln_namelen = *reclen - sizeof(struct link_ea_entry); - } -} -EXPORT_SYMBOL(linkea_entry_unpack); - -/** - * Add a record to the end of link ea buf - **/ -int linkea_add_buf(struct linkea_data *ldata, const struct lu_name *lname, - const struct lu_fid *pfid) -{ - struct link_ea_header *leh = ldata->ld_leh; - int reclen; - - LASSERT(leh); - - if (!lname || !pfid) - return -EINVAL; - - reclen = lname->ln_namelen + sizeof(struct link_ea_entry); - if (unlikely(leh->leh_len + reclen > MAX_LINKEA_SIZE)) { - /* - * Use 32-bits to save the overflow time, although it will - * shrink the ktime_get_real_seconds() returned 64-bits value - * to 32-bits value, it is still quite large and can be used - * for about 140 years. That is enough. - */ - leh->leh_overflow_time = ktime_get_real_seconds(); - if (unlikely(leh->leh_overflow_time == 0)) - leh->leh_overflow_time++; - - CDEBUG(D_INODE, "No enough space to hold linkea entry '" DFID ": %.*s' at %u\n", - PFID(pfid), lname->ln_namelen, - lname->ln_name, leh->leh_overflow_time); - return 0; - } - - if (leh->leh_len + reclen > ldata->ld_buf->lb_len) { - /* Note: this never happens as MAX_LINKEA_SIZE is 4096, while - * the initial allocation is PAGE_SIZE. - */ - void *b = krealloc(ldata->ld_buf->lb_buf, leh->leh_len + reclen, GFP_NOFS); - if (!b) - return -ENOMEM; - - ldata->ld_buf->lb_len = leh->leh_len + reclen; - leh = ldata->ld_leh = ldata->ld_buf->lb_buf = b; - } - - ldata->ld_lee = ldata->ld_buf->lb_buf + leh->leh_len; - ldata->ld_reclen = linkea_entry_pack(ldata->ld_lee, lname, pfid); - leh->leh_len += ldata->ld_reclen; - leh->leh_reccount++; - CDEBUG(D_INODE, "New link_ea name '" DFID ":%.*s' is added\n", - PFID(pfid), lname->ln_namelen, lname->ln_name); - return 0; -} -EXPORT_SYMBOL(linkea_add_buf); - -/** Del the current record from the link ea buf */ -void linkea_del_buf(struct linkea_data *ldata, const struct lu_name *lname) -{ - LASSERT(ldata->ld_leh && ldata->ld_lee); - LASSERT(ldata->ld_leh->leh_reccount > 0); - - ldata->ld_leh->leh_reccount--; - ldata->ld_leh->leh_len -= ldata->ld_reclen; - memmove(ldata->ld_lee, (char *)ldata->ld_lee + ldata->ld_reclen, - (char *)ldata->ld_leh + ldata->ld_leh->leh_len - - (char *)ldata->ld_lee); - CDEBUG(D_INODE, "Old link_ea name '%.*s' is removed\n", - lname->ln_namelen, lname->ln_name); - - if ((char *)ldata->ld_lee >= ((char *)ldata->ld_leh + - ldata->ld_leh->leh_len)) - ldata->ld_lee = NULL; -} -EXPORT_SYMBOL(linkea_del_buf); - -/** - * Check if such a link exists in linkEA. - * - * \param ldata link data the search to be done on - * \param lname name in the parent's directory entry pointing to this object - * \param pfid parent fid the link to be found for - * - * \retval 0 success - * \retval -ENOENT link does not exist - * \retval -ve on error - */ -int linkea_links_find(struct linkea_data *ldata, const struct lu_name *lname, - const struct lu_fid *pfid) -{ - struct lu_name tmpname; - struct lu_fid tmpfid; - int count; - - LASSERT(ldata->ld_leh); - - /* link #0, if leh_reccount == 0 we skip the loop and return -ENOENT */ - if (likely(ldata->ld_leh->leh_reccount > 0)) - ldata->ld_lee = (struct link_ea_entry *)(ldata->ld_leh + 1); - - for (count = 0; count < ldata->ld_leh->leh_reccount; count++) { - linkea_entry_unpack(ldata->ld_lee, &ldata->ld_reclen, - &tmpname, &tmpfid); - if (tmpname.ln_namelen == lname->ln_namelen && - lu_fid_eq(&tmpfid, pfid) && - (strncmp(tmpname.ln_name, lname->ln_name, - tmpname.ln_namelen) == 0)) - break; - ldata->ld_lee = (struct link_ea_entry *)((char *)ldata->ld_lee + - ldata->ld_reclen); - } - - if (count == ldata->ld_leh->leh_reccount) { - CDEBUG(D_INODE, "Old link_ea name '%.*s' not found\n", - lname->ln_namelen, lname->ln_name); - ldata->ld_lee = NULL; - ldata->ld_reclen = 0; - return -ENOENT; - } - return 0; -} -EXPORT_SYMBOL(linkea_links_find); diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c deleted file mode 100644 index 7bceee7f121e..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c +++ /dev/null @@ -1,531 +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) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2011, 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lustre/obdclass/linux/linux-module.c - * - * Object Devices Class Driver - * These are the only exported functions, they provide some generic - * infrastructure for managing object devices - */ - -#define DEBUG_SUBSYSTEM S_CLASS - -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/sched.h> -#include <linux/lp.h> -#include <linux/slab.h> -#include <linux/ioport.h> -#include <linux/fcntl.h> -#include <linux/delay.h> -#include <linux/skbuff.h> -#include <linux/fs.h> -#include <linux/poll.h> -#include <linux/list.h> -#include <linux/highmem.h> -#include <linux/io.h> -#include <asm/ioctls.h> -#include <linux/uaccess.h> -#include <linux/miscdevice.h> -#include <linux/seq_file.h> -#include <linux/kobject.h> - -#include <linux/libcfs/libcfs.h> -#include <uapi/linux/lnet/lnetctl.h> -#include <obd_support.h> -#include <obd_class.h> -#include <lprocfs_status.h> -#include <uapi/linux/lustre/lustre_ioctl.h> -#include <uapi/linux/lustre/lustre_ver.h> - -#define OBD_MAX_IOCTL_BUFFER 8192 - -static int obd_ioctl_is_invalid(struct obd_ioctl_data *data) -{ - if (data->ioc_len > BIT(30)) { - CERROR("OBD ioctl: ioc_len larger than 1<<30\n"); - return 1; - } - - if (data->ioc_inllen1 > BIT(30)) { - CERROR("OBD ioctl: ioc_inllen1 larger than 1<<30\n"); - return 1; - } - - if (data->ioc_inllen2 > BIT(30)) { - CERROR("OBD ioctl: ioc_inllen2 larger than 1<<30\n"); - return 1; - } - - if (data->ioc_inllen3 > BIT(30)) { - CERROR("OBD ioctl: ioc_inllen3 larger than 1<<30\n"); - return 1; - } - - if (data->ioc_inllen4 > BIT(30)) { - CERROR("OBD ioctl: ioc_inllen4 larger than 1<<30\n"); - return 1; - } - - if (data->ioc_inlbuf1 && data->ioc_inllen1 == 0) { - CERROR("OBD ioctl: inlbuf1 pointer but 0 length\n"); - return 1; - } - - if (data->ioc_inlbuf2 && data->ioc_inllen2 == 0) { - CERROR("OBD ioctl: inlbuf2 pointer but 0 length\n"); - return 1; - } - - if (data->ioc_inlbuf3 && data->ioc_inllen3 == 0) { - CERROR("OBD ioctl: inlbuf3 pointer but 0 length\n"); - return 1; - } - - if (data->ioc_inlbuf4 && data->ioc_inllen4 == 0) { - CERROR("OBD ioctl: inlbuf4 pointer but 0 length\n"); - return 1; - } - - if (data->ioc_pbuf1 && data->ioc_plen1 == 0) { - CERROR("OBD ioctl: pbuf1 pointer but 0 length\n"); - return 1; - } - - if (data->ioc_pbuf2 && data->ioc_plen2 == 0) { - CERROR("OBD ioctl: pbuf2 pointer but 0 length\n"); - return 1; - } - - if (!data->ioc_pbuf1 && data->ioc_plen1 != 0) { - CERROR("OBD ioctl: plen1 set but NULL pointer\n"); - return 1; - } - - if (!data->ioc_pbuf2 && data->ioc_plen2 != 0) { - CERROR("OBD ioctl: plen2 set but NULL pointer\n"); - return 1; - } - - if (obd_ioctl_packlen(data) > data->ioc_len) { - CERROR("OBD ioctl: packlen exceeds ioc_len (%d > %d)\n", - obd_ioctl_packlen(data), data->ioc_len); - return 1; - } - - return 0; -} - -/* buffer MUST be at least the size of obd_ioctl_hdr */ -int obd_ioctl_getdata(char **buf, int *len, void __user *arg) -{ - struct obd_ioctl_hdr hdr; - struct obd_ioctl_data *data; - int err; - int offset = 0; - - if (copy_from_user(&hdr, arg, sizeof(hdr))) - return -EFAULT; - - if (hdr.ioc_version != OBD_IOCTL_VERSION) { - CERROR("Version mismatch kernel (%x) vs application (%x)\n", - OBD_IOCTL_VERSION, hdr.ioc_version); - return -EINVAL; - } - - if (hdr.ioc_len > OBD_MAX_IOCTL_BUFFER) { - CERROR("User buffer len %d exceeds %d max buffer\n", - hdr.ioc_len, OBD_MAX_IOCTL_BUFFER); - return -EINVAL; - } - - if (hdr.ioc_len < sizeof(struct obd_ioctl_data)) { - CERROR("User buffer too small for ioctl (%d)\n", hdr.ioc_len); - return -EINVAL; - } - - /* When there are lots of processes calling vmalloc on multi-core - * system, the high lock contention will hurt performance badly, - * obdfilter-survey is an example, which relies on ioctl. So we'd - * better avoid vmalloc on ioctl path. LU-66 - */ - *buf = kvzalloc(hdr.ioc_len, GFP_KERNEL); - if (!*buf) { - CERROR("Cannot allocate control buffer of len %d\n", - hdr.ioc_len); - return -EINVAL; - } - *len = hdr.ioc_len; - data = (struct obd_ioctl_data *)*buf; - - if (copy_from_user(*buf, arg, hdr.ioc_len)) { - err = -EFAULT; - goto free_buf; - } - if (hdr.ioc_len != data->ioc_len) { - err = -EINVAL; - goto free_buf; - } - - if (obd_ioctl_is_invalid(data)) { - CERROR("ioctl not correctly formatted\n"); - err = -EINVAL; - goto free_buf; - } - - if (data->ioc_inllen1) { - data->ioc_inlbuf1 = &data->ioc_bulk[0]; - offset += cfs_size_round(data->ioc_inllen1); - } - - if (data->ioc_inllen2) { - data->ioc_inlbuf2 = &data->ioc_bulk[0] + offset; - offset += cfs_size_round(data->ioc_inllen2); - } - - if (data->ioc_inllen3) { - data->ioc_inlbuf3 = &data->ioc_bulk[0] + offset; - offset += cfs_size_round(data->ioc_inllen3); - } - - if (data->ioc_inllen4) - data->ioc_inlbuf4 = &data->ioc_bulk[0] + offset; - - return 0; - -free_buf: - kvfree(*buf); - return err; -} -EXPORT_SYMBOL(obd_ioctl_getdata); - -/* opening /dev/obd */ -static int obd_class_open(struct inode *inode, struct file *file) -{ - try_module_get(THIS_MODULE); - return 0; -} - -/* closing /dev/obd */ -static int obd_class_release(struct inode *inode, struct file *file) -{ - module_put(THIS_MODULE); - return 0; -} - -/* to control /dev/obd */ -static long obd_class_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - int err = 0; - - /* Allow non-root access for OBD_IOC_PING_TARGET - used by lfs check */ - if (!capable(CAP_SYS_ADMIN) && (cmd != OBD_IOC_PING_TARGET)) - return err = -EACCES; - if ((cmd & 0xffffff00) == ((int)'T') << 8) /* ignore all tty ioctls */ - return err = -ENOTTY; - - err = class_handle_ioctl(cmd, (unsigned long)arg); - - return err; -} - -/* declare character device */ -static const struct file_operations obd_psdev_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = obd_class_ioctl, /* unlocked_ioctl */ - .open = obd_class_open, /* open */ - .release = obd_class_release, /* release */ -}; - -/* modules setup */ -struct miscdevice obd_psdev = { - .minor = OBD_DEV_MINOR, - .name = OBD_DEV_NAME, - .fops = &obd_psdev_fops, -}; - -static ssize_t version_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - return sprintf(buf, "%s\n", LUSTRE_VERSION_STRING); -} - -static ssize_t pinger_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - return sprintf(buf, "%s\n", "on"); -} - -static ssize_t -health_check_show(struct kobject *kobj, struct attribute *attr, char *buf) -{ - bool healthy = true; - int i; - size_t len = 0; - - if (libcfs_catastrophe) - return sprintf(buf, "LBUG\n"); - - read_lock(&obd_dev_lock); - for (i = 0; i < class_devno_max(); i++) { - struct obd_device *obd; - - obd = class_num2obd(i); - if (!obd || !obd->obd_attached || !obd->obd_set_up) - continue; - - LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC); - if (obd->obd_stopping) - continue; - - class_incref(obd, __func__, current); - read_unlock(&obd_dev_lock); - - if (obd_health_check(NULL, obd)) - healthy = false; - class_decref(obd, __func__, current); - read_lock(&obd_dev_lock); - } - read_unlock(&obd_dev_lock); - - if (healthy) - len = sprintf(buf, "healthy\n"); - else - len = sprintf(buf, "NOT HEALTHY\n"); - - return len; -} - -static ssize_t jobid_var_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", obd_jobid_var); -} - -static ssize_t jobid_var_store(struct kobject *kobj, struct attribute *attr, - const char *buffer, - size_t count) -{ - if (!count || count > JOBSTATS_JOBID_VAR_MAX_LEN) - return -EINVAL; - - memset(obd_jobid_var, 0, JOBSTATS_JOBID_VAR_MAX_LEN + 1); - - memcpy(obd_jobid_var, buffer, count); - - /* Trim the trailing '\n' if any */ - if (obd_jobid_var[count - 1] == '\n') - obd_jobid_var[count - 1] = 0; - - return count; -} - -static ssize_t jobid_name_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", obd_jobid_node); -} - -static ssize_t jobid_name_store(struct kobject *kobj, struct attribute *attr, - const char *buffer, - size_t count) -{ - if (!count || count > LUSTRE_JOBID_SIZE) - return -EINVAL; - - memcpy(obd_jobid_node, buffer, count); - - obd_jobid_node[count] = 0; - - /* Trim the trailing '\n' if any */ - if (obd_jobid_node[count - 1] == '\n') - obd_jobid_node[count - 1] = 0; - - return count; -} - -/* Root for /sys/kernel/debug/lustre */ -struct dentry *debugfs_lustre_root; -EXPORT_SYMBOL_GPL(debugfs_lustre_root); - -LUSTRE_RO_ATTR(version); -LUSTRE_RO_ATTR(pinger); -LUSTRE_RO_ATTR(health_check); -LUSTRE_RW_ATTR(jobid_var); -LUSTRE_RW_ATTR(jobid_name); - -static struct attribute *lustre_attrs[] = { - &lustre_attr_version.attr, - &lustre_attr_pinger.attr, - &lustre_attr_health_check.attr, - &lustre_attr_jobid_name.attr, - &lustre_attr_jobid_var.attr, - NULL, -}; - -static void *obd_device_list_seq_start(struct seq_file *p, loff_t *pos) -{ - if (*pos >= class_devno_max()) - return NULL; - - return pos; -} - -static void obd_device_list_seq_stop(struct seq_file *p, void *v) -{ -} - -static void *obd_device_list_seq_next(struct seq_file *p, void *v, loff_t *pos) -{ - ++*pos; - if (*pos >= class_devno_max()) - return NULL; - - return pos; -} - -static int obd_device_list_seq_show(struct seq_file *p, void *v) -{ - loff_t index = *(loff_t *)v; - struct obd_device *obd = class_num2obd((int)index); - char *status; - - if (!obd) - return 0; - - LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC); - if (obd->obd_stopping) - status = "ST"; - else if (obd->obd_inactive) - status = "IN"; - else if (obd->obd_set_up) - status = "UP"; - else if (obd->obd_attached) - status = "AT"; - else - status = "--"; - - seq_printf(p, "%3d %s %s %s %s %d\n", - (int)index, status, obd->obd_type->typ_name, - obd->obd_name, obd->obd_uuid.uuid, - atomic_read(&obd->obd_refcount)); - return 0; -} - -static const struct seq_operations obd_device_list_sops = { - .start = obd_device_list_seq_start, - .stop = obd_device_list_seq_stop, - .next = obd_device_list_seq_next, - .show = obd_device_list_seq_show, -}; - -static int obd_device_list_open(struct inode *inode, struct file *file) -{ - struct seq_file *seq; - int rc = seq_open(file, &obd_device_list_sops); - - if (rc) - return rc; - - seq = file->private_data; - seq->private = inode->i_private; - - return 0; -} - -static const struct file_operations obd_device_list_fops = { - .owner = THIS_MODULE, - .open = obd_device_list_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -struct kobject *lustre_kobj; -EXPORT_SYMBOL_GPL(lustre_kobj); - -static const struct attribute_group lustre_attr_group = { - .attrs = lustre_attrs, -}; - -int class_procfs_init(void) -{ - int rc = -ENOMEM; - struct dentry *file; - - lustre_kobj = kobject_create_and_add("lustre", fs_kobj); - if (!lustre_kobj) - goto out; - - /* Create the files associated with this kobject */ - rc = sysfs_create_group(lustre_kobj, &lustre_attr_group); - if (rc) { - kobject_put(lustre_kobj); - goto out; - } - - debugfs_lustre_root = debugfs_create_dir("lustre", NULL); - if (IS_ERR_OR_NULL(debugfs_lustre_root)) { - rc = debugfs_lustre_root ? PTR_ERR(debugfs_lustre_root) - : -ENOMEM; - debugfs_lustre_root = NULL; - sysfs_remove_group(lustre_kobj, &lustre_attr_group); - kobject_put(lustre_kobj); - goto out; - } - - file = debugfs_create_file("devices", 0444, debugfs_lustre_root, NULL, - &obd_device_list_fops); - if (IS_ERR_OR_NULL(file)) { - rc = file ? PTR_ERR(file) : -ENOMEM; - sysfs_remove_group(lustre_kobj, &lustre_attr_group); - kobject_put(lustre_kobj); - goto out; - } -out: - return rc; -} - -int class_procfs_clean(void) -{ - debugfs_remove_recursive(debugfs_lustre_root); - - debugfs_lustre_root = NULL; - - sysfs_remove_group(lustre_kobj, &lustre_attr_group); - kobject_put(lustre_kobj); - - return 0; -} diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c deleted file mode 100644 index e5e8687784ee..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c +++ /dev/null @@ -1,162 +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) 1999, 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. - */ - -#include <linux/module.h> -#include <linux/sysctl.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/stat.h> -#include <linux/ctype.h> -#include <linux/bitops.h> -#include <linux/uaccess.h> -#include <linux/utsname.h> - -#define DEBUG_SUBSYSTEM S_CLASS - -#include <obd_support.h> -#include <lprocfs_status.h> -#include <obd_class.h> - -struct static_lustre_uintvalue_attr { - struct { - struct attribute attr; - ssize_t (*show)(struct kobject *kobj, struct attribute *attr, - char *buf); - ssize_t (*store)(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t len); - } u; - int *value; -}; - -static ssize_t static_uintvalue_show(struct kobject *kobj, - struct attribute *attr, - char *buf) -{ - struct static_lustre_uintvalue_attr *lattr = (void *)attr; - - return sprintf(buf, "%d\n", *lattr->value); -} - -static ssize_t static_uintvalue_store(struct kobject *kobj, - struct attribute *attr, - const char *buffer, size_t count) -{ - struct static_lustre_uintvalue_attr *lattr = (void *)attr; - int rc; - unsigned int val; - - rc = kstrtouint(buffer, 10, &val); - if (rc) - return rc; - - *lattr->value = val; - - return count; -} - -#define LUSTRE_STATIC_UINT_ATTR(name, value) \ -static struct static_lustre_uintvalue_attr lustre_sattr_##name = \ - {__ATTR(name, 0644, \ - static_uintvalue_show, \ - static_uintvalue_store),\ - value } - -LUSTRE_STATIC_UINT_ATTR(timeout, &obd_timeout); - -static ssize_t max_dirty_mb_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - return sprintf(buf, "%lu\n", - obd_max_dirty_pages / (1 << (20 - PAGE_SHIFT))); -} - -static ssize_t max_dirty_mb_store(struct kobject *kobj, struct attribute *attr, - const char *buffer, size_t count) -{ - int rc; - unsigned long val; - - rc = kstrtoul(buffer, 10, &val); - if (rc) - return rc; - - val *= 1 << (20 - PAGE_SHIFT); /* convert to pages */ - - if (val > ((totalram_pages / 10) * 9)) { - /* Somebody wants to assign too much memory to dirty pages */ - return -EINVAL; - } - - if (val < 4 << (20 - PAGE_SHIFT)) { - /* Less than 4 Mb for dirty cache is also bad */ - return -EINVAL; - } - - obd_max_dirty_pages = val; - - return count; -} -LUSTRE_RW_ATTR(max_dirty_mb); - -LUSTRE_STATIC_UINT_ATTR(debug_peer_on_timeout, &obd_debug_peer_on_timeout); -LUSTRE_STATIC_UINT_ATTR(dump_on_timeout, &obd_dump_on_timeout); -LUSTRE_STATIC_UINT_ATTR(dump_on_eviction, &obd_dump_on_eviction); -LUSTRE_STATIC_UINT_ATTR(at_min, &at_min); -LUSTRE_STATIC_UINT_ATTR(at_max, &at_max); -LUSTRE_STATIC_UINT_ATTR(at_extra, &at_extra); -LUSTRE_STATIC_UINT_ATTR(at_early_margin, &at_early_margin); -LUSTRE_STATIC_UINT_ATTR(at_history, &at_history); - -static struct attribute *lustre_attrs[] = { - &lustre_sattr_timeout.u.attr, - &lustre_attr_max_dirty_mb.attr, - &lustre_sattr_debug_peer_on_timeout.u.attr, - &lustre_sattr_dump_on_timeout.u.attr, - &lustre_sattr_dump_on_eviction.u.attr, - &lustre_sattr_at_min.u.attr, - &lustre_sattr_at_max.u.attr, - &lustre_sattr_at_extra.u.attr, - &lustre_sattr_at_early_margin.u.attr, - &lustre_sattr_at_history.u.attr, - NULL, -}; - -static const struct attribute_group lustre_attr_group = { - .attrs = lustre_attrs, -}; - -int obd_sysctl_init(void) -{ - return sysfs_create_group(lustre_kobj, &lustre_attr_group); -} diff --git a/drivers/staging/lustre/lustre/obdclass/llog.c b/drivers/staging/lustre/lustre/obdclass/llog.c deleted file mode 100644 index 693e1129f1f9..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/llog.c +++ /dev/null @@ -1,523 +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) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, 2015, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lustre/obdclass/llog.c - * - * OST<->MDS recovery logging infrastructure. - * Invariants in implementation: - * - we do not share logs among different OST<->MDS connections, so that - * if an OST or MDS fails it need only look at log(s) relevant to itself - * - * Author: Andreas Dilger <adilger@clusterfs.com> - * Author: Alex Zhuravlev <bzzz@whamcloud.com> - * Author: Mikhail Pershin <tappro@whamcloud.com> - */ - -#define DEBUG_SUBSYSTEM S_LOG - -#include <llog_swab.h> -#include <lustre_log.h> -#include <obd_class.h> -#include "llog_internal.h" - -/* - * Allocate a new log or catalog handle - * Used inside llog_open(). - */ -static struct llog_handle *llog_alloc_handle(void) -{ - struct llog_handle *loghandle; - - loghandle = kzalloc(sizeof(*loghandle), GFP_NOFS); - if (!loghandle) - return NULL; - - init_rwsem(&loghandle->lgh_lock); - spin_lock_init(&loghandle->lgh_hdr_lock); - INIT_LIST_HEAD(&loghandle->u.phd.phd_entry); - atomic_set(&loghandle->lgh_refcount, 1); - - return loghandle; -} - -/* - * Free llog handle and header data if exists. Used in llog_close() only - */ -static void llog_free_handle(struct llog_handle *loghandle) -{ - /* failed llog_init_handle */ - if (!loghandle->lgh_hdr) - goto out; - - if (loghandle->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN) - LASSERT(list_empty(&loghandle->u.phd.phd_entry)); - else if (loghandle->lgh_hdr->llh_flags & LLOG_F_IS_CAT) - LASSERT(list_empty(&loghandle->u.chd.chd_head)); - kvfree(loghandle->lgh_hdr); -out: - kfree(loghandle); -} - -void llog_handle_get(struct llog_handle *loghandle) -{ - atomic_inc(&loghandle->lgh_refcount); -} - -void llog_handle_put(struct llog_handle *loghandle) -{ - LASSERT(atomic_read(&loghandle->lgh_refcount) > 0); - if (atomic_dec_and_test(&loghandle->lgh_refcount)) - llog_free_handle(loghandle); -} - -static int llog_read_header(const struct lu_env *env, - struct llog_handle *handle, - struct obd_uuid *uuid) -{ - struct llog_operations *lop; - int rc; - - rc = llog_handle2ops(handle, &lop); - if (rc) - return rc; - - if (!lop->lop_read_header) - return -EOPNOTSUPP; - - rc = lop->lop_read_header(env, handle); - if (rc == LLOG_EEMPTY) { - struct llog_log_hdr *llh = handle->lgh_hdr; - size_t len; - - /* lrh_len should be initialized in llog_init_handle */ - handle->lgh_last_idx = 0; /* header is record with index 0 */ - llh->llh_count = 1; /* for the header record */ - llh->llh_hdr.lrh_type = LLOG_HDR_MAGIC; - LASSERT(handle->lgh_ctxt->loc_chunk_size >= LLOG_MIN_CHUNK_SIZE); - llh->llh_hdr.lrh_len = handle->lgh_ctxt->loc_chunk_size; - llh->llh_hdr.lrh_index = 0; - llh->llh_timestamp = ktime_get_real_seconds(); - if (uuid) - memcpy(&llh->llh_tgtuuid, uuid, - sizeof(llh->llh_tgtuuid)); - llh->llh_bitmap_offset = offsetof(typeof(*llh), llh_bitmap); - /* - * Since update llog header might also call this function, - * let's reset the bitmap to 0 here - */ - len = llh->llh_hdr.lrh_len - llh->llh_bitmap_offset; - memset(LLOG_HDR_BITMAP(llh), 0, len - sizeof(llh->llh_tail)); - ext2_set_bit(0, LLOG_HDR_BITMAP(llh)); - LLOG_HDR_TAIL(llh)->lrt_len = llh->llh_hdr.lrh_len; - LLOG_HDR_TAIL(llh)->lrt_index = llh->llh_hdr.lrh_index; - rc = 0; - } - return rc; -} - -int llog_init_handle(const struct lu_env *env, struct llog_handle *handle, - int flags, struct obd_uuid *uuid) -{ - int chunk_size = handle->lgh_ctxt->loc_chunk_size; - enum llog_flag fmt = flags & LLOG_F_EXT_MASK; - struct llog_log_hdr *llh; - int rc; - - LASSERT(!handle->lgh_hdr); - - LASSERT(chunk_size >= LLOG_MIN_CHUNK_SIZE); - llh = kvzalloc(sizeof(*llh), GFP_KERNEL); - if (!llh) - return -ENOMEM; - handle->lgh_hdr = llh; - handle->lgh_hdr_size = chunk_size; - /* first assign flags to use llog_client_ops */ - llh->llh_flags = flags; - rc = llog_read_header(env, handle, uuid); - if (rc == 0) { - if (unlikely((llh->llh_flags & LLOG_F_IS_PLAIN && - flags & LLOG_F_IS_CAT) || - (llh->llh_flags & LLOG_F_IS_CAT && - flags & LLOG_F_IS_PLAIN))) { - CERROR("%s: llog type is %s but initializing %s\n", - handle->lgh_ctxt->loc_obd->obd_name, - llh->llh_flags & LLOG_F_IS_CAT ? - "catalog" : "plain", - flags & LLOG_F_IS_CAT ? "catalog" : "plain"); - rc = -EINVAL; - goto out; - } else if (llh->llh_flags & - (LLOG_F_IS_PLAIN | LLOG_F_IS_CAT)) { - /* - * it is possible to open llog without specifying llog - * type so it is taken from llh_flags - */ - flags = llh->llh_flags; - } else { - /* for some reason the llh_flags has no type set */ - CERROR("llog type is not specified!\n"); - rc = -EINVAL; - goto out; - } - if (unlikely(uuid && - !obd_uuid_equals(uuid, &llh->llh_tgtuuid))) { - CERROR("%s: llog uuid mismatch: %s/%s\n", - handle->lgh_ctxt->loc_obd->obd_name, - (char *)uuid->uuid, - (char *)llh->llh_tgtuuid.uuid); - rc = -EEXIST; - goto out; - } - } - if (flags & LLOG_F_IS_CAT) { - LASSERT(list_empty(&handle->u.chd.chd_head)); - INIT_LIST_HEAD(&handle->u.chd.chd_head); - llh->llh_size = sizeof(struct llog_logid_rec); - llh->llh_flags |= LLOG_F_IS_FIXSIZE; - } else if (!(flags & LLOG_F_IS_PLAIN)) { - CERROR("%s: unknown flags: %#x (expected %#x or %#x)\n", - handle->lgh_ctxt->loc_obd->obd_name, - flags, LLOG_F_IS_CAT, LLOG_F_IS_PLAIN); - rc = -EINVAL; - } - llh->llh_flags |= fmt; -out: - if (rc) { - kvfree(llh); - handle->lgh_hdr = NULL; - } - return rc; -} -EXPORT_SYMBOL(llog_init_handle); - -static int llog_process_thread(void *arg) -{ - struct llog_process_info *lpi = arg; - struct llog_handle *loghandle = lpi->lpi_loghandle; - struct llog_log_hdr *llh = loghandle->lgh_hdr; - struct llog_process_cat_data *cd = lpi->lpi_catdata; - char *buf; - u64 cur_offset, tmp_offset; - int chunk_size; - int rc = 0, index = 1, last_index; - int saved_index = 0; - int last_called_index = 0; - - if (!llh) - return -EINVAL; - - cur_offset = llh->llh_hdr.lrh_len; - chunk_size = llh->llh_hdr.lrh_len; - /* expect chunk_size to be power of two */ - LASSERT(is_power_of_2(chunk_size)); - - buf = kvzalloc(chunk_size, GFP_NOFS); - if (!buf) { - lpi->lpi_rc = -ENOMEM; - return 0; - } - - if (cd) { - last_called_index = cd->lpcd_first_idx; - index = cd->lpcd_first_idx + 1; - } - if (cd && cd->lpcd_last_idx) - last_index = cd->lpcd_last_idx; - else - last_index = LLOG_HDR_BITMAP_SIZE(llh) - 1; - - while (rc == 0) { - unsigned int buf_offset = 0; - struct llog_rec_hdr *rec; - bool partial_chunk; - off_t chunk_offset; - - /* skip records not set in bitmap */ - while (index <= last_index && - !ext2_test_bit(index, LLOG_HDR_BITMAP(llh))) - ++index; - - if (index > last_index) - break; - - CDEBUG(D_OTHER, "index: %d last_index %d\n", - index, last_index); -repeat: - /* get the buf with our target record; avoid old garbage */ - memset(buf, 0, chunk_size); - rc = llog_next_block(lpi->lpi_env, loghandle, &saved_index, - index, &cur_offset, buf, chunk_size); - if (rc) - goto out; - - /* - * NB: after llog_next_block() call the cur_offset is the - * offset of the next block after read one. - * The absolute offset of the current chunk is calculated - * from cur_offset value and stored in chunk_offset variable. - */ - tmp_offset = cur_offset; - if (do_div(tmp_offset, chunk_size)) { - partial_chunk = true; - chunk_offset = cur_offset & ~(chunk_size - 1); - } else { - partial_chunk = false; - chunk_offset = cur_offset - chunk_size; - } - - /* NB: when rec->lrh_len is accessed it is already swabbed - * since it is used at the "end" of the loop and the rec - * swabbing is done at the beginning of the loop. - */ - for (rec = (struct llog_rec_hdr *)(buf + buf_offset); - (char *)rec < buf + chunk_size; - rec = llog_rec_hdr_next(rec)) { - CDEBUG(D_OTHER, "processing rec 0x%p type %#x\n", - rec, rec->lrh_type); - - if (LLOG_REC_HDR_NEEDS_SWABBING(rec)) - lustre_swab_llog_rec(rec); - - CDEBUG(D_OTHER, "after swabbing, type=%#x idx=%d\n", - rec->lrh_type, rec->lrh_index); - - /* - * for partial chunk the end of it is zeroed, check - * for index 0 to distinguish it. - */ - if (partial_chunk && !rec->lrh_index) { - /* concurrent llog_add() might add new records - * while llog_processing, check this is not - * the case and re-read the current chunk - * otherwise. - */ - if (index > loghandle->lgh_last_idx) { - rc = 0; - goto out; - } - CDEBUG(D_OTHER, "Re-read last llog buffer for new records, index %u, last %u\n", - index, loghandle->lgh_last_idx); - /* save offset inside buffer for the re-read */ - buf_offset = (char *)rec - (char *)buf; - cur_offset = chunk_offset; - goto repeat; - } - - if (!rec->lrh_len || rec->lrh_len > chunk_size) { - CWARN("invalid length %d in llog record for index %d/%d\n", - rec->lrh_len, - rec->lrh_index, index); - rc = -EINVAL; - goto out; - } - - if (rec->lrh_index < index) { - CDEBUG(D_OTHER, "skipping lrh_index %d\n", - rec->lrh_index); - continue; - } - - if (rec->lrh_index != index) { - CERROR("%s: Invalid record: index %u but expected %u\n", - loghandle->lgh_ctxt->loc_obd->obd_name, - rec->lrh_index, index); - rc = -ERANGE; - goto out; - } - - CDEBUG(D_OTHER, - "lrh_index: %d lrh_len: %d (%d remains)\n", - rec->lrh_index, rec->lrh_len, - (int)(buf + chunk_size - (char *)rec)); - - loghandle->lgh_cur_idx = rec->lrh_index; - loghandle->lgh_cur_offset = (char *)rec - (char *)buf + - chunk_offset; - - /* if set, process the callback on this record */ - if (ext2_test_bit(index, LLOG_HDR_BITMAP(llh))) { - rc = lpi->lpi_cb(lpi->lpi_env, loghandle, rec, - lpi->lpi_cbdata); - last_called_index = index; - if (rc) - goto out; - } - - /* exit if the last index is reached */ - if (index >= last_index) { - rc = 0; - goto out; - } - index++; - } - } - -out: - if (cd) - cd->lpcd_last_idx = last_called_index; - - kfree(buf); - lpi->lpi_rc = rc; - return 0; -} - -static int llog_process_thread_daemonize(void *arg) -{ - struct llog_process_info *lpi = arg; - struct lu_env env; - int rc; - - unshare_fs_struct(); - - /* client env has no keys, tags is just 0 */ - rc = lu_env_init(&env, LCT_LOCAL | LCT_MG_THREAD); - if (rc) - goto out; - lpi->lpi_env = &env; - - rc = llog_process_thread(arg); - - lu_env_fini(&env); -out: - complete(&lpi->lpi_completion); - return rc; -} - -int llog_process_or_fork(const struct lu_env *env, - struct llog_handle *loghandle, - llog_cb_t cb, void *data, void *catdata, bool fork) -{ - struct llog_process_info *lpi; - int rc; - - lpi = kzalloc(sizeof(*lpi), GFP_NOFS); - if (!lpi) - return -ENOMEM; - lpi->lpi_loghandle = loghandle; - lpi->lpi_cb = cb; - lpi->lpi_cbdata = data; - lpi->lpi_catdata = catdata; - - if (fork) { - struct task_struct *task; - - /* The new thread can't use parent env, - * init the new one in llog_process_thread_daemonize. - */ - lpi->lpi_env = NULL; - init_completion(&lpi->lpi_completion); - task = kthread_run(llog_process_thread_daemonize, lpi, - "llog_process_thread"); - if (IS_ERR(task)) { - rc = PTR_ERR(task); - CERROR("%s: cannot start thread: rc = %d\n", - loghandle->lgh_ctxt->loc_obd->obd_name, rc); - goto out_lpi; - } - wait_for_completion(&lpi->lpi_completion); - } else { - lpi->lpi_env = env; - llog_process_thread(lpi); - } - rc = lpi->lpi_rc; -out_lpi: - kfree(lpi); - return rc; -} -EXPORT_SYMBOL(llog_process_or_fork); - -int llog_process(const struct lu_env *env, struct llog_handle *loghandle, - llog_cb_t cb, void *data, void *catdata) -{ - return llog_process_or_fork(env, loghandle, cb, data, catdata, true); -} -EXPORT_SYMBOL(llog_process); - -int llog_open(const struct lu_env *env, struct llog_ctxt *ctxt, - struct llog_handle **lgh, struct llog_logid *logid, - char *name, enum llog_open_param open_param) -{ - const struct cred *old_cred = NULL; - int rc; - - LASSERT(ctxt); - LASSERT(ctxt->loc_logops); - - if (!ctxt->loc_logops->lop_open) { - *lgh = NULL; - return -EOPNOTSUPP; - } - - *lgh = llog_alloc_handle(); - if (!*lgh) - return -ENOMEM; - (*lgh)->lgh_ctxt = ctxt; - (*lgh)->lgh_logops = ctxt->loc_logops; - - if (cap_raised(current_cap(), CAP_SYS_RESOURCE)) { - struct cred *cred = prepare_creds(); - - if (cred) { - cap_raise(cred->cap_effective, CAP_SYS_RESOURCE); - old_cred = override_creds(cred); - } - } - rc = ctxt->loc_logops->lop_open(env, *lgh, logid, name, open_param); - if (old_cred) - revert_creds(old_cred); - - if (rc) { - llog_free_handle(*lgh); - *lgh = NULL; - } - return rc; -} -EXPORT_SYMBOL(llog_open); - -int llog_close(const struct lu_env *env, struct llog_handle *loghandle) -{ - struct llog_operations *lop; - int rc; - - rc = llog_handle2ops(loghandle, &lop); - if (rc) - goto out; - if (!lop->lop_close) { - rc = -EOPNOTSUPP; - goto out; - } - rc = lop->lop_close(env, loghandle); -out: - llog_handle_put(loghandle); - return rc; -} -EXPORT_SYMBOL(llog_close); diff --git a/drivers/staging/lustre/lustre/obdclass/llog_cat.c b/drivers/staging/lustre/lustre/obdclass/llog_cat.c deleted file mode 100644 index d9c63adff206..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/llog_cat.c +++ /dev/null @@ -1,236 +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) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, 2015, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lustre/obdclass/llog_cat.c - * - * OST<->MDS recovery logging infrastructure. - * - * Invariants in implementation: - * - we do not share logs among different OST<->MDS connections, so that - * if an OST or MDS fails it need only look at log(s) relevant to itself - * - * Author: Andreas Dilger <adilger@clusterfs.com> - * Author: Alexey Zhuravlev <alexey.zhuravlev@intel.com> - * Author: Mikhail Pershin <mike.pershin@intel.com> - */ - -#define DEBUG_SUBSYSTEM S_LOG - -#include <obd_class.h> - -#include "llog_internal.h" - -/* Open an existent log handle and add it to the open list. - * This log handle will be closed when all of the records in it are removed. - * - * Assumes caller has already pushed us into the kernel context and is locking. - * We return a lock on the handle to ensure nobody yanks it from us. - * - * This takes extra reference on llog_handle via llog_handle_get() and require - * this reference to be put by caller using llog_handle_put() - */ -static int llog_cat_id2handle(const struct lu_env *env, - struct llog_handle *cathandle, - struct llog_handle **res, - struct llog_logid *logid) -{ - struct llog_handle *loghandle; - enum llog_flag fmt; - int rc = 0; - - if (!cathandle) - return -EBADF; - - fmt = cathandle->lgh_hdr->llh_flags & LLOG_F_EXT_MASK; - down_write(&cathandle->lgh_lock); - list_for_each_entry(loghandle, &cathandle->u.chd.chd_head, - u.phd.phd_entry) { - struct llog_logid *cgl = &loghandle->lgh_id; - - if (ostid_id(&cgl->lgl_oi) == ostid_id(&logid->lgl_oi) && - ostid_seq(&cgl->lgl_oi) == ostid_seq(&logid->lgl_oi)) { - if (cgl->lgl_ogen != logid->lgl_ogen) { - CERROR("%s: log " DOSTID " generation %x != %x\n", - loghandle->lgh_ctxt->loc_obd->obd_name, - POSTID(&logid->lgl_oi), cgl->lgl_ogen, - logid->lgl_ogen); - continue; - } - loghandle->u.phd.phd_cat_handle = cathandle; - up_write(&cathandle->lgh_lock); - rc = 0; - goto out; - } - } - up_write(&cathandle->lgh_lock); - - rc = llog_open(env, cathandle->lgh_ctxt, &loghandle, logid, NULL, - LLOG_OPEN_EXISTS); - if (rc < 0) { - CERROR("%s: error opening log id " DOSTID ":%x: rc = %d\n", - cathandle->lgh_ctxt->loc_obd->obd_name, - POSTID(&logid->lgl_oi), logid->lgl_ogen, rc); - return rc; - } - - rc = llog_init_handle(env, loghandle, fmt | LLOG_F_IS_PLAIN, NULL); - if (rc < 0) { - llog_close(env, loghandle); - loghandle = NULL; - return rc; - } - - down_write(&cathandle->lgh_lock); - list_add_tail(&loghandle->u.phd.phd_entry, &cathandle->u.chd.chd_head); - up_write(&cathandle->lgh_lock); - - loghandle->u.phd.phd_cat_handle = cathandle; - loghandle->u.phd.phd_cookie.lgc_lgl = cathandle->lgh_id; - loghandle->u.phd.phd_cookie.lgc_index = - loghandle->lgh_hdr->llh_cat_idx; -out: - llog_handle_get(loghandle); - *res = loghandle; - return 0; -} - -int llog_cat_close(const struct lu_env *env, struct llog_handle *cathandle) -{ - struct llog_handle *loghandle, *n; - - list_for_each_entry_safe(loghandle, n, &cathandle->u.chd.chd_head, - u.phd.phd_entry) { - /* unlink open-not-created llogs */ - list_del_init(&loghandle->u.phd.phd_entry); - llog_close(env, loghandle); - } - /* if handle was stored in ctxt, remove it too */ - if (cathandle->lgh_ctxt->loc_handle == cathandle) - cathandle->lgh_ctxt->loc_handle = NULL; - return llog_close(env, cathandle); -} -EXPORT_SYMBOL(llog_cat_close); - -static int llog_cat_process_cb(const struct lu_env *env, - struct llog_handle *cat_llh, - struct llog_rec_hdr *rec, void *data) -{ - struct llog_process_data *d = data; - struct llog_logid_rec *lir = (struct llog_logid_rec *)rec; - struct llog_handle *llh; - int rc; - - if (rec->lrh_type != LLOG_LOGID_MAGIC) { - CERROR("invalid record in catalog\n"); - return -EINVAL; - } - CDEBUG(D_HA, "processing log " DOSTID ":%x at index %u of catalog " - DOSTID "\n", POSTID(&lir->lid_id.lgl_oi), lir->lid_id.lgl_ogen, - rec->lrh_index, POSTID(&cat_llh->lgh_id.lgl_oi)); - - rc = llog_cat_id2handle(env, cat_llh, &llh, &lir->lid_id); - if (rc) { - CERROR("%s: cannot find handle for llog " DOSTID ": %d\n", - cat_llh->lgh_ctxt->loc_obd->obd_name, - POSTID(&lir->lid_id.lgl_oi), rc); - return rc; - } - - if (rec->lrh_index < d->lpd_startcat) - /* Skip processing of the logs until startcat */ - rc = 0; - else if (d->lpd_startidx > 0) { - struct llog_process_cat_data cd; - - cd.lpcd_first_idx = d->lpd_startidx; - cd.lpcd_last_idx = 0; - rc = llog_process_or_fork(env, llh, d->lpd_cb, d->lpd_data, - &cd, false); - /* Continue processing the next log from idx 0 */ - d->lpd_startidx = 0; - } else { - rc = llog_process_or_fork(env, llh, d->lpd_cb, d->lpd_data, - NULL, false); - } - - llog_handle_put(llh); - - return rc; -} - -static int llog_cat_process_or_fork(const struct lu_env *env, - struct llog_handle *cat_llh, - llog_cb_t cb, void *data, int startcat, - int startidx, bool fork) -{ - struct llog_process_data d; - struct llog_log_hdr *llh = cat_llh->lgh_hdr; - int rc; - - LASSERT(llh->llh_flags & LLOG_F_IS_CAT); - d.lpd_data = data; - d.lpd_cb = cb; - d.lpd_startcat = startcat; - d.lpd_startidx = startidx; - - if (llh->llh_cat_idx > cat_llh->lgh_last_idx) { - struct llog_process_cat_data cd; - - CWARN("catlog " DOSTID " crosses index zero\n", - POSTID(&cat_llh->lgh_id.lgl_oi)); - - cd.lpcd_first_idx = llh->llh_cat_idx; - cd.lpcd_last_idx = 0; - rc = llog_process_or_fork(env, cat_llh, llog_cat_process_cb, - &d, &cd, fork); - if (rc != 0) - return rc; - - cd.lpcd_first_idx = 0; - cd.lpcd_last_idx = cat_llh->lgh_last_idx; - rc = llog_process_or_fork(env, cat_llh, llog_cat_process_cb, - &d, &cd, fork); - } else { - rc = llog_process_or_fork(env, cat_llh, llog_cat_process_cb, - &d, NULL, fork); - } - - return rc; -} - -int llog_cat_process(const struct lu_env *env, struct llog_handle *cat_llh, - llog_cb_t cb, void *data, int startcat, int startidx) -{ - return llog_cat_process_or_fork(env, cat_llh, cb, data, startcat, - startidx, false); -} -EXPORT_SYMBOL(llog_cat_process); diff --git a/drivers/staging/lustre/lustre/obdclass/llog_internal.h b/drivers/staging/lustre/lustre/obdclass/llog_internal.h deleted file mode 100644 index 4991d4e589dc..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/llog_internal.h +++ /dev/null @@ -1,79 +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) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, 2015, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - */ - -#ifndef __LLOG_INTERNAL_H__ -#define __LLOG_INTERNAL_H__ - -#include <lustre_log.h> - -struct llog_process_info { - struct llog_handle *lpi_loghandle; - llog_cb_t lpi_cb; - void *lpi_cbdata; - void *lpi_catdata; - int lpi_rc; - struct completion lpi_completion; - const struct lu_env *lpi_env; - -}; - -struct llog_thread_info { - struct lu_attr lgi_attr; - struct lu_fid lgi_fid; - struct lu_buf lgi_buf; - loff_t lgi_off; - struct llog_rec_hdr lgi_lrh; - struct llog_rec_tail lgi_tail; -}; - -extern struct lu_context_key llog_thread_key; - -int llog_info_init(void); -void llog_info_fini(void); - -void llog_handle_get(struct llog_handle *loghandle); -void llog_handle_put(struct llog_handle *loghandle); -int class_config_dump_handler(const struct lu_env *env, - struct llog_handle *handle, - struct llog_rec_hdr *rec, void *data); -int llog_process_or_fork(const struct lu_env *env, - struct llog_handle *loghandle, - llog_cb_t cb, void *data, void *catdata, bool fork); -int llog_cat_cleanup(const struct lu_env *env, struct llog_handle *cathandle, - struct llog_handle *loghandle, int index); - -static inline struct llog_rec_hdr *llog_rec_hdr_next(struct llog_rec_hdr *rec) -{ - return (struct llog_rec_hdr *)((char *)rec + rec->lrh_len); -} -#endif diff --git a/drivers/staging/lustre/lustre/obdclass/llog_obd.c b/drivers/staging/lustre/lustre/obdclass/llog_obd.c deleted file mode 100644 index 26aea114a29b..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/llog_obd.c +++ /dev/null @@ -1,225 +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) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, 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_LOG - -#include <obd_class.h> -#include <lustre_log.h> -#include "llog_internal.h" - -/* helper functions for calling the llog obd methods */ -static struct llog_ctxt *llog_new_ctxt(struct obd_device *obd) -{ - struct llog_ctxt *ctxt; - - ctxt = kzalloc(sizeof(*ctxt), GFP_NOFS); - if (!ctxt) - return NULL; - - ctxt->loc_obd = obd; - atomic_set(&ctxt->loc_refcount, 1); - - return ctxt; -} - -static void llog_ctxt_destroy(struct llog_ctxt *ctxt) -{ - if (ctxt->loc_exp) { - class_export_put(ctxt->loc_exp); - ctxt->loc_exp = NULL; - } - if (ctxt->loc_imp) { - class_import_put(ctxt->loc_imp); - ctxt->loc_imp = NULL; - } - kfree(ctxt); -} - -int __llog_ctxt_put(const struct lu_env *env, struct llog_ctxt *ctxt) -{ - struct obd_llog_group *olg = ctxt->loc_olg; - struct obd_device *obd; - int rc = 0; - - spin_lock(&olg->olg_lock); - if (!atomic_dec_and_test(&ctxt->loc_refcount)) { - spin_unlock(&olg->olg_lock); - return rc; - } - olg->olg_ctxts[ctxt->loc_idx] = NULL; - spin_unlock(&olg->olg_lock); - - obd = ctxt->loc_obd; - spin_lock(&obd->obd_dev_lock); - /* sync with llog ctxt user thread */ - spin_unlock(&obd->obd_dev_lock); - - /* obd->obd_starting is needed for the case of cleanup - * in error case while obd is starting up. - */ - LASSERTF(obd->obd_starting == 1 || - obd->obd_stopping == 1 || obd->obd_set_up == 0, - "wrong obd state: %d/%d/%d\n", !!obd->obd_starting, - !!obd->obd_stopping, !!obd->obd_set_up); - - /* cleanup the llog ctxt here */ - if (CTXTP(ctxt, cleanup)) - rc = CTXTP(ctxt, cleanup)(env, ctxt); - - llog_ctxt_destroy(ctxt); - wake_up(&olg->olg_waitq); - return rc; -} -EXPORT_SYMBOL(__llog_ctxt_put); - -int llog_cleanup(const struct lu_env *env, struct llog_ctxt *ctxt) -{ - struct obd_llog_group *olg; - int rc, idx; - - olg = ctxt->loc_olg; - LASSERT(olg); - LASSERT(olg != LP_POISON); - - idx = ctxt->loc_idx; - - /* - * Banlance the ctxt get when calling llog_cleanup() - */ - LASSERT(atomic_read(&ctxt->loc_refcount) < LI_POISON); - LASSERT(atomic_read(&ctxt->loc_refcount) > 1); - llog_ctxt_put(ctxt); - - /* - * Try to free the ctxt. - */ - rc = __llog_ctxt_put(env, ctxt); - if (rc) - CERROR("Error %d while cleaning up ctxt %p\n", - rc, ctxt); - - l_wait_event_abortable(olg->olg_waitq, - llog_group_ctxt_null(olg, idx)); - - return rc; -} -EXPORT_SYMBOL(llog_cleanup); - -int llog_setup(const struct lu_env *env, struct obd_device *obd, - struct obd_llog_group *olg, int index, - struct obd_device *disk_obd, struct llog_operations *op) -{ - struct llog_ctxt *ctxt; - int rc = 0; - - if (index < 0 || index >= LLOG_MAX_CTXTS) - return -EINVAL; - - LASSERT(olg); - - ctxt = llog_new_ctxt(obd); - if (!ctxt) - return -ENOMEM; - - ctxt->loc_obd = obd; - ctxt->loc_olg = olg; - ctxt->loc_idx = index; - ctxt->loc_logops = op; - mutex_init(&ctxt->loc_mutex); - ctxt->loc_exp = class_export_get(disk_obd->obd_self_export); - ctxt->loc_flags = LLOG_CTXT_FLAG_UNINITIALIZED; - ctxt->loc_chunk_size = LLOG_MIN_CHUNK_SIZE; - - rc = llog_group_set_ctxt(olg, ctxt, index); - if (rc) { - llog_ctxt_destroy(ctxt); - if (rc == -EEXIST) { - ctxt = llog_group_get_ctxt(olg, index); - if (ctxt) { - /* - * mds_lov_update_desc() might call here multiple - * times. So if the llog is already set up then - * don't to do it again. - */ - CDEBUG(D_CONFIG, "obd %s ctxt %d already set up\n", - obd->obd_name, index); - LASSERT(ctxt->loc_olg == olg); - LASSERT(ctxt->loc_obd == obd); - LASSERT(ctxt->loc_exp == disk_obd->obd_self_export); - LASSERT(ctxt->loc_logops == op); - llog_ctxt_put(ctxt); - } - rc = 0; - } - return rc; - } - - if (op->lop_setup) { - if (OBD_FAIL_CHECK(OBD_FAIL_OBD_LLOG_SETUP)) - rc = -EOPNOTSUPP; - else - rc = op->lop_setup(env, obd, olg, index, disk_obd); - } - - if (rc) { - CERROR("%s: ctxt %d lop_setup=%p failed: rc = %d\n", - obd->obd_name, index, op->lop_setup, rc); - llog_group_clear_ctxt(olg, index); - llog_ctxt_destroy(ctxt); - } else { - CDEBUG(D_CONFIG, "obd %s ctxt %d is initialized\n", - obd->obd_name, index); - ctxt->loc_flags &= ~LLOG_CTXT_FLAG_UNINITIALIZED; - } - - return rc; -} -EXPORT_SYMBOL(llog_setup); - -/* context key constructor/destructor: llog_key_init, llog_key_fini */ -LU_KEY_INIT_FINI(llog, struct llog_thread_info); -/* context key: llog_thread_key */ -LU_CONTEXT_KEY_DEFINE(llog, LCT_MD_THREAD | LCT_MG_THREAD | LCT_LOCAL); -LU_KEY_INIT_GENERIC(llog); - -int llog_info_init(void) -{ - llog_key_init_generic(&llog_thread_key, NULL); - lu_context_key_register(&llog_thread_key); - return 0; -} - -void llog_info_fini(void) -{ - lu_context_key_degister(&llog_thread_key); -} diff --git a/drivers/staging/lustre/lustre/obdclass/llog_swab.c b/drivers/staging/lustre/lustre/obdclass/llog_swab.c deleted file mode 100644 index b431c3408fe4..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/llog_swab.c +++ /dev/null @@ -1,412 +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) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, 2015, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lustre/obdclass/llog_swab.c - * - * Swabbing of llog datatypes (from disk or over the wire). - * - * Author: jacob berkman <jacob@clusterfs.com> - */ - -#define DEBUG_SUBSYSTEM S_LOG - -#include <llog_swab.h> -#include <lustre_log.h> - -static void print_llogd_body(struct llogd_body *d) -{ - CDEBUG(D_OTHER, "llogd body: %p\n", d); - CDEBUG(D_OTHER, "\tlgd_logid.lgl_oi: " DOSTID "\n", - POSTID(&d->lgd_logid.lgl_oi)); - CDEBUG(D_OTHER, "\tlgd_logid.lgl_ogen: %#x\n", d->lgd_logid.lgl_ogen); - CDEBUG(D_OTHER, "\tlgd_ctxt_idx: %#x\n", d->lgd_ctxt_idx); - CDEBUG(D_OTHER, "\tlgd_llh_flags: %#x\n", d->lgd_llh_flags); - CDEBUG(D_OTHER, "\tlgd_index: %#x\n", d->lgd_index); - CDEBUG(D_OTHER, "\tlgd_saved_index: %#x\n", d->lgd_saved_index); - CDEBUG(D_OTHER, "\tlgd_len: %#x\n", d->lgd_len); - CDEBUG(D_OTHER, "\tlgd_cur_offset: %#llx\n", d->lgd_cur_offset); -} - -void lustre_swab_lu_fid(struct lu_fid *fid) -{ - __swab64s(&fid->f_seq); - __swab32s(&fid->f_oid); - __swab32s(&fid->f_ver); -} -EXPORT_SYMBOL(lustre_swab_lu_fid); - -void lustre_swab_ost_id(struct ost_id *oid) -{ - if (fid_seq_is_mdt0(oid->oi.oi_seq)) { - __swab64s(&oid->oi.oi_id); - __swab64s(&oid->oi.oi_seq); - } else { - lustre_swab_lu_fid(&oid->oi_fid); - } -} -EXPORT_SYMBOL(lustre_swab_ost_id); - -static void lustre_swab_llog_id(struct llog_logid *log_id) -{ - __swab64s(&log_id->lgl_oi.oi.oi_id); - __swab64s(&log_id->lgl_oi.oi.oi_seq); - __swab32s(&log_id->lgl_ogen); -} - -void lustre_swab_llogd_body(struct llogd_body *d) -{ - print_llogd_body(d); - lustre_swab_llog_id(&d->lgd_logid); - __swab32s(&d->lgd_ctxt_idx); - __swab32s(&d->lgd_llh_flags); - __swab32s(&d->lgd_index); - __swab32s(&d->lgd_saved_index); - __swab32s(&d->lgd_len); - __swab64s(&d->lgd_cur_offset); - print_llogd_body(d); -} -EXPORT_SYMBOL(lustre_swab_llogd_body); - -void lustre_swab_llogd_conn_body(struct llogd_conn_body *d) -{ - __swab64s(&d->lgdc_gen.mnt_cnt); - __swab64s(&d->lgdc_gen.conn_cnt); - lustre_swab_llog_id(&d->lgdc_logid); - __swab32s(&d->lgdc_ctxt_idx); -} -EXPORT_SYMBOL(lustre_swab_llogd_conn_body); - -static void lustre_swab_ll_fid(struct ll_fid *fid) -{ - __swab64s(&fid->id); - __swab32s(&fid->generation); - __swab32s(&fid->f_type); -} - -void lustre_swab_lu_seq_range(struct lu_seq_range *range) -{ - __swab64s(&range->lsr_start); - __swab64s(&range->lsr_end); - __swab32s(&range->lsr_index); - __swab32s(&range->lsr_flags); -} -EXPORT_SYMBOL(lustre_swab_lu_seq_range); - -void lustre_swab_llog_rec(struct llog_rec_hdr *rec) -{ - struct llog_rec_tail *tail = NULL; - - __swab32s(&rec->lrh_len); - __swab32s(&rec->lrh_index); - __swab32s(&rec->lrh_type); - __swab32s(&rec->lrh_id); - - switch (rec->lrh_type) { - case OST_SZ_REC: - { - struct llog_size_change_rec *lsc = - (struct llog_size_change_rec *)rec; - - lustre_swab_ll_fid(&lsc->lsc_fid); - __swab32s(&lsc->lsc_ioepoch); - tail = &lsc->lsc_tail; - break; - } - case MDS_UNLINK_REC: - { - struct llog_unlink_rec *lur = (struct llog_unlink_rec *)rec; - - __swab64s(&lur->lur_oid); - __swab32s(&lur->lur_oseq); - __swab32s(&lur->lur_count); - tail = &lur->lur_tail; - break; - } - case MDS_UNLINK64_REC: - { - struct llog_unlink64_rec *lur = - (struct llog_unlink64_rec *)rec; - - lustre_swab_lu_fid(&lur->lur_fid); - __swab32s(&lur->lur_count); - tail = &lur->lur_tail; - break; - } - case CHANGELOG_REC: - { - struct llog_changelog_rec *cr = - (struct llog_changelog_rec *)rec; - - __swab16s(&cr->cr.cr_namelen); - __swab16s(&cr->cr.cr_flags); - __swab32s(&cr->cr.cr_type); - __swab64s(&cr->cr.cr_index); - __swab64s(&cr->cr.cr_prev); - __swab64s(&cr->cr.cr_time); - lustre_swab_lu_fid(&cr->cr.cr_tfid); - lustre_swab_lu_fid(&cr->cr.cr_pfid); - if (cr->cr.cr_flags & CLF_RENAME) { - struct changelog_ext_rename *rnm = - changelog_rec_rename(&cr->cr); - - lustre_swab_lu_fid(&rnm->cr_sfid); - lustre_swab_lu_fid(&rnm->cr_spfid); - } - /* - * Because the tail follows a variable-length structure we need - * to compute its location at runtime - */ - tail = (struct llog_rec_tail *)((char *)&cr->cr + - changelog_rec_size(&cr->cr) + - cr->cr.cr_namelen); - break; - } - - case CHANGELOG_USER_REC: - { - struct llog_changelog_user_rec *cur = - (struct llog_changelog_user_rec *)rec; - - __swab32s(&cur->cur_id); - __swab64s(&cur->cur_endrec); - tail = &cur->cur_tail; - break; - } - - case HSM_AGENT_REC: { - struct llog_agent_req_rec *arr = - (struct llog_agent_req_rec *)rec; - - __swab32s(&arr->arr_hai.hai_len); - __swab32s(&arr->arr_hai.hai_action); - lustre_swab_lu_fid(&arr->arr_hai.hai_fid); - lustre_swab_lu_fid(&arr->arr_hai.hai_dfid); - __swab64s(&arr->arr_hai.hai_cookie); - __swab64s(&arr->arr_hai.hai_extent.offset); - __swab64s(&arr->arr_hai.hai_extent.length); - __swab64s(&arr->arr_hai.hai_gid); - /* no swabing for opaque data */ - /* hai_data[0]; */ - break; - } - - case MDS_SETATTR64_REC: - { - struct llog_setattr64_rec *lsr = - (struct llog_setattr64_rec *)rec; - - lustre_swab_ost_id(&lsr->lsr_oi); - __swab32s(&lsr->lsr_uid); - __swab32s(&lsr->lsr_uid_h); - __swab32s(&lsr->lsr_gid); - __swab32s(&lsr->lsr_gid_h); - __swab64s(&lsr->lsr_valid); - tail = &lsr->lsr_tail; - break; - } - case OBD_CFG_REC: - /* these are swabbed as they are consumed */ - break; - case LLOG_HDR_MAGIC: - { - struct llog_log_hdr *llh = (struct llog_log_hdr *)rec; - - __swab64s(&llh->llh_timestamp); - __swab32s(&llh->llh_count); - __swab32s(&llh->llh_bitmap_offset); - __swab32s(&llh->llh_flags); - __swab32s(&llh->llh_size); - __swab32s(&llh->llh_cat_idx); - tail = LLOG_HDR_TAIL(llh); - break; - } - case LLOG_LOGID_MAGIC: - { - struct llog_logid_rec *lid = (struct llog_logid_rec *)rec; - - lustre_swab_llog_id(&lid->lid_id); - tail = &lid->lid_tail; - break; - } - case LLOG_GEN_REC: - { - struct llog_gen_rec *lgr = (struct llog_gen_rec *)rec; - - __swab64s(&lgr->lgr_gen.mnt_cnt); - __swab64s(&lgr->lgr_gen.conn_cnt); - tail = &lgr->lgr_tail; - break; - } - case LLOG_PAD_MAGIC: - break; - default: - CERROR("Unknown llog rec type %#x swabbing rec %p\n", - rec->lrh_type, rec); - } - - if (tail) { - __swab32s(&tail->lrt_len); - __swab32s(&tail->lrt_index); - } -} -EXPORT_SYMBOL(lustre_swab_llog_rec); - -static void print_llog_hdr(struct llog_log_hdr *h) -{ - CDEBUG(D_OTHER, "llog header: %p\n", h); - CDEBUG(D_OTHER, "\tllh_hdr.lrh_index: %#x\n", h->llh_hdr.lrh_index); - CDEBUG(D_OTHER, "\tllh_hdr.lrh_len: %#x\n", h->llh_hdr.lrh_len); - CDEBUG(D_OTHER, "\tllh_hdr.lrh_type: %#x\n", h->llh_hdr.lrh_type); - CDEBUG(D_OTHER, "\tllh_timestamp: %#llx\n", h->llh_timestamp); - CDEBUG(D_OTHER, "\tllh_count: %#x\n", h->llh_count); - CDEBUG(D_OTHER, "\tllh_bitmap_offset: %#x\n", h->llh_bitmap_offset); - CDEBUG(D_OTHER, "\tllh_flags: %#x\n", h->llh_flags); - CDEBUG(D_OTHER, "\tllh_size: %#x\n", h->llh_size); - CDEBUG(D_OTHER, "\tllh_cat_idx: %#x\n", h->llh_cat_idx); - CDEBUG(D_OTHER, "\tllh_tail.lrt_index: %#x\n", - LLOG_HDR_TAIL(h)->lrt_index); - CDEBUG(D_OTHER, "\tllh_tail.lrt_len: %#x\n", - LLOG_HDR_TAIL(h)->lrt_len); -} - -void lustre_swab_llog_hdr(struct llog_log_hdr *h) -{ - print_llog_hdr(h); - - lustre_swab_llog_rec(&h->llh_hdr); - - print_llog_hdr(h); -} -EXPORT_SYMBOL(lustre_swab_llog_hdr); - -static void print_lustre_cfg(struct lustre_cfg *lcfg) -{ - int i; - - if (!(libcfs_debug & D_OTHER)) /* don't loop on nothing */ - return; - CDEBUG(D_OTHER, "lustre_cfg: %p\n", lcfg); - CDEBUG(D_OTHER, "\tlcfg->lcfg_version: %#x\n", lcfg->lcfg_version); - - CDEBUG(D_OTHER, "\tlcfg->lcfg_command: %#x\n", lcfg->lcfg_command); - CDEBUG(D_OTHER, "\tlcfg->lcfg_num: %#x\n", lcfg->lcfg_num); - CDEBUG(D_OTHER, "\tlcfg->lcfg_flags: %#x\n", lcfg->lcfg_flags); - CDEBUG(D_OTHER, "\tlcfg->lcfg_nid: %s\n", libcfs_nid2str(lcfg->lcfg_nid)); - - CDEBUG(D_OTHER, "\tlcfg->lcfg_bufcount: %d\n", lcfg->lcfg_bufcount); - if (lcfg->lcfg_bufcount < LUSTRE_CFG_MAX_BUFCOUNT) - for (i = 0; i < lcfg->lcfg_bufcount; i++) - CDEBUG(D_OTHER, "\tlcfg->lcfg_buflens[%d]: %d\n", - i, lcfg->lcfg_buflens[i]); -} - -void lustre_swab_lustre_cfg(struct lustre_cfg *lcfg) -{ - int i; - - __swab32s(&lcfg->lcfg_version); - - if (lcfg->lcfg_version != LUSTRE_CFG_VERSION) { - CERROR("not swabbing lustre_cfg version %#x (expecting %#x)\n", - lcfg->lcfg_version, LUSTRE_CFG_VERSION); - return; - } - - __swab32s(&lcfg->lcfg_command); - __swab32s(&lcfg->lcfg_num); - __swab32s(&lcfg->lcfg_flags); - __swab64s(&lcfg->lcfg_nid); - __swab32s(&lcfg->lcfg_bufcount); - for (i = 0; i < lcfg->lcfg_bufcount && i < LUSTRE_CFG_MAX_BUFCOUNT; i++) - __swab32s(&lcfg->lcfg_buflens[i]); - - print_lustre_cfg(lcfg); -} - -/* used only for compatibility with old on-disk cfg_marker data */ -struct cfg_marker32 { - __u32 cm_step; - __u32 cm_flags; - __u32 cm_vers; - __u32 padding; - __u32 cm_createtime; - __u32 cm_canceltime; - char cm_tgtname[MTI_NAME_MAXLEN]; - char cm_comment[MTI_NAME_MAXLEN]; -}; - -#define MTI_NAMELEN32 (MTI_NAME_MAXLEN - \ - (sizeof(struct cfg_marker) - sizeof(struct cfg_marker32))) - -void lustre_swab_cfg_marker(struct cfg_marker *marker, int swab, int size) -{ - struct cfg_marker32 *cm32 = (struct cfg_marker32 *)marker; - - if (swab) { - __swab32s(&marker->cm_step); - __swab32s(&marker->cm_flags); - __swab32s(&marker->cm_vers); - } - if (size == sizeof(*cm32)) { - __u32 createtime, canceltime; - /* There was a problem with the original declaration of - * cfg_marker on 32-bit systems because it used time_t as - * a wire protocol structure, and didn't verify this in - * wirecheck. We now have to convert the offsets of the - * later fields in order to work on 32- and 64-bit systems. - * - * Fortunately, the cm_comment field has no functional use - * so can be sacrificed when converting the timestamp size. - * - * Overwrite fields from the end first, so they are not - * clobbered, and use memmove() instead of memcpy() because - * the source and target buffers overlap. bug 16771 - */ - createtime = cm32->cm_createtime; - canceltime = cm32->cm_canceltime; - memmove(marker->cm_comment, cm32->cm_comment, MTI_NAMELEN32); - marker->cm_comment[MTI_NAMELEN32 - 1] = '\0'; - memmove(marker->cm_tgtname, cm32->cm_tgtname, - sizeof(marker->cm_tgtname)); - if (swab) { - __swab32s(&createtime); - __swab32s(&canceltime); - } - marker->cm_createtime = createtime; - marker->cm_canceltime = canceltime; - CDEBUG(D_CONFIG, "Find old cfg_marker(Srv32b,Clt64b) for target %s, converting\n", - marker->cm_tgtname); - } else if (swab) { - __swab64s(&marker->cm_createtime); - __swab64s(&marker->cm_canceltime); - } -} diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_counters.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_counters.c deleted file mode 100644 index c83b7d7f8e72..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/lprocfs_counters.c +++ /dev/null @@ -1,133 +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) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, 2013, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lustre/obdclass/lprocfs_counters.c - * - * Lustre lprocfs counter routines - * - * Author: Andreas Dilger <andreas.dilger@intel.com> - */ - -#include <linux/module.h> -#include <lprocfs_status.h> -#include <obd_support.h> - -void lprocfs_counter_add(struct lprocfs_stats *stats, int idx, long amount) -{ - struct lprocfs_counter *percpu_cntr; - struct lprocfs_counter_header *header; - int smp_id; - unsigned long flags = 0; - - if (!stats) - return; - - LASSERTF(0 <= idx && idx < stats->ls_num, - "idx %d, ls_num %hu\n", idx, stats->ls_num); - - /* With per-client stats, statistics are allocated only for - * single CPU area, so the smp_id should be 0 always. - */ - smp_id = lprocfs_stats_lock(stats, LPROCFS_GET_SMP_ID, &flags); - if (smp_id < 0) - return; - - header = &stats->ls_cnt_header[idx]; - percpu_cntr = lprocfs_stats_counter_get(stats, smp_id, idx); - percpu_cntr->lc_count++; - - if (header->lc_config & LPROCFS_CNTR_AVGMINMAX) { - /* - * lprocfs_counter_add() can be called in interrupt context, - * as memory allocation could trigger memory shrinker call - * ldlm_pool_shrink(), which calls lprocfs_counter_add(). - * LU-1727. - * - */ - if (in_interrupt() && - (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0) - percpu_cntr->lc_sum_irq += amount; - else - percpu_cntr->lc_sum += amount; - - if (header->lc_config & LPROCFS_CNTR_STDDEV) - percpu_cntr->lc_sumsquare += (__s64)amount * amount; - if (amount < percpu_cntr->lc_min) - percpu_cntr->lc_min = amount; - if (amount > percpu_cntr->lc_max) - percpu_cntr->lc_max = amount; - } - lprocfs_stats_unlock(stats, LPROCFS_GET_SMP_ID, &flags); -} -EXPORT_SYMBOL(lprocfs_counter_add); - -void lprocfs_counter_sub(struct lprocfs_stats *stats, int idx, long amount) -{ - struct lprocfs_counter *percpu_cntr; - struct lprocfs_counter_header *header; - int smp_id; - unsigned long flags = 0; - - if (!stats) - return; - - LASSERTF(0 <= idx && idx < stats->ls_num, - "idx %d, ls_num %hu\n", idx, stats->ls_num); - - /* With per-client stats, statistics are allocated only for - * single CPU area, so the smp_id should be 0 always. - */ - smp_id = lprocfs_stats_lock(stats, LPROCFS_GET_SMP_ID, &flags); - if (smp_id < 0) - return; - - header = &stats->ls_cnt_header[idx]; - percpu_cntr = lprocfs_stats_counter_get(stats, smp_id, idx); - if (header->lc_config & LPROCFS_CNTR_AVGMINMAX) { - /* - * Sometimes we use RCU callbacks to free memory which calls - * lprocfs_counter_sub(), and RCU callbacks may execute in - * softirq context - right now that's the only case we're in - * softirq context here, use separate counter for that. - * bz20650. - * - */ - if (in_interrupt() && - (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0) - percpu_cntr->lc_sum_irq -= amount; - else - percpu_cntr->lc_sum -= amount; - } - lprocfs_stats_unlock(stats, LPROCFS_GET_SMP_ID, &flags); -} -EXPORT_SYMBOL(lprocfs_counter_sub); diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c deleted file mode 100644 index 2ed350527398..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c +++ /dev/null @@ -1,1810 +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. - * - * lustre/obdclass/lprocfs_status.c - * - * Author: Hariharan Thantry <thantry@users.sourceforge.net> - */ - -#define DEBUG_SUBSYSTEM S_CLASS - -#include <obd_class.h> -#include <lprocfs_status.h> -#include <uapi/linux/lustre/lustre_idl.h> -#include <linux/seq_file.h> -#include <linux/ctype.h> - -static const char * const obd_connect_names[] = { - "read_only", - "lov_index", - "connect_from_mds", - "write_grant", - "server_lock", - "version", - "request_portal", - "acl", - "xattr", - "create_on_write", - "truncate_lock", - "initial_transno", - "inode_bit_locks", - "join_file(obsolete)", - "getattr_by_fid", - "no_oh_for_devices", - "remote_client", - "remote_client_by_force", - "max_byte_per_rpc", - "64bit_qdata", - "mds_capability", - "oss_capability", - "early_lock_cancel", - "som", - "adaptive_timeouts", - "lru_resize", - "mds_mds_connection", - "real_conn", - "change_qunit_size", - "alt_checksum_algorithm", - "fid_is_enabled", - "version_recovery", - "pools", - "grant_shrink", - "skip_orphan", - "large_ea", - "full20", - "layout_lock", - "64bithash", - "object_max_bytes", - "imp_recov", - "jobstats", - "umask", - "einprogress", - "grant_param", - "flock_owner", - "lvb_type", - "nanoseconds_times", - "lightweight_conn", - "short_io", - "pingless", - "flock_deadlock", - "disp_stripe", - "open_by_fid", - "lfsck", - "unknown", - "unlink_close", - "multi_mod_rpcs", - "dir_stripe", - "subtree", - "lock_ahead", - "bulk_mbits", - "compact_obdo", - "second_flags", - NULL -}; - -int obd_connect_flags2str(char *page, int count, __u64 flags, char *sep) -{ - __u64 mask = 1; - int i, ret = 0; - - for (i = 0; obd_connect_names[i]; i++, mask <<= 1) { - if (flags & mask) - ret += snprintf(page + ret, count - ret, "%s%s", - ret ? sep : "", obd_connect_names[i]); - } - if (flags & ~(mask - 1)) - ret += snprintf(page + ret, count - ret, - "%sunknown flags %#llx", - ret ? sep : "", flags & ~(mask - 1)); - return ret; -} -EXPORT_SYMBOL(obd_connect_flags2str); - -static void obd_connect_data_seqprint(struct seq_file *m, - struct obd_connect_data *ocd) -{ - u64 flags; - - LASSERT(ocd); - flags = ocd->ocd_connect_flags; - - seq_printf(m, " connect_data:\n" - " flags: %llx\n" - " instance: %u\n", - ocd->ocd_connect_flags, - ocd->ocd_instance); - if (flags & OBD_CONNECT_VERSION) - seq_printf(m, " target_version: %u.%u.%u.%u\n", - OBD_OCD_VERSION_MAJOR(ocd->ocd_version), - OBD_OCD_VERSION_MINOR(ocd->ocd_version), - OBD_OCD_VERSION_PATCH(ocd->ocd_version), - OBD_OCD_VERSION_FIX(ocd->ocd_version)); - if (flags & OBD_CONNECT_MDS) - seq_printf(m, " mdt_index: %d\n", ocd->ocd_group); - if (flags & OBD_CONNECT_GRANT) - seq_printf(m, " initial_grant: %d\n", ocd->ocd_grant); - if (flags & OBD_CONNECT_INDEX) - seq_printf(m, " target_index: %u\n", ocd->ocd_index); - if (flags & OBD_CONNECT_BRW_SIZE) - seq_printf(m, " max_brw_size: %d\n", ocd->ocd_brw_size); - if (flags & OBD_CONNECT_IBITS) - seq_printf(m, " ibits_known: %llx\n", - ocd->ocd_ibits_known); - if (flags & OBD_CONNECT_GRANT_PARAM) - seq_printf(m, " grant_block_size: %d\n" - " grant_inode_size: %d\n" - " grant_extent_overhead: %d\n", - ocd->ocd_blocksize, - ocd->ocd_inodespace, - ocd->ocd_grant_extent); - if (flags & OBD_CONNECT_TRANSNO) - seq_printf(m, " first_transno: %llx\n", - ocd->ocd_transno); - if (flags & OBD_CONNECT_CKSUM) - seq_printf(m, " cksum_types: %#x\n", - ocd->ocd_cksum_types); - if (flags & OBD_CONNECT_MAX_EASIZE) - seq_printf(m, " max_easize: %d\n", ocd->ocd_max_easize); - if (flags & OBD_CONNECT_MAXBYTES) - seq_printf(m, " max_object_bytes: %llx\n", - ocd->ocd_maxbytes); - if (flags & OBD_CONNECT_MULTIMODRPCS) - seq_printf(m, " max_mod_rpcs: %hu\n", - ocd->ocd_maxmodrpcs); -} - -int lprocfs_read_frac_helper(char *buffer, unsigned long count, long val, - int mult) -{ - long decimal_val, frac_val; - int prtn; - - if (count < 10) - return -EINVAL; - - decimal_val = val / mult; - prtn = snprintf(buffer, count, "%ld", decimal_val); - frac_val = val % mult; - - if (prtn < (count - 4) && frac_val > 0) { - long temp_frac; - int i, temp_mult = 1, frac_bits = 0; - - temp_frac = frac_val * 10; - buffer[prtn++] = '.'; - while (frac_bits < 2 && (temp_frac / mult) < 1) { - /* only reserved 2 bits fraction */ - buffer[prtn++] = '0'; - temp_frac *= 10; - frac_bits++; - } - /* - * Need to think these cases : - * 1. #echo x.00 > /sys/xxx output result : x - * 2. #echo x.0x > /sys/xxx output result : x.0x - * 3. #echo x.x0 > /sys/xxx output result : x.x - * 4. #echo x.xx > /sys/xxx output result : x.xx - * Only reserved 2 bits fraction. - */ - for (i = 0; i < (5 - prtn); i++) - temp_mult *= 10; - - frac_bits = min((int)count - prtn, 3 - frac_bits); - prtn += snprintf(buffer + prtn, frac_bits, "%ld", - frac_val * temp_mult / mult); - - prtn--; - while (buffer[prtn] < '1' || buffer[prtn] > '9') { - prtn--; - if (buffer[prtn] == '.') { - prtn--; - break; - } - } - prtn++; - } - buffer[prtn++] = '\n'; - return prtn; -} -EXPORT_SYMBOL(lprocfs_read_frac_helper); - -int lprocfs_write_frac_helper(const char __user *buffer, unsigned long count, - int *val, int mult) -{ - char kernbuf[20], *end, *pbuf; - - if (count > (sizeof(kernbuf) - 1)) - return -EINVAL; - - if (copy_from_user(kernbuf, buffer, count)) - return -EFAULT; - - kernbuf[count] = '\0'; - pbuf = kernbuf; - if (*pbuf == '-') { - mult = -mult; - pbuf++; - } - - *val = (int)simple_strtoul(pbuf, &end, 10) * mult; - if (pbuf == end) - return -EINVAL; - - if (end && *end == '.') { - int temp_val, pow = 1; - int i; - - pbuf = end + 1; - if (strlen(pbuf) > 5) - pbuf[5] = '\0'; /*only allow 5bits fractional*/ - - temp_val = (int)simple_strtoul(pbuf, &end, 10) * mult; - - if (pbuf < end) { - for (i = 0; i < (end - pbuf); i++) - pow *= 10; - - *val += temp_val / pow; - } - } - return 0; -} -EXPORT_SYMBOL(lprocfs_write_frac_helper); - -static int lprocfs_no_percpu_stats; -module_param(lprocfs_no_percpu_stats, int, 0644); -MODULE_PARM_DESC(lprocfs_no_percpu_stats, "Do not alloc percpu data for lprocfs stats"); - -#define MAX_STRING_SIZE 128 - -int lprocfs_single_release(struct inode *inode, struct file *file) -{ - return single_release(inode, file); -} -EXPORT_SYMBOL(lprocfs_single_release); - -int lprocfs_seq_release(struct inode *inode, struct file *file) -{ - return seq_release(inode, file); -} -EXPORT_SYMBOL(lprocfs_seq_release); - -/* lprocfs API calls */ - -struct dentry *ldebugfs_add_simple(struct dentry *root, - char *name, void *data, - const struct file_operations *fops) -{ - struct dentry *entry; - umode_t mode = 0; - - if (!root || !name || !fops) - return ERR_PTR(-EINVAL); - - if (fops->read) - mode = 0444; - if (fops->write) - mode |= 0200; - entry = debugfs_create_file(name, mode, root, data, fops); - if (IS_ERR_OR_NULL(entry)) { - CERROR("LprocFS: No memory to create <debugfs> entry %s\n", name); - return entry ?: ERR_PTR(-ENOMEM); - } - return entry; -} -EXPORT_SYMBOL_GPL(ldebugfs_add_simple); - -static const struct file_operations lprocfs_generic_fops = { }; - -int ldebugfs_add_vars(struct dentry *parent, - struct lprocfs_vars *list, - void *data) -{ - if (IS_ERR_OR_NULL(parent) || IS_ERR_OR_NULL(list)) - return -EINVAL; - - while (list->name) { - struct dentry *entry; - umode_t mode = 0; - - if (list->proc_mode != 0000) { - mode = list->proc_mode; - } else if (list->fops) { - if (list->fops->read) - mode = 0444; - if (list->fops->write) - mode |= 0200; - } - entry = debugfs_create_file(list->name, mode, parent, - list->data ?: data, - list->fops ?: &lprocfs_generic_fops - ); - if (IS_ERR_OR_NULL(entry)) - return entry ? PTR_ERR(entry) : -ENOMEM; - list++; - } - return 0; -} -EXPORT_SYMBOL_GPL(ldebugfs_add_vars); - -void ldebugfs_remove(struct dentry **entryp) -{ - debugfs_remove_recursive(*entryp); - *entryp = NULL; -} -EXPORT_SYMBOL_GPL(ldebugfs_remove); - -struct dentry *ldebugfs_register(const char *name, - struct dentry *parent, - struct lprocfs_vars *list, void *data) -{ - struct dentry *entry; - - entry = debugfs_create_dir(name, parent); - if (IS_ERR_OR_NULL(entry)) { - entry = entry ?: ERR_PTR(-ENOMEM); - goto out; - } - - if (!IS_ERR_OR_NULL(list)) { - int rc; - - rc = ldebugfs_add_vars(entry, list, data); - if (rc != 0) { - debugfs_remove(entry); - entry = ERR_PTR(rc); - } - } -out: - return entry; -} -EXPORT_SYMBOL_GPL(ldebugfs_register); - -/* Generic callbacks */ -static ssize_t uuid_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct obd_device *obd = container_of(kobj, struct obd_device, - obd_kobj); - - return sprintf(buf, "%s\n", obd->obd_uuid.uuid); -} -LUSTRE_RO_ATTR(uuid); - -static ssize_t blocksize_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct obd_device *obd = container_of(kobj, struct obd_device, - obd_kobj); - struct obd_statfs osfs; - int rc = obd_statfs(NULL, obd->obd_self_export, &osfs, - cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS), - OBD_STATFS_NODELAY); - if (!rc) - return sprintf(buf, "%u\n", osfs.os_bsize); - - return rc; -} -LUSTRE_RO_ATTR(blocksize); - -static ssize_t kbytestotal_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct obd_device *obd = container_of(kobj, struct obd_device, - obd_kobj); - struct obd_statfs osfs; - int rc = obd_statfs(NULL, obd->obd_self_export, &osfs, - cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS), - OBD_STATFS_NODELAY); - if (!rc) { - __u32 blk_size = osfs.os_bsize >> 10; - __u64 result = osfs.os_blocks; - - while (blk_size >>= 1) - result <<= 1; - - return sprintf(buf, "%llu\n", result); - } - - return rc; -} -LUSTRE_RO_ATTR(kbytestotal); - -static ssize_t kbytesfree_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct obd_device *obd = container_of(kobj, struct obd_device, - obd_kobj); - struct obd_statfs osfs; - int rc = obd_statfs(NULL, obd->obd_self_export, &osfs, - cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS), - OBD_STATFS_NODELAY); - if (!rc) { - __u32 blk_size = osfs.os_bsize >> 10; - __u64 result = osfs.os_bfree; - - while (blk_size >>= 1) - result <<= 1; - - return sprintf(buf, "%llu\n", result); - } - - return rc; -} -LUSTRE_RO_ATTR(kbytesfree); - -static ssize_t kbytesavail_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct obd_device *obd = container_of(kobj, struct obd_device, - obd_kobj); - struct obd_statfs osfs; - int rc = obd_statfs(NULL, obd->obd_self_export, &osfs, - cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS), - OBD_STATFS_NODELAY); - if (!rc) { - __u32 blk_size = osfs.os_bsize >> 10; - __u64 result = osfs.os_bavail; - - while (blk_size >>= 1) - result <<= 1; - - return sprintf(buf, "%llu\n", result); - } - - return rc; -} -LUSTRE_RO_ATTR(kbytesavail); - -static ssize_t filestotal_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct obd_device *obd = container_of(kobj, struct obd_device, - obd_kobj); - struct obd_statfs osfs; - int rc = obd_statfs(NULL, obd->obd_self_export, &osfs, - cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS), - OBD_STATFS_NODELAY); - if (!rc) - return sprintf(buf, "%llu\n", osfs.os_files); - - return rc; -} -LUSTRE_RO_ATTR(filestotal); - -static ssize_t filesfree_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct obd_device *obd = container_of(kobj, struct obd_device, - obd_kobj); - struct obd_statfs osfs; - int rc = obd_statfs(NULL, obd->obd_self_export, &osfs, - cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS), - OBD_STATFS_NODELAY); - if (!rc) - return sprintf(buf, "%llu\n", osfs.os_ffree); - - return rc; -} -LUSTRE_RO_ATTR(filesfree); - -int lprocfs_rd_server_uuid(struct seq_file *m, void *data) -{ - struct obd_device *obd = data; - struct obd_import *imp; - char *imp_state_name = NULL; - int rc; - - LASSERT(obd); - rc = lprocfs_climp_check(obd); - if (rc) - return rc; - - imp = obd->u.cli.cl_import; - imp_state_name = ptlrpc_import_state_name(imp->imp_state); - seq_printf(m, "%s\t%s%s\n", - obd2cli_tgt(obd), imp_state_name, - imp->imp_deactive ? "\tDEACTIVATED" : ""); - - up_read(&obd->u.cli.cl_sem); - - return 0; -} -EXPORT_SYMBOL(lprocfs_rd_server_uuid); - -int lprocfs_rd_conn_uuid(struct seq_file *m, void *data) -{ - struct obd_device *obd = data; - struct ptlrpc_connection *conn; - int rc; - - LASSERT(obd); - - rc = lprocfs_climp_check(obd); - if (rc) - return rc; - - conn = obd->u.cli.cl_import->imp_connection; - if (conn && obd->u.cli.cl_import) - seq_printf(m, "%s\n", conn->c_remote_uuid.uuid); - else - seq_puts(m, "<none>\n"); - - up_read(&obd->u.cli.cl_sem); - - return 0; -} -EXPORT_SYMBOL(lprocfs_rd_conn_uuid); - -/** - * Lock statistics structure for access, possibly only on this CPU. - * - * The statistics struct may be allocated with per-CPU structures for - * efficient concurrent update (usually only on server-wide stats), or - * as a single global struct (e.g. for per-client or per-job statistics), - * so the required locking depends on the type of structure allocated. - * - * For per-CPU statistics, pin the thread to the current cpuid so that - * will only access the statistics for that CPU. If the stats structure - * for the current CPU has not been allocated (or previously freed), - * allocate it now. The per-CPU statistics do not need locking since - * the thread is pinned to the CPU during update. - * - * For global statistics, lock the stats structure to prevent concurrent update. - * - * \param[in] stats statistics structure to lock - * \param[in] opc type of operation: - * LPROCFS_GET_SMP_ID: "lock" and return current CPU index - * for incrementing statistics for that CPU - * LPROCFS_GET_NUM_CPU: "lock" and return number of used - * CPU indices to iterate over all indices - * \param[out] flags CPU interrupt saved state for IRQ-safe locking - * - * \retval cpuid of current thread or number of allocated structs - * \retval negative on error (only for opc LPROCFS_GET_SMP_ID + per-CPU stats) - */ -int lprocfs_stats_lock(struct lprocfs_stats *stats, - enum lprocfs_stats_lock_ops opc, - unsigned long *flags) -{ - if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU) { - if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) - spin_lock_irqsave(&stats->ls_lock, *flags); - else - spin_lock(&stats->ls_lock); - return opc == LPROCFS_GET_NUM_CPU ? 1 : 0; - } - - switch (opc) { - case LPROCFS_GET_SMP_ID: { - unsigned int cpuid = get_cpu(); - - if (unlikely(!stats->ls_percpu[cpuid])) { - int rc = lprocfs_stats_alloc_one(stats, cpuid); - - if (rc < 0) { - put_cpu(); - return rc; - } - } - return cpuid; - } - case LPROCFS_GET_NUM_CPU: - return stats->ls_biggest_alloc_num; - default: - LBUG(); - } -} - -/** - * Unlock statistics structure after access. - * - * Unlock the lock acquired via lprocfs_stats_lock() for global statistics, - * or unpin this thread from the current cpuid for per-CPU statistics. - * - * This function must be called using the same arguments as used when calling - * lprocfs_stats_lock() so that the correct operation can be performed. - * - * \param[in] stats statistics structure to unlock - * \param[in] opc type of operation (current cpuid or number of structs) - * \param[in] flags CPU interrupt saved state for IRQ-safe locking - */ -void lprocfs_stats_unlock(struct lprocfs_stats *stats, - enum lprocfs_stats_lock_ops opc, - unsigned long *flags) -{ - if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU) { - if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) - spin_unlock_irqrestore(&stats->ls_lock, *flags); - else - spin_unlock(&stats->ls_lock); - } else if (opc == LPROCFS_GET_SMP_ID) { - put_cpu(); - } -} - -/** add up per-cpu counters */ -void lprocfs_stats_collect(struct lprocfs_stats *stats, int idx, - struct lprocfs_counter *cnt) -{ - unsigned int num_entry; - struct lprocfs_counter *percpu_cntr; - int i; - unsigned long flags = 0; - - memset(cnt, 0, sizeof(*cnt)); - - if (!stats) { - /* set count to 1 to avoid divide-by-zero errs in callers */ - cnt->lc_count = 1; - return; - } - - cnt->lc_min = LC_MIN_INIT; - - num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags); - - for (i = 0; i < num_entry; i++) { - if (!stats->ls_percpu[i]) - continue; - percpu_cntr = lprocfs_stats_counter_get(stats, i, idx); - - cnt->lc_count += percpu_cntr->lc_count; - cnt->lc_sum += percpu_cntr->lc_sum; - if (percpu_cntr->lc_min < cnt->lc_min) - cnt->lc_min = percpu_cntr->lc_min; - if (percpu_cntr->lc_max > cnt->lc_max) - cnt->lc_max = percpu_cntr->lc_max; - cnt->lc_sumsquare += percpu_cntr->lc_sumsquare; - } - - lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags); -} - -/** - * Append a space separated list of current set flags to str. - */ -#define flag2str(flag, first) \ - do { \ - if (imp->imp_##flag) \ - seq_printf(m, "%s" #flag, first ? "" : ", "); \ - } while (0) -static int obd_import_flags2str(struct obd_import *imp, struct seq_file *m) -{ - bool first = true; - - if (imp->imp_obd->obd_no_recov) { - seq_puts(m, "no_recov"); - first = false; - } - - flag2str(invalid, first); - first = false; - flag2str(deactive, first); - flag2str(replayable, first); - flag2str(pingable, first); - return 0; -} - -#undef flags2str - -static void obd_connect_seq_flags2str(struct seq_file *m, __u64 flags, char *sep) -{ - __u64 mask = 1; - int i; - bool first = true; - - for (i = 0; obd_connect_names[i]; i++, mask <<= 1) { - if (flags & mask) { - seq_printf(m, "%s%s", - first ? sep : "", obd_connect_names[i]); - first = false; - } - } - if (flags & ~(mask - 1)) - seq_printf(m, "%sunknown flags %#llx", - first ? sep : "", flags & ~(mask - 1)); -} - -int lprocfs_rd_import(struct seq_file *m, void *data) -{ - char nidstr[LNET_NIDSTR_SIZE]; - struct lprocfs_counter ret; - struct lprocfs_counter_header *header; - struct obd_device *obd = data; - struct obd_import *imp; - struct obd_import_conn *conn; - struct obd_connect_data *ocd; - int j; - int k; - int rw = 0; - int rc; - - LASSERT(obd); - rc = lprocfs_climp_check(obd); - if (rc) - return rc; - - imp = obd->u.cli.cl_import; - ocd = &imp->imp_connect_data; - - seq_printf(m, "import:\n" - " name: %s\n" - " target: %s\n" - " state: %s\n" - " instance: %u\n" - " connect_flags: [ ", - obd->obd_name, - obd2cli_tgt(obd), - ptlrpc_import_state_name(imp->imp_state), - imp->imp_connect_data.ocd_instance); - obd_connect_seq_flags2str(m, imp->imp_connect_data.ocd_connect_flags, - ", "); - seq_puts(m, " ]\n"); - obd_connect_data_seqprint(m, ocd); - seq_puts(m, " import_flags: [ "); - obd_import_flags2str(imp, m); - - seq_puts(m, - " ]\n" - " connection:\n" - " failover_nids: [ "); - spin_lock(&imp->imp_lock); - j = 0; - list_for_each_entry(conn, &imp->imp_conn_list, oic_item) { - libcfs_nid2str_r(conn->oic_conn->c_peer.nid, - nidstr, sizeof(nidstr)); - seq_printf(m, "%s%s", j ? ", " : "", nidstr); - j++; - } - if (imp->imp_connection) - libcfs_nid2str_r(imp->imp_connection->c_peer.nid, - nidstr, sizeof(nidstr)); - else - strncpy(nidstr, "<none>", sizeof(nidstr)); - seq_printf(m, - " ]\n" - " current_connection: %s\n" - " connection_attempts: %u\n" - " generation: %u\n" - " in-progress_invalidations: %u\n", - nidstr, - imp->imp_conn_cnt, - imp->imp_generation, - atomic_read(&imp->imp_inval_count)); - spin_unlock(&imp->imp_lock); - - if (!obd->obd_svc_stats) - goto out_climp; - - header = &obd->obd_svc_stats->ls_cnt_header[PTLRPC_REQWAIT_CNTR]; - lprocfs_stats_collect(obd->obd_svc_stats, PTLRPC_REQWAIT_CNTR, &ret); - if (ret.lc_count != 0) { - /* first argument to do_div MUST be __u64 */ - __u64 sum = ret.lc_sum; - - do_div(sum, ret.lc_count); - ret.lc_sum = sum; - } else { - ret.lc_sum = 0; - } - seq_printf(m, - " rpcs:\n" - " inflight: %u\n" - " unregistering: %u\n" - " timeouts: %u\n" - " avg_waittime: %llu %s\n", - atomic_read(&imp->imp_inflight), - atomic_read(&imp->imp_unregistering), - atomic_read(&imp->imp_timeouts), - ret.lc_sum, header->lc_units); - - k = 0; - for (j = 0; j < IMP_AT_MAX_PORTALS; j++) { - if (imp->imp_at.iat_portal[j] == 0) - break; - k = max_t(unsigned int, k, - at_get(&imp->imp_at.iat_service_estimate[j])); - } - seq_printf(m, - " service_estimates:\n" - " services: %u sec\n" - " network: %u sec\n", - k, - at_get(&imp->imp_at.iat_net_latency)); - - seq_printf(m, - " transactions:\n" - " last_replay: %llu\n" - " peer_committed: %llu\n" - " last_checked: %llu\n", - imp->imp_last_replay_transno, - imp->imp_peer_committed_transno, - imp->imp_last_transno_checked); - - /* avg data rates */ - for (rw = 0; rw <= 1; rw++) { - lprocfs_stats_collect(obd->obd_svc_stats, - PTLRPC_LAST_CNTR + BRW_READ_BYTES + rw, - &ret); - if (ret.lc_sum > 0 && ret.lc_count > 0) { - /* first argument to do_div MUST be __u64 */ - __u64 sum = ret.lc_sum; - - do_div(sum, ret.lc_count); - ret.lc_sum = sum; - seq_printf(m, - " %s_data_averages:\n" - " bytes_per_rpc: %llu\n", - rw ? "write" : "read", - ret.lc_sum); - } - k = (int)ret.lc_sum; - j = opcode_offset(OST_READ + rw) + EXTRA_MAX_OPCODES; - header = &obd->obd_svc_stats->ls_cnt_header[j]; - lprocfs_stats_collect(obd->obd_svc_stats, j, &ret); - if (ret.lc_sum > 0 && ret.lc_count != 0) { - /* first argument to do_div MUST be __u64 */ - __u64 sum = ret.lc_sum; - - do_div(sum, ret.lc_count); - ret.lc_sum = sum; - seq_printf(m, - " %s_per_rpc: %llu\n", - header->lc_units, ret.lc_sum); - j = (int)ret.lc_sum; - if (j > 0) - seq_printf(m, - " MB_per_sec: %u.%.02u\n", - k / j, (100 * k / j) % 100); - } - } - -out_climp: - up_read(&obd->u.cli.cl_sem); - return 0; -} -EXPORT_SYMBOL(lprocfs_rd_import); - -int lprocfs_rd_state(struct seq_file *m, void *data) -{ - struct obd_device *obd = data; - struct obd_import *imp; - int j, k, rc; - - LASSERT(obd); - rc = lprocfs_climp_check(obd); - if (rc) - return rc; - - imp = obd->u.cli.cl_import; - - seq_printf(m, "current_state: %s\n", - ptlrpc_import_state_name(imp->imp_state)); - seq_puts(m, "state_history:\n"); - k = imp->imp_state_hist_idx; - for (j = 0; j < IMP_STATE_HIST_LEN; j++) { - struct import_state_hist *ish = - &imp->imp_state_hist[(k + j) % IMP_STATE_HIST_LEN]; - if (ish->ish_state == 0) - continue; - seq_printf(m, " - [ %lld, %s ]\n", (s64)ish->ish_time, - ptlrpc_import_state_name(ish->ish_state)); - } - - up_read(&obd->u.cli.cl_sem); - return 0; -} -EXPORT_SYMBOL(lprocfs_rd_state); - -int lprocfs_at_hist_helper(struct seq_file *m, struct adaptive_timeout *at) -{ - int i; - - for (i = 0; i < AT_BINS; i++) - seq_printf(m, "%3u ", at->at_hist[i]); - seq_puts(m, "\n"); - return 0; -} -EXPORT_SYMBOL(lprocfs_at_hist_helper); - -/* See also ptlrpc_lprocfs_rd_timeouts */ -int lprocfs_rd_timeouts(struct seq_file *m, void *data) -{ - struct obd_device *obd = data; - struct obd_import *imp; - unsigned int cur, worst; - time64_t now, worstt; - struct dhms ts; - int i, rc; - - LASSERT(obd); - rc = lprocfs_climp_check(obd); - if (rc) - return rc; - - imp = obd->u.cli.cl_import; - - now = ktime_get_real_seconds(); - - /* Some network health info for kicks */ - s2dhms(&ts, now - imp->imp_last_reply_time); - seq_printf(m, "%-10s : %lld, " DHMS_FMT " ago\n", - "last reply", (s64)imp->imp_last_reply_time, DHMS_VARS(&ts)); - - cur = at_get(&imp->imp_at.iat_net_latency); - worst = imp->imp_at.iat_net_latency.at_worst_ever; - worstt = imp->imp_at.iat_net_latency.at_worst_time; - s2dhms(&ts, now - worstt); - seq_printf(m, "%-10s : cur %3u worst %3u (at %lld, " DHMS_FMT " ago) ", - "network", cur, worst, (s64)worstt, DHMS_VARS(&ts)); - lprocfs_at_hist_helper(m, &imp->imp_at.iat_net_latency); - - for (i = 0; i < IMP_AT_MAX_PORTALS; i++) { - if (imp->imp_at.iat_portal[i] == 0) - break; - cur = at_get(&imp->imp_at.iat_service_estimate[i]); - worst = imp->imp_at.iat_service_estimate[i].at_worst_ever; - worstt = imp->imp_at.iat_service_estimate[i].at_worst_time; - s2dhms(&ts, now - worstt); - seq_printf(m, "portal %-2d : cur %3u worst %3u (at %lld, " - DHMS_FMT " ago) ", imp->imp_at.iat_portal[i], - cur, worst, (s64)worstt, DHMS_VARS(&ts)); - lprocfs_at_hist_helper(m, &imp->imp_at.iat_service_estimate[i]); - } - - up_read(&obd->u.cli.cl_sem); - return 0; -} -EXPORT_SYMBOL(lprocfs_rd_timeouts); - -int lprocfs_rd_connect_flags(struct seq_file *m, void *data) -{ - struct obd_device *obd = data; - __u64 flags; - int rc; - - rc = lprocfs_climp_check(obd); - if (rc) - return rc; - - flags = obd->u.cli.cl_import->imp_connect_data.ocd_connect_flags; - seq_printf(m, "flags=%#llx\n", flags); - obd_connect_seq_flags2str(m, flags, "\n"); - seq_puts(m, "\n"); - up_read(&obd->u.cli.cl_sem); - return 0; -} -EXPORT_SYMBOL(lprocfs_rd_connect_flags); - -static struct attribute *obd_def_attrs[] = { - &lustre_attr_blocksize.attr, - &lustre_attr_kbytestotal.attr, - &lustre_attr_kbytesfree.attr, - &lustre_attr_kbytesavail.attr, - &lustre_attr_filestotal.attr, - &lustre_attr_filesfree.attr, - &lustre_attr_uuid.attr, - NULL, -}; - -static void obd_sysfs_release(struct kobject *kobj) -{ - struct obd_device *obd = container_of(kobj, struct obd_device, - obd_kobj); - - complete(&obd->obd_kobj_unregister); -} - -static struct kobj_type obd_ktype = { - .default_attrs = obd_def_attrs, - .sysfs_ops = &lustre_sysfs_ops, - .release = obd_sysfs_release, -}; - -int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list, - const struct attribute_group *attrs) -{ - int rc = 0; - - init_completion(&obd->obd_kobj_unregister); - rc = kobject_init_and_add(&obd->obd_kobj, &obd_ktype, - obd->obd_type->typ_kobj, - "%s", obd->obd_name); - if (rc) - return rc; - - if (attrs) { - rc = sysfs_create_group(&obd->obd_kobj, attrs); - if (rc) { - kobject_put(&obd->obd_kobj); - return rc; - } - } - - obd->obd_debugfs_entry = ldebugfs_register(obd->obd_name, - obd->obd_type->typ_debugfs_entry, - list, obd); - if (IS_ERR_OR_NULL(obd->obd_debugfs_entry)) { - rc = obd->obd_debugfs_entry ? PTR_ERR(obd->obd_debugfs_entry) - : -ENOMEM; - CERROR("error %d setting up lprocfs for %s\n", - rc, obd->obd_name); - obd->obd_debugfs_entry = NULL; - } - - return rc; -} -EXPORT_SYMBOL_GPL(lprocfs_obd_setup); - -int lprocfs_obd_cleanup(struct obd_device *obd) -{ - if (!obd) - return -EINVAL; - - if (!IS_ERR_OR_NULL(obd->obd_debugfs_entry)) - ldebugfs_remove(&obd->obd_debugfs_entry); - - kobject_put(&obd->obd_kobj); - wait_for_completion(&obd->obd_kobj_unregister); - - return 0; -} -EXPORT_SYMBOL_GPL(lprocfs_obd_cleanup); - -int lprocfs_stats_alloc_one(struct lprocfs_stats *stats, unsigned int cpuid) -{ - struct lprocfs_counter *cntr; - unsigned int percpusize; - int rc = -ENOMEM; - unsigned long flags = 0; - int i; - - LASSERT(!stats->ls_percpu[cpuid]); - LASSERT((stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU) == 0); - - percpusize = lprocfs_stats_counter_size(stats); - stats->ls_percpu[cpuid] = kzalloc(percpusize, GFP_ATOMIC); - if (stats->ls_percpu[cpuid]) { - rc = 0; - if (unlikely(stats->ls_biggest_alloc_num <= cpuid)) { - if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) - spin_lock_irqsave(&stats->ls_lock, flags); - else - spin_lock(&stats->ls_lock); - if (stats->ls_biggest_alloc_num <= cpuid) - stats->ls_biggest_alloc_num = cpuid + 1; - if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) - spin_unlock_irqrestore(&stats->ls_lock, flags); - else - spin_unlock(&stats->ls_lock); - } - /* initialize the ls_percpu[cpuid] non-zero counter */ - for (i = 0; i < stats->ls_num; ++i) { - cntr = lprocfs_stats_counter_get(stats, cpuid, i); - cntr->lc_min = LC_MIN_INIT; - } - } - return rc; -} - -struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num, - enum lprocfs_stats_flags flags) -{ - struct lprocfs_stats *stats; - unsigned int num_entry; - unsigned int percpusize = 0; - int i; - - if (num == 0) - return NULL; - - if (lprocfs_no_percpu_stats != 0) - flags |= LPROCFS_STATS_FLAG_NOPERCPU; - - if (flags & LPROCFS_STATS_FLAG_NOPERCPU) - num_entry = 1; - else - num_entry = num_possible_cpus(); - - /* alloc percpu pointers for all possible cpu slots */ - stats = kvzalloc(offsetof(typeof(*stats), ls_percpu[num_entry]), - GFP_KERNEL); - if (!stats) - return NULL; - - stats->ls_num = num; - stats->ls_flags = flags; - spin_lock_init(&stats->ls_lock); - - /* alloc num of counter headers */ - stats->ls_cnt_header = kvmalloc_array(stats->ls_num, - sizeof(struct lprocfs_counter_header), - GFP_KERNEL | __GFP_ZERO); - if (!stats->ls_cnt_header) - goto fail; - - if ((flags & LPROCFS_STATS_FLAG_NOPERCPU) != 0) { - /* contains only one set counters */ - percpusize = lprocfs_stats_counter_size(stats); - stats->ls_percpu[0] = kzalloc(percpusize, GFP_ATOMIC); - if (!stats->ls_percpu[0]) - goto fail; - stats->ls_biggest_alloc_num = 1; - } else if ((flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0) { - /* alloc all percpu data */ - for (i = 0; i < num_entry; ++i) - if (lprocfs_stats_alloc_one(stats, i) < 0) - goto fail; - } - - return stats; - -fail: - lprocfs_free_stats(&stats); - return NULL; -} -EXPORT_SYMBOL(lprocfs_alloc_stats); - -void lprocfs_free_stats(struct lprocfs_stats **statsh) -{ - struct lprocfs_stats *stats = *statsh; - unsigned int num_entry; - unsigned int percpusize; - unsigned int i; - - if (!stats || stats->ls_num == 0) - return; - *statsh = NULL; - - if (stats->ls_flags & LPROCFS_STATS_FLAG_NOPERCPU) - num_entry = 1; - else - num_entry = num_possible_cpus(); - - percpusize = lprocfs_stats_counter_size(stats); - for (i = 0; i < num_entry; i++) - kfree(stats->ls_percpu[i]); - kvfree(stats->ls_cnt_header); - kvfree(stats); -} -EXPORT_SYMBOL(lprocfs_free_stats); - -__u64 lprocfs_stats_collector(struct lprocfs_stats *stats, int idx, - enum lprocfs_fields_flags field) -{ - unsigned int i; - unsigned int num_cpu; - unsigned long flags = 0; - __u64 ret = 0; - - LASSERT(stats); - - num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags); - for (i = 0; i < num_cpu; i++) { - if (!stats->ls_percpu[i]) - continue; - ret += lprocfs_read_helper( - lprocfs_stats_counter_get(stats, i, idx), - &stats->ls_cnt_header[idx], stats->ls_flags, - field); - } - lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags); - return ret; -} -EXPORT_SYMBOL(lprocfs_stats_collector); - -void lprocfs_clear_stats(struct lprocfs_stats *stats) -{ - struct lprocfs_counter *percpu_cntr; - int i; - int j; - unsigned int num_entry; - unsigned long flags = 0; - - num_entry = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags); - - for (i = 0; i < num_entry; i++) { - if (!stats->ls_percpu[i]) - continue; - for (j = 0; j < stats->ls_num; j++) { - percpu_cntr = lprocfs_stats_counter_get(stats, i, j); - percpu_cntr->lc_count = 0; - percpu_cntr->lc_min = LC_MIN_INIT; - percpu_cntr->lc_max = 0; - percpu_cntr->lc_sumsquare = 0; - percpu_cntr->lc_sum = 0; - if (stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) - percpu_cntr->lc_sum_irq = 0; - } - } - - lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags); -} -EXPORT_SYMBOL(lprocfs_clear_stats); - -static ssize_t lprocfs_stats_seq_write(struct file *file, - const char __user *buf, - size_t len, loff_t *off) -{ - struct seq_file *seq = file->private_data; - struct lprocfs_stats *stats = seq->private; - - lprocfs_clear_stats(stats); - - return len; -} - -static void *lprocfs_stats_seq_start(struct seq_file *p, loff_t *pos) -{ - struct lprocfs_stats *stats = p->private; - - return (*pos < stats->ls_num) ? pos : NULL; -} - -static void lprocfs_stats_seq_stop(struct seq_file *p, void *v) -{ -} - -static void *lprocfs_stats_seq_next(struct seq_file *p, void *v, loff_t *pos) -{ - (*pos)++; - return lprocfs_stats_seq_start(p, pos); -} - -/* seq file export of one lprocfs counter */ -static int lprocfs_stats_seq_show(struct seq_file *p, void *v) -{ - struct lprocfs_stats *stats = p->private; - struct lprocfs_counter_header *hdr; - struct lprocfs_counter ctr; - int idx = *(loff_t *)v; - - if (idx == 0) { - struct timespec64 now; - - ktime_get_real_ts64(&now); - seq_printf(p, "%-25s %llu.%9lu secs.usecs\n", - "snapshot_time", - (s64)now.tv_sec, (unsigned long)now.tv_nsec); - } - - hdr = &stats->ls_cnt_header[idx]; - lprocfs_stats_collect(stats, idx, &ctr); - - if (ctr.lc_count != 0) { - seq_printf(p, "%-25s %lld samples [%s]", - hdr->lc_name, ctr.lc_count, hdr->lc_units); - - if ((hdr->lc_config & LPROCFS_CNTR_AVGMINMAX) && - (ctr.lc_count > 0)) { - seq_printf(p, " %lld %lld %lld", - ctr.lc_min, ctr.lc_max, ctr.lc_sum); - if (hdr->lc_config & LPROCFS_CNTR_STDDEV) - seq_printf(p, " %lld", ctr.lc_sumsquare); - } - seq_putc(p, '\n'); - } - - return 0; -} - -static const struct seq_operations lprocfs_stats_seq_sops = { - .start = lprocfs_stats_seq_start, - .stop = lprocfs_stats_seq_stop, - .next = lprocfs_stats_seq_next, - .show = lprocfs_stats_seq_show, -}; - -static int lprocfs_stats_seq_open(struct inode *inode, struct file *file) -{ - struct seq_file *seq; - int rc; - - rc = seq_open(file, &lprocfs_stats_seq_sops); - if (rc) - return rc; - - seq = file->private_data; - seq->private = inode->i_private; - - return 0; -} - -static const struct file_operations lprocfs_stats_seq_fops = { - .owner = THIS_MODULE, - .open = lprocfs_stats_seq_open, - .read = seq_read, - .write = lprocfs_stats_seq_write, - .llseek = seq_lseek, - .release = lprocfs_seq_release, -}; - -int ldebugfs_register_stats(struct dentry *parent, const char *name, - struct lprocfs_stats *stats) -{ - struct dentry *entry; - - LASSERT(!IS_ERR_OR_NULL(parent)); - - entry = debugfs_create_file(name, 0644, parent, stats, - &lprocfs_stats_seq_fops); - if (IS_ERR_OR_NULL(entry)) - return entry ? PTR_ERR(entry) : -ENOMEM; - - return 0; -} -EXPORT_SYMBOL_GPL(ldebugfs_register_stats); - -void lprocfs_counter_init(struct lprocfs_stats *stats, int index, - unsigned int conf, const char *name, - const char *units) -{ - struct lprocfs_counter_header *header; - struct lprocfs_counter *percpu_cntr; - unsigned long flags = 0; - unsigned int i; - unsigned int num_cpu; - - header = &stats->ls_cnt_header[index]; - LASSERTF(header, "Failed to allocate stats header:[%d]%s/%s\n", - index, name, units); - - header->lc_config = conf; - header->lc_name = name; - header->lc_units = units; - - num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU, &flags); - for (i = 0; i < num_cpu; ++i) { - if (!stats->ls_percpu[i]) - continue; - percpu_cntr = lprocfs_stats_counter_get(stats, i, index); - percpu_cntr->lc_count = 0; - percpu_cntr->lc_min = LC_MIN_INIT; - percpu_cntr->lc_max = 0; - percpu_cntr->lc_sumsquare = 0; - percpu_cntr->lc_sum = 0; - if ((stats->ls_flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0) - percpu_cntr->lc_sum_irq = 0; - } - lprocfs_stats_unlock(stats, LPROCFS_GET_NUM_CPU, &flags); -} -EXPORT_SYMBOL(lprocfs_counter_init); - -int lprocfs_exp_cleanup(struct obd_export *exp) -{ - return 0; -} -EXPORT_SYMBOL(lprocfs_exp_cleanup); - -__s64 lprocfs_read_helper(struct lprocfs_counter *lc, - struct lprocfs_counter_header *header, - enum lprocfs_stats_flags flags, - enum lprocfs_fields_flags field) -{ - __s64 ret = 0; - - if (!lc || !header) - return 0; - - switch (field) { - case LPROCFS_FIELDS_FLAGS_CONFIG: - ret = header->lc_config; - break; - case LPROCFS_FIELDS_FLAGS_SUM: - ret = lc->lc_sum; - if ((flags & LPROCFS_STATS_FLAG_IRQ_SAFE) != 0) - ret += lc->lc_sum_irq; - break; - case LPROCFS_FIELDS_FLAGS_MIN: - ret = lc->lc_min; - break; - case LPROCFS_FIELDS_FLAGS_MAX: - ret = lc->lc_max; - break; - case LPROCFS_FIELDS_FLAGS_AVG: - ret = (lc->lc_max - lc->lc_min) / 2; - break; - case LPROCFS_FIELDS_FLAGS_SUMSQUARE: - ret = lc->lc_sumsquare; - break; - case LPROCFS_FIELDS_FLAGS_COUNT: - ret = lc->lc_count; - break; - default: - break; - } - - return 0; -} -EXPORT_SYMBOL(lprocfs_read_helper); - -int lprocfs_write_helper(const char __user *buffer, unsigned long count, - int *val) -{ - return lprocfs_write_frac_helper(buffer, count, val, 1); -} -EXPORT_SYMBOL(lprocfs_write_helper); - -int lprocfs_write_u64_helper(const char __user *buffer, unsigned long count, - __u64 *val) -{ - return lprocfs_write_frac_u64_helper(buffer, count, val, 1); -} -EXPORT_SYMBOL(lprocfs_write_u64_helper); - -int lprocfs_write_frac_u64_helper(const char __user *buffer, - unsigned long count, __u64 *val, int mult) -{ - char kernbuf[22], *end, *pbuf; - __u64 whole, frac = 0, units; - unsigned int frac_d = 1; - int sign = 1; - - if (count > (sizeof(kernbuf) - 1)) - return -EINVAL; - - if (copy_from_user(kernbuf, buffer, count)) - return -EFAULT; - - kernbuf[count] = '\0'; - pbuf = kernbuf; - if (*pbuf == '-') { - sign = -1; - pbuf++; - } - - whole = simple_strtoull(pbuf, &end, 10); - if (pbuf == end) - return -EINVAL; - - if (*end == '.') { - int i; - - pbuf = end + 1; - - /* need to limit frac_d to a __u32 */ - if (strlen(pbuf) > 10) - pbuf[10] = '\0'; - - frac = simple_strtoull(pbuf, &end, 10); - /* count decimal places */ - for (i = 0; i < (end - pbuf); i++) - frac_d *= 10; - } - - units = 1; - if (end) { - switch (tolower(*end)) { - case 'p': - units <<= 10; - /* fall through */ - case 't': - units <<= 10; - /* fall through */ - case 'g': - units <<= 10; - /* fall through */ - case 'm': - units <<= 10; - /* fall through */ - case 'k': - units <<= 10; - } - } - /* Specified units override the multiplier */ - if (units > 1) - mult = units; - - frac *= mult; - do_div(frac, frac_d); - *val = sign * (whole * mult + frac); - return 0; -} -EXPORT_SYMBOL(lprocfs_write_frac_u64_helper); - -static char *lprocfs_strnstr(const char *s1, const char *s2, size_t len) -{ - size_t l2; - - l2 = strlen(s2); - if (!l2) - return (char *)s1; - while (len >= l2) { - len--; - if (!memcmp(s1, s2, l2)) - return (char *)s1; - s1++; - } - return NULL; -} - -/** - * Find the string \a name in the input \a buffer, and return a pointer to the - * value immediately following \a name, reducing \a count appropriately. - * If \a name is not found the original \a buffer is returned. - */ -char *lprocfs_find_named_value(const char *buffer, const char *name, - size_t *count) -{ - char *val; - size_t buflen = *count; - - /* there is no strnstr() in rhel5 and ubuntu kernels */ - val = lprocfs_strnstr(buffer, name, buflen); - if (!val) - return (char *)buffer; - - val += strlen(name); /* skip prefix */ - while (val < buffer + buflen && isspace(*val)) /* skip separator */ - val++; - - *count = 0; - while (val < buffer + buflen && isalnum(*val)) { - ++*count; - ++val; - } - - return val - *count; -} -EXPORT_SYMBOL(lprocfs_find_named_value); - -int ldebugfs_seq_create(struct dentry *parent, const char *name, - umode_t mode, const struct file_operations *seq_fops, - void *data) -{ - struct dentry *entry; - - /* Disallow secretly (un)writable entries. */ - LASSERT((!seq_fops->write) == ((mode & 0222) == 0)); - - entry = debugfs_create_file(name, mode, parent, data, seq_fops); - if (IS_ERR_OR_NULL(entry)) - return entry ? PTR_ERR(entry) : -ENOMEM; - - return 0; -} -EXPORT_SYMBOL_GPL(ldebugfs_seq_create); - -int ldebugfs_obd_seq_create(struct obd_device *dev, - const char *name, - umode_t mode, - const struct file_operations *seq_fops, - void *data) -{ - return ldebugfs_seq_create(dev->obd_debugfs_entry, name, - mode, seq_fops, data); -} -EXPORT_SYMBOL_GPL(ldebugfs_obd_seq_create); - -void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value) -{ - if (value >= OBD_HIST_MAX) - value = OBD_HIST_MAX - 1; - - spin_lock(&oh->oh_lock); - oh->oh_buckets[value]++; - spin_unlock(&oh->oh_lock); -} -EXPORT_SYMBOL(lprocfs_oh_tally); - -void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value) -{ - unsigned int val = 0; - - if (likely(value != 0)) - val = min(fls(value - 1), OBD_HIST_MAX); - - lprocfs_oh_tally(oh, val); -} -EXPORT_SYMBOL(lprocfs_oh_tally_log2); - -unsigned long lprocfs_oh_sum(struct obd_histogram *oh) -{ - unsigned long ret = 0; - int i; - - for (i = 0; i < OBD_HIST_MAX; i++) - ret += oh->oh_buckets[i]; - return ret; -} -EXPORT_SYMBOL(lprocfs_oh_sum); - -void lprocfs_oh_clear(struct obd_histogram *oh) -{ - spin_lock(&oh->oh_lock); - memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets)); - spin_unlock(&oh->oh_lock); -} -EXPORT_SYMBOL(lprocfs_oh_clear); - -int lprocfs_wr_root_squash(const char __user *buffer, unsigned long count, - struct root_squash_info *squash, char *name) -{ - char kernbuf[64], *tmp, *errmsg; - unsigned long uid, gid; - int rc; - - if (count >= sizeof(kernbuf)) { - errmsg = "string too long"; - rc = -EINVAL; - goto failed_noprint; - } - if (copy_from_user(kernbuf, buffer, count)) { - errmsg = "bad address"; - rc = -EFAULT; - goto failed_noprint; - } - kernbuf[count] = '\0'; - - /* look for uid gid separator */ - tmp = strchr(kernbuf, ':'); - if (!tmp) { - errmsg = "needs uid:gid format"; - rc = -EINVAL; - goto failed; - } - *tmp = '\0'; - tmp++; - - /* parse uid */ - if (kstrtoul(kernbuf, 0, &uid) != 0) { - errmsg = "bad uid"; - rc = -EINVAL; - goto failed; - } - /* parse gid */ - if (kstrtoul(tmp, 0, &gid) != 0) { - errmsg = "bad gid"; - rc = -EINVAL; - goto failed; - } - - squash->rsi_uid = uid; - squash->rsi_gid = gid; - - LCONSOLE_INFO("%s: root_squash is set to %u:%u\n", - name, squash->rsi_uid, squash->rsi_gid); - return count; - -failed: - if (tmp) { - tmp--; - *tmp = ':'; - } - CWARN("%s: failed to set root_squash to \"%s\", %s, rc = %d\n", - name, kernbuf, errmsg, rc); - return rc; -failed_noprint: - CWARN("%s: failed to set root_squash due to %s, rc = %d\n", - name, errmsg, rc); - return rc; -} -EXPORT_SYMBOL(lprocfs_wr_root_squash); - -int lprocfs_wr_nosquash_nids(const char __user *buffer, unsigned long count, - struct root_squash_info *squash, char *name) -{ - char *kernbuf = NULL, *errmsg; - struct list_head tmp; - int len = count; - int rc; - - if (count > 4096) { - errmsg = "string too long"; - rc = -EINVAL; - goto failed; - } - - kernbuf = kzalloc(count + 1, GFP_NOFS); - if (!kernbuf) { - errmsg = "no memory"; - rc = -ENOMEM; - goto failed; - } - - if (copy_from_user(kernbuf, buffer, count)) { - errmsg = "bad address"; - rc = -EFAULT; - goto failed; - } - kernbuf[count] = '\0'; - - if (count > 0 && kernbuf[count - 1] == '\n') - len = count - 1; - - if ((len == 4 && !strncmp(kernbuf, "NONE", len)) || - (len == 5 && !strncmp(kernbuf, "clear", len))) { - /* empty string is special case */ - down_write(&squash->rsi_sem); - if (!list_empty(&squash->rsi_nosquash_nids)) - cfs_free_nidlist(&squash->rsi_nosquash_nids); - up_write(&squash->rsi_sem); - LCONSOLE_INFO("%s: nosquash_nids is cleared\n", name); - kfree(kernbuf); - return count; - } - - INIT_LIST_HEAD(&tmp); - if (cfs_parse_nidlist(kernbuf, count, &tmp) <= 0) { - errmsg = "can't parse"; - rc = -EINVAL; - goto failed; - } - LCONSOLE_INFO("%s: nosquash_nids set to %s\n", - name, kernbuf); - kfree(kernbuf); - kernbuf = NULL; - - down_write(&squash->rsi_sem); - if (!list_empty(&squash->rsi_nosquash_nids)) - cfs_free_nidlist(&squash->rsi_nosquash_nids); - list_splice(&tmp, &squash->rsi_nosquash_nids); - up_write(&squash->rsi_sem); - - return count; - -failed: - if (kernbuf) { - CWARN("%s: failed to set nosquash_nids to \"%s\", %s rc = %d\n", - name, kernbuf, errmsg, rc); - kfree(kernbuf); - kernbuf = NULL; - } else { - CWARN("%s: failed to set nosquash_nids due to %s rc = %d\n", - name, errmsg, rc); - } - return rc; -} -EXPORT_SYMBOL(lprocfs_wr_nosquash_nids); - -static ssize_t lustre_attr_show(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - struct lustre_attr *a = container_of(attr, struct lustre_attr, attr); - - return a->show ? a->show(kobj, attr, buf) : 0; -} - -static ssize_t lustre_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t len) -{ - struct lustre_attr *a = container_of(attr, struct lustre_attr, attr); - - return a->store ? a->store(kobj, attr, buf, len) : len; -} - -const struct sysfs_ops lustre_sysfs_ops = { - .show = lustre_attr_show, - .store = lustre_attr_store, -}; -EXPORT_SYMBOL_GPL(lustre_sysfs_ops); diff --git a/drivers/staging/lustre/lustre/obdclass/lu_object.c b/drivers/staging/lustre/lustre/obdclass/lu_object.c deleted file mode 100644 index 3ae16e8501c2..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/lu_object.c +++ /dev/null @@ -1,2058 +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) 2007, 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. - * - * lustre/obdclass/lu_object.c - * - * Lustre Object. - * These are the only exported functions, they provide some generic - * infrastructure for managing object devices - * - * Author: Nikita Danilov <nikita.danilov@sun.com> - */ - -#define DEBUG_SUBSYSTEM S_CLASS - -#include <linux/libcfs/libcfs.h> - -#include <linux/module.h> - -/* hash_long() */ -#include <linux/libcfs/libcfs_hash.h> -#include <obd_class.h> -#include <obd_support.h> -#include <lustre_disk.h> -#include <lustre_fid.h> -#include <lu_object.h> -#include <cl_object.h> -#include <lu_ref.h> -#include <linux/list.h> - -enum { - LU_CACHE_PERCENT_MAX = 50, - LU_CACHE_PERCENT_DEFAULT = 20 -}; - -#define LU_CACHE_NR_MAX_ADJUST 512 -#define LU_CACHE_NR_UNLIMITED -1 -#define LU_CACHE_NR_DEFAULT LU_CACHE_NR_UNLIMITED -#define LU_CACHE_NR_LDISKFS_LIMIT LU_CACHE_NR_UNLIMITED -#define LU_CACHE_NR_ZFS_LIMIT 256 - -#define LU_SITE_BITS_MIN 12 -#define LU_SITE_BITS_MAX 24 -#define LU_SITE_BITS_MAX_CL 19 -/** - * total 256 buckets, we don't want too many buckets because: - * - consume too much memory - * - avoid unbalanced LRU list - */ -#define LU_SITE_BKT_BITS 8 - -static unsigned int lu_cache_percent = LU_CACHE_PERCENT_DEFAULT; -module_param(lu_cache_percent, int, 0644); -MODULE_PARM_DESC(lu_cache_percent, "Percentage of memory to be used as lu_object cache"); - -static long lu_cache_nr = LU_CACHE_NR_DEFAULT; -module_param(lu_cache_nr, long, 0644); -MODULE_PARM_DESC(lu_cache_nr, "Maximum number of objects in lu_object cache"); - -static void lu_object_free(const struct lu_env *env, struct lu_object *o); -static __u32 ls_stats_read(struct lprocfs_stats *stats, int idx); - -/** - * Decrease reference counter on object. If last reference is freed, return - * object to the cache, unless lu_object_is_dying(o) holds. In the latter - * case, free object immediately. - */ -void lu_object_put(const struct lu_env *env, struct lu_object *o) -{ - struct lu_site_bkt_data *bkt; - struct lu_object_header *top; - struct lu_site *site; - struct lu_object *orig; - struct cfs_hash_bd bd; - const struct lu_fid *fid; - - top = o->lo_header; - site = o->lo_dev->ld_site; - orig = o; - - /* - * till we have full fids-on-OST implemented anonymous objects - * are possible in OSP. such an object isn't listed in the site - * so we should not remove it from the site. - */ - fid = lu_object_fid(o); - if (fid_is_zero(fid)) { - LASSERT(!top->loh_hash.next && !top->loh_hash.pprev); - LASSERT(list_empty(&top->loh_lru)); - if (!atomic_dec_and_test(&top->loh_ref)) - return; - list_for_each_entry_reverse(o, &top->loh_layers, lo_linkage) { - if (o->lo_ops->loo_object_release) - o->lo_ops->loo_object_release(env, o); - } - lu_object_free(env, orig); - return; - } - - cfs_hash_bd_get(site->ls_obj_hash, &top->loh_fid, &bd); - bkt = cfs_hash_bd_extra_get(site->ls_obj_hash, &bd); - - if (!cfs_hash_bd_dec_and_lock(site->ls_obj_hash, &bd, &top->loh_ref)) { - if (lu_object_is_dying(top)) { - /* - * somebody may be waiting for this, currently only - * used for cl_object, see cl_object_put_last(). - */ - wake_up_all(&bkt->lsb_marche_funebre); - } - return; - } - - /* - * When last reference is released, iterate over object - * layers, and notify them that object is no longer busy. - */ - list_for_each_entry_reverse(o, &top->loh_layers, lo_linkage) { - if (o->lo_ops->loo_object_release) - o->lo_ops->loo_object_release(env, o); - } - - if (!lu_object_is_dying(top)) { - LASSERT(list_empty(&top->loh_lru)); - list_add_tail(&top->loh_lru, &bkt->lsb_lru); - bkt->lsb_lru_len++; - percpu_counter_inc(&site->ls_lru_len_counter); - CDEBUG(D_INODE, "Add %p to site lru. hash: %p, bkt: %p, lru_len: %ld\n", - o, site->ls_obj_hash, bkt, bkt->lsb_lru_len); - cfs_hash_bd_unlock(site->ls_obj_hash, &bd, 1); - return; - } - - /* - * If object is dying (will not be cached), then removed it - * from hash table and LRU. - * - * This is done with hash table and LRU lists locked. As the only - * way to acquire first reference to previously unreferenced - * object is through hash-table lookup (lu_object_find()), - * or LRU scanning (lu_site_purge()), that are done under hash-table - * and LRU lock, no race with concurrent object lookup is possible - * and we can safely destroy object below. - */ - if (!test_and_set_bit(LU_OBJECT_UNHASHED, &top->loh_flags)) - cfs_hash_bd_del_locked(site->ls_obj_hash, &bd, &top->loh_hash); - cfs_hash_bd_unlock(site->ls_obj_hash, &bd, 1); - /* - * Object was already removed from hash and lru above, can - * kill it. - */ - lu_object_free(env, orig); -} -EXPORT_SYMBOL(lu_object_put); - -/** - * Kill the object and take it out of LRU cache. - * Currently used by client code for layout change. - */ -void lu_object_unhash(const struct lu_env *env, struct lu_object *o) -{ - struct lu_object_header *top; - - top = o->lo_header; - set_bit(LU_OBJECT_HEARD_BANSHEE, &top->loh_flags); - if (!test_and_set_bit(LU_OBJECT_UNHASHED, &top->loh_flags)) { - struct lu_site *site = o->lo_dev->ld_site; - struct cfs_hash *obj_hash = site->ls_obj_hash; - struct cfs_hash_bd bd; - - cfs_hash_bd_get_and_lock(obj_hash, &top->loh_fid, &bd, 1); - if (!list_empty(&top->loh_lru)) { - struct lu_site_bkt_data *bkt; - - list_del_init(&top->loh_lru); - bkt = cfs_hash_bd_extra_get(obj_hash, &bd); - bkt->lsb_lru_len--; - percpu_counter_dec(&site->ls_lru_len_counter); - } - cfs_hash_bd_del_locked(obj_hash, &bd, &top->loh_hash); - cfs_hash_bd_unlock(obj_hash, &bd, 1); - } -} -EXPORT_SYMBOL(lu_object_unhash); - -/** - * Allocate new object. - * - * This follows object creation protocol, described in the comment within - * struct lu_device_operations definition. - */ -static struct lu_object *lu_object_alloc(const struct lu_env *env, - struct lu_device *dev, - const struct lu_fid *f, - const struct lu_object_conf *conf) -{ - struct lu_object *scan; - struct lu_object *top; - struct list_head *layers; - unsigned int init_mask = 0; - unsigned int init_flag; - int clean; - int result; - - /* - * Create top-level object slice. This will also create - * lu_object_header. - */ - top = dev->ld_ops->ldo_object_alloc(env, NULL, dev); - if (!top) - return ERR_PTR(-ENOMEM); - if (IS_ERR(top)) - return top; - /* - * This is the only place where object fid is assigned. It's constant - * after this point. - */ - top->lo_header->loh_fid = *f; - layers = &top->lo_header->loh_layers; - - do { - /* - * Call ->loo_object_init() repeatedly, until no more new - * object slices are created. - */ - clean = 1; - init_flag = 1; - list_for_each_entry(scan, layers, lo_linkage) { - if (init_mask & init_flag) - goto next; - clean = 0; - scan->lo_header = top->lo_header; - result = scan->lo_ops->loo_object_init(env, scan, conf); - if (result != 0) { - lu_object_free(env, top); - return ERR_PTR(result); - } - init_mask |= init_flag; -next: - init_flag <<= 1; - } - } while (!clean); - - list_for_each_entry_reverse(scan, layers, lo_linkage) { - if (scan->lo_ops->loo_object_start) { - result = scan->lo_ops->loo_object_start(env, scan); - if (result != 0) { - lu_object_free(env, top); - return ERR_PTR(result); - } - } - } - - lprocfs_counter_incr(dev->ld_site->ls_stats, LU_SS_CREATED); - return top; -} - -/** - * Free an object. - */ -static void lu_object_free(const struct lu_env *env, struct lu_object *o) -{ - struct lu_site_bkt_data *bkt; - struct lu_site *site; - struct lu_object *scan; - struct list_head *layers; - struct list_head splice; - - site = o->lo_dev->ld_site; - layers = &o->lo_header->loh_layers; - bkt = lu_site_bkt_from_fid(site, &o->lo_header->loh_fid); - /* - * First call ->loo_object_delete() method to release all resources. - */ - list_for_each_entry_reverse(scan, layers, lo_linkage) { - if (scan->lo_ops->loo_object_delete) - scan->lo_ops->loo_object_delete(env, scan); - } - - /* - * Then, splice object layers into stand-alone list, and call - * ->loo_object_free() on all layers to free memory. Splice is - * necessary, because lu_object_header is freed together with the - * top-level slice. - */ - INIT_LIST_HEAD(&splice); - list_splice_init(layers, &splice); - while (!list_empty(&splice)) { - /* - * Free layers in bottom-to-top order, so that object header - * lives as long as possible and ->loo_object_free() methods - * can look at its contents. - */ - o = container_of0(splice.prev, struct lu_object, lo_linkage); - list_del_init(&o->lo_linkage); - o->lo_ops->loo_object_free(env, o); - } - - if (waitqueue_active(&bkt->lsb_marche_funebre)) - wake_up_all(&bkt->lsb_marche_funebre); -} - -/** - * Free \a nr objects from the cold end of the site LRU list. - * if canblock is false, then don't block awaiting for another - * instance of lu_site_purge() to complete - */ -int lu_site_purge_objects(const struct lu_env *env, struct lu_site *s, - int nr, bool canblock) -{ - struct lu_object_header *h; - struct lu_object_header *temp; - struct lu_site_bkt_data *bkt; - struct cfs_hash_bd bd; - struct cfs_hash_bd bd2; - struct list_head dispose; - int did_sth; - unsigned int start = 0; - int count; - int bnr; - unsigned int i; - - if (OBD_FAIL_CHECK(OBD_FAIL_OBD_NO_LRU)) - return 0; - - INIT_LIST_HEAD(&dispose); - /* - * Under LRU list lock, scan LRU list and move unreferenced objects to - * the dispose list, removing them from LRU and hash table. - */ - if (nr != ~0) - start = s->ls_purge_start; - bnr = (nr == ~0) ? -1 : nr / (int)CFS_HASH_NBKT(s->ls_obj_hash) + 1; - again: - /* - * It doesn't make any sense to make purge threads parallel, that can - * only bring troubles to us. See LU-5331. - */ - if (canblock) - mutex_lock(&s->ls_purge_mutex); - else if (!mutex_trylock(&s->ls_purge_mutex)) - goto out; - - did_sth = 0; - cfs_hash_for_each_bucket(s->ls_obj_hash, &bd, i) { - if (i < start) - continue; - count = bnr; - cfs_hash_bd_lock(s->ls_obj_hash, &bd, 1); - bkt = cfs_hash_bd_extra_get(s->ls_obj_hash, &bd); - - list_for_each_entry_safe(h, temp, &bkt->lsb_lru, loh_lru) { - LASSERT(atomic_read(&h->loh_ref) == 0); - - cfs_hash_bd_get(s->ls_obj_hash, &h->loh_fid, &bd2); - LASSERT(bd.bd_bucket == bd2.bd_bucket); - - cfs_hash_bd_del_locked(s->ls_obj_hash, - &bd2, &h->loh_hash); - list_move(&h->loh_lru, &dispose); - bkt->lsb_lru_len--; - percpu_counter_dec(&s->ls_lru_len_counter); - if (did_sth == 0) - did_sth = 1; - - if (nr != ~0 && --nr == 0) - break; - - if (count > 0 && --count == 0) - break; - } - cfs_hash_bd_unlock(s->ls_obj_hash, &bd, 1); - cond_resched(); - /* - * Free everything on the dispose list. This is safe against - * races due to the reasons described in lu_object_put(). - */ - while (!list_empty(&dispose)) { - h = container_of0(dispose.next, - struct lu_object_header, loh_lru); - list_del_init(&h->loh_lru); - lu_object_free(env, lu_object_top(h)); - lprocfs_counter_incr(s->ls_stats, LU_SS_LRU_PURGED); - } - - if (nr == 0) - break; - } - mutex_unlock(&s->ls_purge_mutex); - - if (nr != 0 && did_sth && start != 0) { - start = 0; /* restart from the first bucket */ - goto again; - } - /* race on s->ls_purge_start, but nobody cares */ - s->ls_purge_start = i % CFS_HASH_NBKT(s->ls_obj_hash); -out: - return nr; -} -EXPORT_SYMBOL(lu_site_purge_objects); - -/* - * Object printing. - * - * Code below has to jump through certain loops to output object description - * into libcfs_debug_msg-based log. The problem is that lu_object_print() - * composes object description from strings that are parts of _lines_ of - * output (i.e., strings that are not terminated by newline). This doesn't fit - * very well into libcfs_debug_msg() interface that assumes that each message - * supplied to it is a self-contained output line. - * - * To work around this, strings are collected in a temporary buffer - * (implemented as a value of lu_cdebug_key key), until terminating newline - * character is detected. - * - */ - -enum { - /** - * Maximal line size. - * - * XXX overflow is not handled correctly. - */ - LU_CDEBUG_LINE = 512 -}; - -struct lu_cdebug_data { - /** - * Temporary buffer. - */ - char lck_area[LU_CDEBUG_LINE]; -}; - -/* context key constructor/destructor: lu_global_key_init, lu_global_key_fini */ -LU_KEY_INIT_FINI(lu_global, struct lu_cdebug_data); - -/** - * Key, holding temporary buffer. This key is registered very early by - * lu_global_init(). - */ -static struct lu_context_key lu_global_key = { - .lct_tags = LCT_MD_THREAD | LCT_DT_THREAD | - LCT_MG_THREAD | LCT_CL_THREAD | LCT_LOCAL, - .lct_init = lu_global_key_init, - .lct_fini = lu_global_key_fini -}; - -/** - * Printer function emitting messages through libcfs_debug_msg(). - */ -int lu_cdebug_printer(const struct lu_env *env, - void *cookie, const char *format, ...) -{ - struct libcfs_debug_msg_data *msgdata = cookie; - struct lu_cdebug_data *key; - int used; - int complete; - va_list args; - - va_start(args, format); - - key = lu_context_key_get(&env->le_ctx, &lu_global_key); - - used = strlen(key->lck_area); - complete = format[strlen(format) - 1] == '\n'; - /* - * Append new chunk to the buffer. - */ - vsnprintf(key->lck_area + used, - ARRAY_SIZE(key->lck_area) - used, format, args); - if (complete) { - if (cfs_cdebug_show(msgdata->msg_mask, msgdata->msg_subsys)) - libcfs_debug_msg(msgdata, "%s\n", key->lck_area); - key->lck_area[0] = 0; - } - va_end(args); - return 0; -} -EXPORT_SYMBOL(lu_cdebug_printer); - -/** - * Print object header. - */ -void lu_object_header_print(const struct lu_env *env, void *cookie, - lu_printer_t printer, - const struct lu_object_header *hdr) -{ - (*printer)(env, cookie, "header@%p[%#lx, %d, " DFID "%s%s%s]", - hdr, hdr->loh_flags, atomic_read(&hdr->loh_ref), - PFID(&hdr->loh_fid), - hlist_unhashed(&hdr->loh_hash) ? "" : " hash", - list_empty((struct list_head *)&hdr->loh_lru) ? \ - "" : " lru", - hdr->loh_attr & LOHA_EXISTS ? " exist":""); -} -EXPORT_SYMBOL(lu_object_header_print); - -/** - * Print human readable representation of the \a o to the \a printer. - */ -void lu_object_print(const struct lu_env *env, void *cookie, - lu_printer_t printer, const struct lu_object *o) -{ - static const char ruler[] = "........................................"; - struct lu_object_header *top; - int depth = 4; - - top = o->lo_header; - lu_object_header_print(env, cookie, printer, top); - (*printer)(env, cookie, "{\n"); - - list_for_each_entry(o, &top->loh_layers, lo_linkage) { - /* - * print `.' \a depth times followed by type name and address - */ - (*printer)(env, cookie, "%*.*s%s@%p", depth, depth, ruler, - o->lo_dev->ld_type->ldt_name, o); - - if (o->lo_ops->loo_object_print) - (*o->lo_ops->loo_object_print)(env, cookie, printer, o); - - (*printer)(env, cookie, "\n"); - } - - (*printer)(env, cookie, "} header@%p\n", top); -} -EXPORT_SYMBOL(lu_object_print); - -static struct lu_object *htable_lookup(struct lu_site *s, - struct cfs_hash_bd *bd, - const struct lu_fid *f, - wait_queue_entry_t *waiter, - __u64 *version) -{ - struct lu_site_bkt_data *bkt; - struct lu_object_header *h; - struct hlist_node *hnode; - __u64 ver = cfs_hash_bd_version_get(bd); - - if (*version == ver) - return ERR_PTR(-ENOENT); - - *version = ver; - bkt = cfs_hash_bd_extra_get(s->ls_obj_hash, bd); - /* cfs_hash_bd_peek_locked is a somehow "internal" function - * of cfs_hash, it doesn't add refcount on object. - */ - hnode = cfs_hash_bd_peek_locked(s->ls_obj_hash, bd, (void *)f); - if (!hnode) { - lprocfs_counter_incr(s->ls_stats, LU_SS_CACHE_MISS); - return ERR_PTR(-ENOENT); - } - - h = container_of0(hnode, struct lu_object_header, loh_hash); - if (likely(!lu_object_is_dying(h))) { - cfs_hash_get(s->ls_obj_hash, hnode); - lprocfs_counter_incr(s->ls_stats, LU_SS_CACHE_HIT); - if (!list_empty(&h->loh_lru)) { - list_del_init(&h->loh_lru); - bkt->lsb_lru_len--; - percpu_counter_dec(&s->ls_lru_len_counter); - } - return lu_object_top(h); - } - - /* - * Lookup found an object being destroyed this object cannot be - * returned (to assure that references to dying objects are eventually - * drained), and moreover, lookup has to wait until object is freed. - */ - - init_waitqueue_entry(waiter, current); - add_wait_queue(&bkt->lsb_marche_funebre, waiter); - set_current_state(TASK_UNINTERRUPTIBLE); - lprocfs_counter_incr(s->ls_stats, LU_SS_CACHE_DEATH_RACE); - return ERR_PTR(-EAGAIN); -} - -/** - * Search cache for an object with the fid \a f. If such object is found, - * return it. Otherwise, create new object, insert it into cache and return - * it. In any case, additional reference is acquired on the returned object. - */ -static struct lu_object *lu_object_find(const struct lu_env *env, - struct lu_device *dev, - const struct lu_fid *f, - const struct lu_object_conf *conf) -{ - return lu_object_find_at(env, dev->ld_site->ls_top_dev, f, conf); -} - -/* - * Limit the lu_object cache to a maximum of lu_cache_nr objects. Because - * the calculation for the number of objects to reclaim is not covered by - * a lock the maximum number of objects is capped by LU_CACHE_MAX_ADJUST. - * This ensures that many concurrent threads will not accidentally purge - * the entire cache. - */ -static void lu_object_limit(const struct lu_env *env, struct lu_device *dev) -{ - __u64 size, nr; - - if (lu_cache_nr == LU_CACHE_NR_UNLIMITED) - return; - - size = cfs_hash_size_get(dev->ld_site->ls_obj_hash); - nr = (__u64)lu_cache_nr; - if (size <= nr) - return; - - lu_site_purge_objects(env, dev->ld_site, - min_t(__u64, size - nr, LU_CACHE_NR_MAX_ADJUST), - false); -} - -static struct lu_object *lu_object_new(const struct lu_env *env, - struct lu_device *dev, - const struct lu_fid *f, - const struct lu_object_conf *conf) -{ - struct lu_object *o; - struct cfs_hash *hs; - struct cfs_hash_bd bd; - - o = lu_object_alloc(env, dev, f, conf); - if (IS_ERR(o)) - return o; - - hs = dev->ld_site->ls_obj_hash; - cfs_hash_bd_get_and_lock(hs, (void *)f, &bd, 1); - cfs_hash_bd_add_locked(hs, &bd, &o->lo_header->loh_hash); - cfs_hash_bd_unlock(hs, &bd, 1); - - lu_object_limit(env, dev); - - return o; -} - -/** - * Core logic of lu_object_find*() functions. - */ -static struct lu_object *lu_object_find_try(const struct lu_env *env, - struct lu_device *dev, - const struct lu_fid *f, - const struct lu_object_conf *conf, - wait_queue_entry_t *waiter) -{ - struct lu_object *o; - struct lu_object *shadow; - struct lu_site *s; - struct cfs_hash *hs; - struct cfs_hash_bd bd; - __u64 version = 0; - - /* - * This uses standard index maintenance protocol: - * - * - search index under lock, and return object if found; - * - otherwise, unlock index, allocate new object; - * - lock index and search again; - * - if nothing is found (usual case), insert newly created - * object into index; - * - otherwise (race: other thread inserted object), free - * object just allocated. - * - unlock index; - * - return object. - * - * For "LOC_F_NEW" case, we are sure the object is new established. - * It is unnecessary to perform lookup-alloc-lookup-insert, instead, - * just alloc and insert directly. - * - * If dying object is found during index search, add @waiter to the - * site wait-queue and return ERR_PTR(-EAGAIN). - */ - if (conf && conf->loc_flags & LOC_F_NEW) - return lu_object_new(env, dev, f, conf); - - s = dev->ld_site; - hs = s->ls_obj_hash; - cfs_hash_bd_get_and_lock(hs, (void *)f, &bd, 1); - o = htable_lookup(s, &bd, f, waiter, &version); - cfs_hash_bd_unlock(hs, &bd, 1); - if (!IS_ERR(o) || PTR_ERR(o) != -ENOENT) - return o; - - /* - * Allocate new object. This may result in rather complicated - * operations, including fld queries, inode loading, etc. - */ - o = lu_object_alloc(env, dev, f, conf); - if (IS_ERR(o)) - return o; - - LASSERT(lu_fid_eq(lu_object_fid(o), f)); - - cfs_hash_bd_lock(hs, &bd, 1); - - shadow = htable_lookup(s, &bd, f, waiter, &version); - if (likely(PTR_ERR(shadow) == -ENOENT)) { - cfs_hash_bd_add_locked(hs, &bd, &o->lo_header->loh_hash); - cfs_hash_bd_unlock(hs, &bd, 1); - - lu_object_limit(env, dev); - - return o; - } - - lprocfs_counter_incr(s->ls_stats, LU_SS_CACHE_RACE); - cfs_hash_bd_unlock(hs, &bd, 1); - lu_object_free(env, o); - return shadow; -} - -/** - * Much like lu_object_find(), but top level device of object is specifically - * \a dev rather than top level device of the site. This interface allows - * objects of different "stacking" to be created within the same site. - */ -struct lu_object *lu_object_find_at(const struct lu_env *env, - struct lu_device *dev, - const struct lu_fid *f, - const struct lu_object_conf *conf) -{ - struct lu_site_bkt_data *bkt; - struct lu_object *obj; - wait_queue_entry_t wait; - - while (1) { - obj = lu_object_find_try(env, dev, f, conf, &wait); - if (obj != ERR_PTR(-EAGAIN)) - return obj; - /* - * lu_object_find_try() already added waiter into the - * wait queue. - */ - schedule(); - bkt = lu_site_bkt_from_fid(dev->ld_site, (void *)f); - remove_wait_queue(&bkt->lsb_marche_funebre, &wait); - } -} -EXPORT_SYMBOL(lu_object_find_at); - -/** - * Find object with given fid, and return its slice belonging to given device. - */ -struct lu_object *lu_object_find_slice(const struct lu_env *env, - struct lu_device *dev, - const struct lu_fid *f, - const struct lu_object_conf *conf) -{ - struct lu_object *top; - struct lu_object *obj; - - top = lu_object_find(env, dev, f, conf); - if (IS_ERR(top)) - return top; - - obj = lu_object_locate(top->lo_header, dev->ld_type); - if (unlikely(!obj)) { - lu_object_put(env, top); - obj = ERR_PTR(-ENOENT); - } - - return obj; -} -EXPORT_SYMBOL(lu_object_find_slice); - -/** - * Global list of all device types. - */ -static LIST_HEAD(lu_device_types); - -int lu_device_type_init(struct lu_device_type *ldt) -{ - int result = 0; - - atomic_set(&ldt->ldt_device_nr, 0); - INIT_LIST_HEAD(&ldt->ldt_linkage); - if (ldt->ldt_ops->ldto_init) - result = ldt->ldt_ops->ldto_init(ldt); - - if (!result) { - spin_lock(&obd_types_lock); - list_add(&ldt->ldt_linkage, &lu_device_types); - spin_unlock(&obd_types_lock); - } - - return result; -} -EXPORT_SYMBOL(lu_device_type_init); - -void lu_device_type_fini(struct lu_device_type *ldt) -{ - spin_lock(&obd_types_lock); - list_del_init(&ldt->ldt_linkage); - spin_unlock(&obd_types_lock); - if (ldt->ldt_ops->ldto_fini) - ldt->ldt_ops->ldto_fini(ldt); -} -EXPORT_SYMBOL(lu_device_type_fini); - -/** - * Global list of all sites on this node - */ -static LIST_HEAD(lu_sites); -static DECLARE_RWSEM(lu_sites_guard); - -/** - * Global environment used by site shrinker. - */ -static struct lu_env lu_shrink_env; - -struct lu_site_print_arg { - struct lu_env *lsp_env; - void *lsp_cookie; - lu_printer_t lsp_printer; -}; - -static int -lu_site_obj_print(struct cfs_hash *hs, struct cfs_hash_bd *bd, - struct hlist_node *hnode, void *data) -{ - struct lu_site_print_arg *arg = (struct lu_site_print_arg *)data; - struct lu_object_header *h; - - h = hlist_entry(hnode, struct lu_object_header, loh_hash); - if (!list_empty(&h->loh_layers)) { - const struct lu_object *o; - - o = lu_object_top(h); - lu_object_print(arg->lsp_env, arg->lsp_cookie, - arg->lsp_printer, o); - } else { - lu_object_header_print(arg->lsp_env, arg->lsp_cookie, - arg->lsp_printer, h); - } - return 0; -} - -/** - * Print all objects in \a s. - */ -void lu_site_print(const struct lu_env *env, struct lu_site *s, void *cookie, - lu_printer_t printer) -{ - struct lu_site_print_arg arg = { - .lsp_env = (struct lu_env *)env, - .lsp_cookie = cookie, - .lsp_printer = printer, - }; - - cfs_hash_for_each(s->ls_obj_hash, lu_site_obj_print, &arg); -} -EXPORT_SYMBOL(lu_site_print); - -/** - * Return desired hash table order. - */ -static unsigned long lu_htable_order(struct lu_device *top) -{ - unsigned long bits_max = LU_SITE_BITS_MAX; - unsigned long cache_size; - unsigned long bits; - - if (!strcmp(top->ld_type->ldt_name, LUSTRE_VVP_NAME)) - bits_max = LU_SITE_BITS_MAX_CL; - - /* - * Calculate hash table size, assuming that we want reasonable - * performance when 20% of total memory is occupied by cache of - * lu_objects. - * - * Size of lu_object is (arbitrary) taken as 1K (together with inode). - */ - cache_size = totalram_pages; - -#if BITS_PER_LONG == 32 - /* limit hashtable size for lowmem systems to low RAM */ - if (cache_size > 1 << (30 - PAGE_SHIFT)) - cache_size = 1 << (30 - PAGE_SHIFT) * 3 / 4; -#endif - - /* clear off unreasonable cache setting. */ - if (lu_cache_percent == 0 || lu_cache_percent > LU_CACHE_PERCENT_MAX) { - CWARN("obdclass: invalid lu_cache_percent: %u, it must be in the range of (0, %u]. Will use default value: %u.\n", - lu_cache_percent, LU_CACHE_PERCENT_MAX, - LU_CACHE_PERCENT_DEFAULT); - - lu_cache_percent = LU_CACHE_PERCENT_DEFAULT; - } - cache_size = cache_size / 100 * lu_cache_percent * - (PAGE_SIZE / 1024); - - for (bits = 1; (1 << bits) < cache_size; ++bits) - ; - return clamp_t(typeof(bits), bits, LU_SITE_BITS_MIN, bits_max); -} - -static unsigned int lu_obj_hop_hash(struct cfs_hash *hs, - const void *key, unsigned int mask) -{ - struct lu_fid *fid = (struct lu_fid *)key; - __u32 hash; - - hash = fid_flatten32(fid); - hash += (hash >> 4) + (hash << 12); /* mixing oid and seq */ - hash = hash_long(hash, hs->hs_bkt_bits); - - /* give me another random factor */ - hash -= hash_long((unsigned long)hs, fid_oid(fid) % 11 + 3); - - hash <<= hs->hs_cur_bits - hs->hs_bkt_bits; - hash |= (fid_seq(fid) + fid_oid(fid)) & (CFS_HASH_NBKT(hs) - 1); - - return hash & mask; -} - -static void *lu_obj_hop_object(struct hlist_node *hnode) -{ - return hlist_entry(hnode, struct lu_object_header, loh_hash); -} - -static void *lu_obj_hop_key(struct hlist_node *hnode) -{ - struct lu_object_header *h; - - h = hlist_entry(hnode, struct lu_object_header, loh_hash); - return &h->loh_fid; -} - -static int lu_obj_hop_keycmp(const void *key, struct hlist_node *hnode) -{ - struct lu_object_header *h; - - h = hlist_entry(hnode, struct lu_object_header, loh_hash); - return lu_fid_eq(&h->loh_fid, (struct lu_fid *)key); -} - -static void lu_obj_hop_get(struct cfs_hash *hs, struct hlist_node *hnode) -{ - struct lu_object_header *h; - - h = hlist_entry(hnode, struct lu_object_header, loh_hash); - atomic_inc(&h->loh_ref); -} - -static void lu_obj_hop_put_locked(struct cfs_hash *hs, struct hlist_node *hnode) -{ - LBUG(); /* we should never called it */ -} - -static struct cfs_hash_ops lu_site_hash_ops = { - .hs_hash = lu_obj_hop_hash, - .hs_key = lu_obj_hop_key, - .hs_keycmp = lu_obj_hop_keycmp, - .hs_object = lu_obj_hop_object, - .hs_get = lu_obj_hop_get, - .hs_put_locked = lu_obj_hop_put_locked, -}; - -static void lu_dev_add_linkage(struct lu_site *s, struct lu_device *d) -{ - spin_lock(&s->ls_ld_lock); - if (list_empty(&d->ld_linkage)) - list_add(&d->ld_linkage, &s->ls_ld_linkage); - spin_unlock(&s->ls_ld_lock); -} - -/** - * Initialize site \a s, with \a d as the top level device. - */ -int lu_site_init(struct lu_site *s, struct lu_device *top) -{ - struct lu_site_bkt_data *bkt; - struct cfs_hash_bd bd; - unsigned long bits; - unsigned long i; - char name[16]; - int rc; - - memset(s, 0, sizeof(*s)); - mutex_init(&s->ls_purge_mutex); - - rc = percpu_counter_init(&s->ls_lru_len_counter, 0, GFP_NOFS); - if (rc) - return -ENOMEM; - - snprintf(name, sizeof(name), "lu_site_%s", top->ld_type->ldt_name); - for (bits = lu_htable_order(top); bits >= LU_SITE_BITS_MIN; bits--) { - s->ls_obj_hash = cfs_hash_create(name, bits, bits, - bits - LU_SITE_BKT_BITS, - sizeof(*bkt), 0, 0, - &lu_site_hash_ops, - CFS_HASH_SPIN_BKTLOCK | - CFS_HASH_NO_ITEMREF | - CFS_HASH_DEPTH | - CFS_HASH_ASSERT_EMPTY | - CFS_HASH_COUNTER); - if (s->ls_obj_hash) - break; - } - - if (!s->ls_obj_hash) { - CERROR("failed to create lu_site hash with bits: %lu\n", bits); - return -ENOMEM; - } - - cfs_hash_for_each_bucket(s->ls_obj_hash, &bd, i) { - bkt = cfs_hash_bd_extra_get(s->ls_obj_hash, &bd); - INIT_LIST_HEAD(&bkt->lsb_lru); - init_waitqueue_head(&bkt->lsb_marche_funebre); - } - - s->ls_stats = lprocfs_alloc_stats(LU_SS_LAST_STAT, 0); - if (!s->ls_stats) { - cfs_hash_putref(s->ls_obj_hash); - s->ls_obj_hash = NULL; - return -ENOMEM; - } - - lprocfs_counter_init(s->ls_stats, LU_SS_CREATED, - 0, "created", "created"); - lprocfs_counter_init(s->ls_stats, LU_SS_CACHE_HIT, - 0, "cache_hit", "cache_hit"); - lprocfs_counter_init(s->ls_stats, LU_SS_CACHE_MISS, - 0, "cache_miss", "cache_miss"); - lprocfs_counter_init(s->ls_stats, LU_SS_CACHE_RACE, - 0, "cache_race", "cache_race"); - lprocfs_counter_init(s->ls_stats, LU_SS_CACHE_DEATH_RACE, - 0, "cache_death_race", "cache_death_race"); - lprocfs_counter_init(s->ls_stats, LU_SS_LRU_PURGED, - 0, "lru_purged", "lru_purged"); - - INIT_LIST_HEAD(&s->ls_linkage); - s->ls_top_dev = top; - top->ld_site = s; - lu_device_get(top); - lu_ref_add(&top->ld_reference, "site-top", s); - - INIT_LIST_HEAD(&s->ls_ld_linkage); - spin_lock_init(&s->ls_ld_lock); - - lu_dev_add_linkage(s, top); - - return 0; -} -EXPORT_SYMBOL(lu_site_init); - -/** - * Finalize \a s and release its resources. - */ -void lu_site_fini(struct lu_site *s) -{ - down_write(&lu_sites_guard); - list_del_init(&s->ls_linkage); - up_write(&lu_sites_guard); - - percpu_counter_destroy(&s->ls_lru_len_counter); - - if (s->ls_obj_hash) { - cfs_hash_putref(s->ls_obj_hash); - s->ls_obj_hash = NULL; - } - - if (s->ls_top_dev) { - s->ls_top_dev->ld_site = NULL; - lu_ref_del(&s->ls_top_dev->ld_reference, "site-top", s); - lu_device_put(s->ls_top_dev); - s->ls_top_dev = NULL; - } - - if (s->ls_stats) - lprocfs_free_stats(&s->ls_stats); -} -EXPORT_SYMBOL(lu_site_fini); - -/** - * Called when initialization of stack for this site is completed. - */ -int lu_site_init_finish(struct lu_site *s) -{ - int result; - - down_write(&lu_sites_guard); - result = lu_context_refill(&lu_shrink_env.le_ctx); - if (result == 0) - list_add(&s->ls_linkage, &lu_sites); - up_write(&lu_sites_guard); - return result; -} -EXPORT_SYMBOL(lu_site_init_finish); - -/** - * Acquire additional reference on device \a d - */ -void lu_device_get(struct lu_device *d) -{ - atomic_inc(&d->ld_ref); -} -EXPORT_SYMBOL(lu_device_get); - -/** - * Release reference on device \a d. - */ -void lu_device_put(struct lu_device *d) -{ - LASSERT(atomic_read(&d->ld_ref) > 0); - atomic_dec(&d->ld_ref); -} -EXPORT_SYMBOL(lu_device_put); - -/** - * Initialize device \a d of type \a t. - */ -int lu_device_init(struct lu_device *d, struct lu_device_type *t) -{ - if (atomic_inc_return(&t->ldt_device_nr) == 1 && - t->ldt_ops->ldto_start) - t->ldt_ops->ldto_start(t); - - memset(d, 0, sizeof(*d)); - atomic_set(&d->ld_ref, 0); - d->ld_type = t; - lu_ref_init(&d->ld_reference); - INIT_LIST_HEAD(&d->ld_linkage); - return 0; -} -EXPORT_SYMBOL(lu_device_init); - -/** - * Finalize device \a d. - */ -void lu_device_fini(struct lu_device *d) -{ - struct lu_device_type *t = d->ld_type; - - if (d->ld_obd) { - d->ld_obd->obd_lu_dev = NULL; - d->ld_obd = NULL; - } - - lu_ref_fini(&d->ld_reference); - LASSERTF(atomic_read(&d->ld_ref) == 0, - "Refcount is %u\n", atomic_read(&d->ld_ref)); - LASSERT(atomic_read(&t->ldt_device_nr) > 0); - - if (atomic_dec_and_test(&t->ldt_device_nr) && - t->ldt_ops->ldto_stop) - t->ldt_ops->ldto_stop(t); -} -EXPORT_SYMBOL(lu_device_fini); - -/** - * Initialize object \a o that is part of compound object \a h and was created - * by device \a d. - */ -int lu_object_init(struct lu_object *o, struct lu_object_header *h, - struct lu_device *d) -{ - memset(o, 0, sizeof(*o)); - o->lo_header = h; - o->lo_dev = d; - lu_device_get(d); - lu_ref_add_at(&d->ld_reference, &o->lo_dev_ref, "lu_object", o); - INIT_LIST_HEAD(&o->lo_linkage); - - return 0; -} -EXPORT_SYMBOL(lu_object_init); - -/** - * Finalize object and release its resources. - */ -void lu_object_fini(struct lu_object *o) -{ - struct lu_device *dev = o->lo_dev; - - LASSERT(list_empty(&o->lo_linkage)); - - if (dev) { - lu_ref_del_at(&dev->ld_reference, &o->lo_dev_ref, - "lu_object", o); - lu_device_put(dev); - o->lo_dev = NULL; - } -} -EXPORT_SYMBOL(lu_object_fini); - -/** - * Add object \a o as first layer of compound object \a h - * - * This is typically called by the ->ldo_object_alloc() method of top-level - * device. - */ -void lu_object_add_top(struct lu_object_header *h, struct lu_object *o) -{ - list_move(&o->lo_linkage, &h->loh_layers); -} -EXPORT_SYMBOL(lu_object_add_top); - -/** - * Add object \a o as a layer of compound object, going after \a before. - * - * This is typically called by the ->ldo_object_alloc() method of \a - * before->lo_dev. - */ -void lu_object_add(struct lu_object *before, struct lu_object *o) -{ - list_move(&o->lo_linkage, &before->lo_linkage); -} -EXPORT_SYMBOL(lu_object_add); - -/** - * Initialize compound object. - */ -int lu_object_header_init(struct lu_object_header *h) -{ - memset(h, 0, sizeof(*h)); - atomic_set(&h->loh_ref, 1); - INIT_HLIST_NODE(&h->loh_hash); - INIT_LIST_HEAD(&h->loh_lru); - INIT_LIST_HEAD(&h->loh_layers); - lu_ref_init(&h->loh_reference); - return 0; -} -EXPORT_SYMBOL(lu_object_header_init); - -/** - * Finalize compound object. - */ -void lu_object_header_fini(struct lu_object_header *h) -{ - LASSERT(list_empty(&h->loh_layers)); - LASSERT(list_empty(&h->loh_lru)); - LASSERT(hlist_unhashed(&h->loh_hash)); - lu_ref_fini(&h->loh_reference); -} -EXPORT_SYMBOL(lu_object_header_fini); - -/** - * Given a compound object, find its slice, corresponding to the device type - * \a dtype. - */ -struct lu_object *lu_object_locate(struct lu_object_header *h, - const struct lu_device_type *dtype) -{ - struct lu_object *o; - - list_for_each_entry(o, &h->loh_layers, lo_linkage) { - if (o->lo_dev->ld_type == dtype) - return o; - } - return NULL; -} -EXPORT_SYMBOL(lu_object_locate); - -/** - * Finalize and free devices in the device stack. - * - * Finalize device stack by purging object cache, and calling - * lu_device_type_operations::ldto_device_fini() and - * lu_device_type_operations::ldto_device_free() on all devices in the stack. - */ -void lu_stack_fini(const struct lu_env *env, struct lu_device *top) -{ - struct lu_site *site = top->ld_site; - struct lu_device *scan; - struct lu_device *next; - - lu_site_purge(env, site, ~0); - for (scan = top; scan; scan = next) { - next = scan->ld_type->ldt_ops->ldto_device_fini(env, scan); - lu_ref_del(&scan->ld_reference, "lu-stack", &lu_site_init); - lu_device_put(scan); - } - - /* purge again. */ - lu_site_purge(env, site, ~0); - - for (scan = top; scan; scan = next) { - const struct lu_device_type *ldt = scan->ld_type; - struct obd_type *type; - - next = ldt->ldt_ops->ldto_device_free(env, scan); - type = ldt->ldt_obd_type; - if (type) { - type->typ_refcnt--; - class_put_type(type); - } - } -} - -enum { - /** - * Maximal number of tld slots. - */ - LU_CONTEXT_KEY_NR = 40 -}; - -static struct lu_context_key *lu_keys[LU_CONTEXT_KEY_NR] = { NULL, }; - -static DEFINE_SPINLOCK(lu_keys_guard); -static atomic_t lu_key_initing_cnt = ATOMIC_INIT(0); - -/** - * Global counter incremented whenever key is registered, unregistered, - * revived or quiesced. This is used to void unnecessary calls to - * lu_context_refill(). No locking is provided, as initialization and shutdown - * are supposed to be externally serialized. - */ -static unsigned int key_set_version; - -/** - * Register new key. - */ -int lu_context_key_register(struct lu_context_key *key) -{ - int result; - unsigned int i; - - LASSERT(key->lct_init); - LASSERT(key->lct_fini); - LASSERT(key->lct_tags != 0); - - result = -ENFILE; - spin_lock(&lu_keys_guard); - for (i = 0; i < ARRAY_SIZE(lu_keys); ++i) { - if (!lu_keys[i]) { - key->lct_index = i; - atomic_set(&key->lct_used, 1); - lu_keys[i] = key; - lu_ref_init(&key->lct_reference); - result = 0; - ++key_set_version; - break; - } - } - spin_unlock(&lu_keys_guard); - return result; -} -EXPORT_SYMBOL(lu_context_key_register); - -static void key_fini(struct lu_context *ctx, int index) -{ - if (ctx->lc_value && ctx->lc_value[index]) { - struct lu_context_key *key; - - key = lu_keys[index]; - LASSERT(atomic_read(&key->lct_used) > 1); - - key->lct_fini(ctx, key, ctx->lc_value[index]); - lu_ref_del(&key->lct_reference, "ctx", ctx); - atomic_dec(&key->lct_used); - - if ((ctx->lc_tags & LCT_NOREF) == 0) - module_put(key->lct_owner); - ctx->lc_value[index] = NULL; - } -} - -/** - * Deregister key. - */ -void lu_context_key_degister(struct lu_context_key *key) -{ - LASSERT(atomic_read(&key->lct_used) >= 1); - LINVRNT(0 <= key->lct_index && key->lct_index < ARRAY_SIZE(lu_keys)); - - lu_context_key_quiesce(key); - - ++key_set_version; - spin_lock(&lu_keys_guard); - key_fini(&lu_shrink_env.le_ctx, key->lct_index); - - /** - * Wait until all transient contexts referencing this key have - * run lu_context_key::lct_fini() method. - */ - while (atomic_read(&key->lct_used) > 1) { - spin_unlock(&lu_keys_guard); - CDEBUG(D_INFO, "%s: \"%s\" %p, %d\n", - __func__, module_name(key->lct_owner), - key, atomic_read(&key->lct_used)); - schedule(); - spin_lock(&lu_keys_guard); - } - if (lu_keys[key->lct_index]) { - lu_keys[key->lct_index] = NULL; - lu_ref_fini(&key->lct_reference); - } - spin_unlock(&lu_keys_guard); - - LASSERTF(atomic_read(&key->lct_used) == 1, - "key has instances: %d\n", - atomic_read(&key->lct_used)); -} -EXPORT_SYMBOL(lu_context_key_degister); - -/** - * Register a number of keys. This has to be called after all keys have been - * initialized by a call to LU_CONTEXT_KEY_INIT(). - */ -int lu_context_key_register_many(struct lu_context_key *k, ...) -{ - struct lu_context_key *key = k; - va_list args; - int result; - - va_start(args, k); - do { - result = lu_context_key_register(key); - if (result) - break; - key = va_arg(args, struct lu_context_key *); - } while (key); - va_end(args); - - if (result != 0) { - va_start(args, k); - while (k != key) { - lu_context_key_degister(k); - k = va_arg(args, struct lu_context_key *); - } - va_end(args); - } - - return result; -} -EXPORT_SYMBOL(lu_context_key_register_many); - -/** - * De-register a number of keys. This is a dual to - * lu_context_key_register_many(). - */ -void lu_context_key_degister_many(struct lu_context_key *k, ...) -{ - va_list args; - - va_start(args, k); - do { - lu_context_key_degister(k); - k = va_arg(args, struct lu_context_key*); - } while (k); - va_end(args); -} -EXPORT_SYMBOL(lu_context_key_degister_many); - -/** - * Revive a number of keys. - */ -void lu_context_key_revive_many(struct lu_context_key *k, ...) -{ - va_list args; - - va_start(args, k); - do { - lu_context_key_revive(k); - k = va_arg(args, struct lu_context_key*); - } while (k); - va_end(args); -} -EXPORT_SYMBOL(lu_context_key_revive_many); - -/** - * Quiescent a number of keys. - */ -void lu_context_key_quiesce_many(struct lu_context_key *k, ...) -{ - va_list args; - - va_start(args, k); - do { - lu_context_key_quiesce(k); - k = va_arg(args, struct lu_context_key*); - } while (k); - va_end(args); -} -EXPORT_SYMBOL(lu_context_key_quiesce_many); - -/** - * Return value associated with key \a key in context \a ctx. - */ -void *lu_context_key_get(const struct lu_context *ctx, - const struct lu_context_key *key) -{ - LINVRNT(ctx->lc_state == LCS_ENTERED); - LINVRNT(0 <= key->lct_index && key->lct_index < ARRAY_SIZE(lu_keys)); - LASSERT(lu_keys[key->lct_index] == key); - return ctx->lc_value[key->lct_index]; -} -EXPORT_SYMBOL(lu_context_key_get); - -/** - * List of remembered contexts. XXX document me. - */ -static LIST_HEAD(lu_context_remembered); - -/** - * Destroy \a key in all remembered contexts. This is used to destroy key - * values in "shared" contexts (like service threads), when a module owning - * the key is about to be unloaded. - */ -void lu_context_key_quiesce(struct lu_context_key *key) -{ - struct lu_context *ctx; - - if (!(key->lct_tags & LCT_QUIESCENT)) { - /* - * XXX memory barrier has to go here. - */ - spin_lock(&lu_keys_guard); - key->lct_tags |= LCT_QUIESCENT; - - /** - * Wait until all lu_context_key::lct_init() methods - * have completed. - */ - while (atomic_read(&lu_key_initing_cnt) > 0) { - spin_unlock(&lu_keys_guard); - CDEBUG(D_INFO, "%s: \"%s\" %p, %d (%d)\n", - __func__, - module_name(key->lct_owner), - key, atomic_read(&key->lct_used), - atomic_read(&lu_key_initing_cnt)); - schedule(); - spin_lock(&lu_keys_guard); - } - - list_for_each_entry(ctx, &lu_context_remembered, lc_remember) - key_fini(ctx, key->lct_index); - spin_unlock(&lu_keys_guard); - ++key_set_version; - } -} - -void lu_context_key_revive(struct lu_context_key *key) -{ - key->lct_tags &= ~LCT_QUIESCENT; - ++key_set_version; -} - -static void keys_fini(struct lu_context *ctx) -{ - unsigned int i; - - if (!ctx->lc_value) - return; - - for (i = 0; i < ARRAY_SIZE(lu_keys); ++i) - key_fini(ctx, i); - - kfree(ctx->lc_value); - ctx->lc_value = NULL; -} - -static int keys_fill(struct lu_context *ctx) -{ - unsigned int i; - - /* - * A serialisation with lu_context_key_quiesce() is needed, but some - * "key->lct_init()" are calling kernel memory allocation routine and - * can't be called while holding a spin_lock. - * "lu_keys_guard" is held while incrementing "lu_key_initing_cnt" - * to ensure the start of the serialisation. - * An atomic_t variable is still used, in order not to reacquire the - * lock when decrementing the counter. - */ - spin_lock(&lu_keys_guard); - atomic_inc(&lu_key_initing_cnt); - spin_unlock(&lu_keys_guard); - - LINVRNT(ctx->lc_value); - for (i = 0; i < ARRAY_SIZE(lu_keys); ++i) { - struct lu_context_key *key; - - key = lu_keys[i]; - if (!ctx->lc_value[i] && key && - (key->lct_tags & ctx->lc_tags) && - /* - * Don't create values for a LCT_QUIESCENT key, as this - * will pin module owning a key. - */ - !(key->lct_tags & LCT_QUIESCENT)) { - void *value; - - LINVRNT(key->lct_init); - LINVRNT(key->lct_index == i); - - if (!(ctx->lc_tags & LCT_NOREF) && - !try_module_get(key->lct_owner)) { - /* module is unloading, skip this key */ - continue; - } - - value = key->lct_init(ctx, key); - if (unlikely(IS_ERR(value))) { - atomic_dec(&lu_key_initing_cnt); - return PTR_ERR(value); - } - - lu_ref_add_atomic(&key->lct_reference, "ctx", ctx); - atomic_inc(&key->lct_used); - /* - * This is the only place in the code, where an - * element of ctx->lc_value[] array is set to non-NULL - * value. - */ - ctx->lc_value[i] = value; - if (key->lct_exit) - ctx->lc_tags |= LCT_HAS_EXIT; - } - ctx->lc_version = key_set_version; - } - atomic_dec(&lu_key_initing_cnt); - return 0; -} - -static int keys_init(struct lu_context *ctx) -{ - ctx->lc_value = kcalloc(ARRAY_SIZE(lu_keys), sizeof(ctx->lc_value[0]), - GFP_NOFS); - if (likely(ctx->lc_value)) - return keys_fill(ctx); - - return -ENOMEM; -} - -/** - * Initialize context data-structure. Create values for all keys. - */ -int lu_context_init(struct lu_context *ctx, __u32 tags) -{ - int rc; - - memset(ctx, 0, sizeof(*ctx)); - ctx->lc_state = LCS_INITIALIZED; - ctx->lc_tags = tags; - if (tags & LCT_REMEMBER) { - spin_lock(&lu_keys_guard); - list_add(&ctx->lc_remember, &lu_context_remembered); - spin_unlock(&lu_keys_guard); - } else { - INIT_LIST_HEAD(&ctx->lc_remember); - } - - rc = keys_init(ctx); - if (rc != 0) - lu_context_fini(ctx); - - return rc; -} -EXPORT_SYMBOL(lu_context_init); - -/** - * Finalize context data-structure. Destroy key values. - */ -void lu_context_fini(struct lu_context *ctx) -{ - LINVRNT(ctx->lc_state == LCS_INITIALIZED || ctx->lc_state == LCS_LEFT); - ctx->lc_state = LCS_FINALIZED; - - if ((ctx->lc_tags & LCT_REMEMBER) == 0) { - LASSERT(list_empty(&ctx->lc_remember)); - keys_fini(ctx); - - } else { /* could race with key degister */ - spin_lock(&lu_keys_guard); - keys_fini(ctx); - list_del_init(&ctx->lc_remember); - spin_unlock(&lu_keys_guard); - } -} -EXPORT_SYMBOL(lu_context_fini); - -/** - * Called before entering context. - */ -void lu_context_enter(struct lu_context *ctx) -{ - LINVRNT(ctx->lc_state == LCS_INITIALIZED || ctx->lc_state == LCS_LEFT); - ctx->lc_state = LCS_ENTERED; -} -EXPORT_SYMBOL(lu_context_enter); - -/** - * Called after exiting from \a ctx - */ -void lu_context_exit(struct lu_context *ctx) -{ - unsigned int i; - - LINVRNT(ctx->lc_state == LCS_ENTERED); - ctx->lc_state = LCS_LEFT; - if (ctx->lc_tags & LCT_HAS_EXIT && ctx->lc_value) { - for (i = 0; i < ARRAY_SIZE(lu_keys); ++i) { - /* could race with key quiescency */ - if (ctx->lc_tags & LCT_REMEMBER) - spin_lock(&lu_keys_guard); - if (ctx->lc_value[i]) { - struct lu_context_key *key; - - key = lu_keys[i]; - if (key->lct_exit) - key->lct_exit(ctx, - key, ctx->lc_value[i]); - } - if (ctx->lc_tags & LCT_REMEMBER) - spin_unlock(&lu_keys_guard); - } - } -} -EXPORT_SYMBOL(lu_context_exit); - -/** - * Allocate for context all missing keys that were registered after context - * creation. key_set_version is only changed in rare cases when modules - * are loaded and removed. - */ -int lu_context_refill(struct lu_context *ctx) -{ - return likely(ctx->lc_version == key_set_version) ? 0 : keys_fill(ctx); -} - -/** - * lu_ctx_tags/lu_ses_tags will be updated if there are new types of - * obd being added. Currently, this is only used on client side, specifically - * for echo device client, for other stack (like ptlrpc threads), context are - * predefined when the lu_device type are registered, during the module probe - * phase. - */ -__u32 lu_context_tags_default; -__u32 lu_session_tags_default; - -int lu_env_init(struct lu_env *env, __u32 tags) -{ - int result; - - env->le_ses = NULL; - result = lu_context_init(&env->le_ctx, tags); - if (likely(result == 0)) - lu_context_enter(&env->le_ctx); - return result; -} -EXPORT_SYMBOL(lu_env_init); - -void lu_env_fini(struct lu_env *env) -{ - lu_context_exit(&env->le_ctx); - lu_context_fini(&env->le_ctx); - env->le_ses = NULL; -} -EXPORT_SYMBOL(lu_env_fini); - -int lu_env_refill(struct lu_env *env) -{ - int result; - - result = lu_context_refill(&env->le_ctx); - if (result == 0 && env->le_ses) - result = lu_context_refill(env->le_ses); - return result; -} -EXPORT_SYMBOL(lu_env_refill); - -struct lu_site_stats { - unsigned int lss_populated; - unsigned int lss_max_search; - unsigned int lss_total; - unsigned int lss_busy; -}; - -static void lu_site_stats_get(struct cfs_hash *hs, - struct lu_site_stats *stats, int populated) -{ - struct cfs_hash_bd bd; - unsigned int i; - - cfs_hash_for_each_bucket(hs, &bd, i) { - struct lu_site_bkt_data *bkt = cfs_hash_bd_extra_get(hs, &bd); - struct hlist_head *hhead; - - cfs_hash_bd_lock(hs, &bd, 1); - stats->lss_busy += - cfs_hash_bd_count_get(&bd) - bkt->lsb_lru_len; - stats->lss_total += cfs_hash_bd_count_get(&bd); - stats->lss_max_search = max((int)stats->lss_max_search, - cfs_hash_bd_depmax_get(&bd)); - if (!populated) { - cfs_hash_bd_unlock(hs, &bd, 1); - continue; - } - - cfs_hash_bd_for_each_hlist(hs, &bd, hhead) { - if (!hlist_empty(hhead)) - stats->lss_populated++; - } - cfs_hash_bd_unlock(hs, &bd, 1); - } -} - -/* - * lu_cache_shrink_count() returns an approximate number of cached objects - * that can be freed by shrink_slab(). A counter, which tracks the - * number of items in the site's lru, is maintained in a percpu_counter - * for each site. The percpu values are incremented and decremented as - * objects are added or removed from the lru. The percpu values are summed - * and saved whenever a percpu value exceeds a threshold. Thus the saved, - * summed value at any given time may not accurately reflect the current - * lru length. But this value is sufficiently accurate for the needs of - * a shrinker. - * - * Using a per cpu counter is a compromise solution to concurrent access: - * lu_object_put() can update the counter without locking the site and - * lu_cache_shrink_count can sum the counters without locking each - * ls_obj_hash bucket. - */ -static unsigned long lu_cache_shrink_count(struct shrinker *sk, - struct shrink_control *sc) -{ - struct lu_site *s; - struct lu_site *tmp; - unsigned long cached = 0; - - if (!(sc->gfp_mask & __GFP_FS)) - return 0; - - down_read(&lu_sites_guard); - list_for_each_entry_safe(s, tmp, &lu_sites, ls_linkage) - cached += percpu_counter_read_positive(&s->ls_lru_len_counter); - up_read(&lu_sites_guard); - - cached = (cached / 100) * sysctl_vfs_cache_pressure; - CDEBUG(D_INODE, "%ld objects cached, cache pressure %d\n", - cached, sysctl_vfs_cache_pressure); - - return cached; -} - -static unsigned long lu_cache_shrink_scan(struct shrinker *sk, - struct shrink_control *sc) -{ - struct lu_site *s; - struct lu_site *tmp; - unsigned long remain = sc->nr_to_scan, freed = 0; - LIST_HEAD(splice); - - if (!(sc->gfp_mask & __GFP_FS)) - /* We must not take the lu_sites_guard lock when - * __GFP_FS is *not* set because of the deadlock - * possibility detailed above. Additionally, - * since we cannot determine the number of - * objects in the cache without taking this - * lock, we're in a particularly tough spot. As - * a result, we'll just lie and say our cache is - * empty. This _should_ be ok, as we can't - * reclaim objects when __GFP_FS is *not* set - * anyways. - */ - return SHRINK_STOP; - - down_write(&lu_sites_guard); - list_for_each_entry_safe(s, tmp, &lu_sites, ls_linkage) { - freed = lu_site_purge(&lu_shrink_env, s, remain); - remain -= freed; - /* - * Move just shrunk site to the tail of site list to - * assure shrinking fairness. - */ - list_move_tail(&s->ls_linkage, &splice); - } - list_splice(&splice, lu_sites.prev); - up_write(&lu_sites_guard); - - return sc->nr_to_scan - remain; -} - -/** - * Debugging printer function using printk(). - */ -static struct shrinker lu_site_shrinker = { - .count_objects = lu_cache_shrink_count, - .scan_objects = lu_cache_shrink_scan, - .seeks = DEFAULT_SEEKS, -}; - -/** - * Initialization of global lu_* data. - */ -int lu_global_init(void) -{ - int result; - - CDEBUG(D_INFO, "Lustre LU module (%p).\n", &lu_keys); - - result = lu_ref_global_init(); - if (result != 0) - return result; - - LU_CONTEXT_KEY_INIT(&lu_global_key); - result = lu_context_key_register(&lu_global_key); - if (result != 0) { - lu_ref_global_fini(); - return result; - } - - /* - * At this level, we don't know what tags are needed, so allocate them - * conservatively. This should not be too bad, because this - * environment is global. - */ - down_write(&lu_sites_guard); - result = lu_env_init(&lu_shrink_env, LCT_SHRINKER); - up_write(&lu_sites_guard); - if (result != 0) { - lu_context_key_degister(&lu_global_key); - lu_ref_global_fini(); - return result; - } - - /* - * seeks estimation: 3 seeks to read a record from oi, one to read - * inode, one for ea. Unfortunately setting this high value results in - * lu_object/inode cache consuming all the memory. - */ - result = register_shrinker(&lu_site_shrinker); - if (result != 0) { - /* Order explained in lu_global_fini(). */ - lu_context_key_degister(&lu_global_key); - - down_write(&lu_sites_guard); - lu_env_fini(&lu_shrink_env); - up_write(&lu_sites_guard); - - lu_ref_global_fini(); - return result; - } - - return 0; -} - -/** - * Dual to lu_global_init(). - */ -void lu_global_fini(void) -{ - unregister_shrinker(&lu_site_shrinker); - lu_context_key_degister(&lu_global_key); - - /* - * Tear shrinker environment down _after_ de-registering - * lu_global_key, because the latter has a value in the former. - */ - down_write(&lu_sites_guard); - lu_env_fini(&lu_shrink_env); - up_write(&lu_sites_guard); - - lu_ref_global_fini(); -} - -static __u32 ls_stats_read(struct lprocfs_stats *stats, int idx) -{ - struct lprocfs_counter ret; - - lprocfs_stats_collect(stats, idx, &ret); - return (__u32)ret.lc_count; -} - -/** - * Output site statistical counters into a buffer. Suitable for - * lprocfs_rd_*()-style functions. - */ -int lu_site_stats_print(const struct lu_site *s, struct seq_file *m) -{ - struct lu_site_stats stats; - - memset(&stats, 0, sizeof(stats)); - lu_site_stats_get(s->ls_obj_hash, &stats, 1); - - seq_printf(m, "%d/%d %d/%ld %d %d %d %d %d %d %d\n", - stats.lss_busy, - stats.lss_total, - stats.lss_populated, - CFS_HASH_NHLIST(s->ls_obj_hash), - stats.lss_max_search, - ls_stats_read(s->ls_stats, LU_SS_CREATED), - ls_stats_read(s->ls_stats, LU_SS_CACHE_HIT), - ls_stats_read(s->ls_stats, LU_SS_CACHE_MISS), - ls_stats_read(s->ls_stats, LU_SS_CACHE_RACE), - ls_stats_read(s->ls_stats, LU_SS_CACHE_DEATH_RACE), - ls_stats_read(s->ls_stats, LU_SS_LRU_PURGED)); - return 0; -} -EXPORT_SYMBOL(lu_site_stats_print); - -/** - * Helper function to initialize a number of kmem slab caches at once. - */ -int lu_kmem_init(struct lu_kmem_descr *caches) -{ - int result; - struct lu_kmem_descr *iter = caches; - - for (result = 0; iter->ckd_cache; ++iter) { - *iter->ckd_cache = kmem_cache_create(iter->ckd_name, - iter->ckd_size, - 0, 0, NULL); - if (!*iter->ckd_cache) { - result = -ENOMEM; - /* free all previously allocated caches */ - lu_kmem_fini(caches); - break; - } - } - return result; -} -EXPORT_SYMBOL(lu_kmem_init); - -/** - * Helper function to finalize a number of kmem slab cached at once. Dual to - * lu_kmem_init(). - */ -void lu_kmem_fini(struct lu_kmem_descr *caches) -{ - for (; caches->ckd_cache; ++caches) { - kmem_cache_destroy(*caches->ckd_cache); - *caches->ckd_cache = NULL; - } -} -EXPORT_SYMBOL(lu_kmem_fini); diff --git a/drivers/staging/lustre/lustre/obdclass/lu_ref.c b/drivers/staging/lustre/lustre/obdclass/lu_ref.c deleted file mode 100644 index 54fc88206534..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/lu_ref.c +++ /dev/null @@ -1,47 +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) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lustre/obdclass/lu_ref.c - * - * Lustre reference. - * - * Author: Nikita Danilov <nikita.danilov@sun.com> - */ - -#define DEBUG_SUBSYSTEM S_CLASS - -#include <linux/libcfs/libcfs.h> - -#include <obd.h> -#include <obd_class.h> -#include <obd_support.h> -#include <lu_ref.h> diff --git a/drivers/staging/lustre/lustre/obdclass/lustre_handles.c b/drivers/staging/lustre/lustre/obdclass/lustre_handles.c deleted file mode 100644 index f53b1a3c342e..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/lustre_handles.c +++ /dev/null @@ -1,240 +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) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2011, 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lustre/obdclass/lustre_handles.c - * - * Author: Phil Schwan <phil@clusterfs.com> - */ - -#define DEBUG_SUBSYSTEM S_CLASS - -#include <obd_support.h> -#include <lustre_handles.h> -#include <lustre_lib.h> - -static __u64 handle_base; -#define HANDLE_INCR 7 -static spinlock_t handle_base_lock; - -static struct handle_bucket { - spinlock_t lock; - struct list_head head; -} *handle_hash; - -#define HANDLE_HASH_SIZE (1 << 16) -#define HANDLE_HASH_MASK (HANDLE_HASH_SIZE - 1) - -/* - * Generate a unique 64bit cookie (hash) for a handle and insert it into - * global (per-node) hash-table. - */ -void class_handle_hash(struct portals_handle *h, - struct portals_handle_ops *ops) -{ - struct handle_bucket *bucket; - - LASSERT(h); - LASSERT(list_empty(&h->h_link)); - - /* - * This is fast, but simplistic cookie generation algorithm, it will - * need a re-do at some point in the future for security. - */ - spin_lock(&handle_base_lock); - handle_base += HANDLE_INCR; - - if (unlikely(handle_base == 0)) { - /* - * Cookie of zero is "dangerous", because in many places it's - * assumed that 0 means "unassigned" handle, not bound to any - * object. - */ - CWARN("The universe has been exhausted: cookie wrap-around.\n"); - handle_base += HANDLE_INCR; - } - h->h_cookie = handle_base; - spin_unlock(&handle_base_lock); - - h->h_ops = ops; - spin_lock_init(&h->h_lock); - - bucket = &handle_hash[h->h_cookie & HANDLE_HASH_MASK]; - spin_lock(&bucket->lock); - list_add_rcu(&h->h_link, &bucket->head); - h->h_in = 1; - spin_unlock(&bucket->lock); - - CDEBUG(D_INFO, "added object %p with handle %#llx to hash\n", - h, h->h_cookie); -} -EXPORT_SYMBOL(class_handle_hash); - -static void class_handle_unhash_nolock(struct portals_handle *h) -{ - if (list_empty(&h->h_link)) { - CERROR("removing an already-removed handle (%#llx)\n", - h->h_cookie); - return; - } - - CDEBUG(D_INFO, "removing object %p with handle %#llx from hash\n", - h, h->h_cookie); - - spin_lock(&h->h_lock); - if (h->h_in == 0) { - spin_unlock(&h->h_lock); - return; - } - h->h_in = 0; - spin_unlock(&h->h_lock); - list_del_rcu(&h->h_link); -} - -void class_handle_unhash(struct portals_handle *h) -{ - struct handle_bucket *bucket; - - bucket = handle_hash + (h->h_cookie & HANDLE_HASH_MASK); - - spin_lock(&bucket->lock); - class_handle_unhash_nolock(h); - spin_unlock(&bucket->lock); -} -EXPORT_SYMBOL(class_handle_unhash); - -void *class_handle2object(__u64 cookie, const void *owner) -{ - struct handle_bucket *bucket; - struct portals_handle *h; - void *retval = NULL; - - LASSERT(handle_hash); - - /* Be careful when you want to change this code. See the - * rcu_read_lock() definition on top this file. - jxiong - */ - bucket = handle_hash + (cookie & HANDLE_HASH_MASK); - - rcu_read_lock(); - list_for_each_entry_rcu(h, &bucket->head, h_link) { - if (h->h_cookie != cookie || h->h_owner != owner) - continue; - - spin_lock(&h->h_lock); - if (likely(h->h_in != 0)) { - h->h_ops->hop_addref(h); - retval = h; - } - spin_unlock(&h->h_lock); - break; - } - rcu_read_unlock(); - - return retval; -} -EXPORT_SYMBOL(class_handle2object); - -void class_handle_free_cb(struct rcu_head *rcu) -{ - struct portals_handle *h; - void *ptr; - - h = container_of(rcu, struct portals_handle, h_rcu); - ptr = (void *)(unsigned long)h->h_cookie; - - if (h->h_ops->hop_free) - h->h_ops->hop_free(ptr, h->h_size); - else - kfree(ptr); -} -EXPORT_SYMBOL(class_handle_free_cb); - -int class_handle_init(void) -{ - struct handle_bucket *bucket; - - LASSERT(!handle_hash); - - handle_hash = kvzalloc(sizeof(*bucket) * HANDLE_HASH_SIZE, - GFP_KERNEL); - if (!handle_hash) - return -ENOMEM; - - spin_lock_init(&handle_base_lock); - for (bucket = handle_hash + HANDLE_HASH_SIZE - 1; bucket >= handle_hash; - bucket--) { - INIT_LIST_HEAD(&bucket->head); - spin_lock_init(&bucket->lock); - } - - get_random_bytes(&handle_base, sizeof(handle_base)); - LASSERT(handle_base != 0ULL); - - return 0; -} - -static int cleanup_all_handles(void) -{ - int rc; - int i; - - for (rc = i = 0; i < HANDLE_HASH_SIZE; i++) { - struct portals_handle *h; - - spin_lock(&handle_hash[i].lock); - list_for_each_entry_rcu(h, &handle_hash[i].head, h_link) { - CERROR("force clean handle %#llx addr %p ops %p\n", - h->h_cookie, h, h->h_ops); - - class_handle_unhash_nolock(h); - rc++; - } - spin_unlock(&handle_hash[i].lock); - } - - return rc; -} - -void class_handle_cleanup(void) -{ - int count; - - LASSERT(handle_hash); - - count = cleanup_all_handles(); - - kvfree(handle_hash); - handle_hash = NULL; - - if (count != 0) - CERROR("handle_count at cleanup: %d\n", count); -} diff --git a/drivers/staging/lustre/lustre/obdclass/lustre_peer.c b/drivers/staging/lustre/lustre/obdclass/lustre_peer.c deleted file mode 100644 index e286a2665423..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/lustre_peer.c +++ /dev/null @@ -1,214 +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) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2011, 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - */ - -#define DEBUG_SUBSYSTEM S_RPC - -#include <obd.h> -#include <obd_support.h> -#include <obd_class.h> -#include <lustre_lib.h> -#include <lustre_ha.h> -#include <lustre_net.h> -#include <lprocfs_status.h> - -#define NIDS_MAX 32 - -struct uuid_nid_data { - struct list_head un_list; - struct obd_uuid un_uuid; - int un_nid_count; - lnet_nid_t un_nids[NIDS_MAX]; -}; - -/* FIXME: This should probably become more elegant than a global linked list */ -static struct list_head g_uuid_list; -static spinlock_t g_uuid_lock; - -void class_init_uuidlist(void) -{ - INIT_LIST_HEAD(&g_uuid_list); - spin_lock_init(&g_uuid_lock); -} - -void class_exit_uuidlist(void) -{ - /* delete all */ - class_del_uuid(NULL); -} - -int lustre_uuid_to_peer(const char *uuid, lnet_nid_t *peer_nid, int index) -{ - struct uuid_nid_data *data; - struct obd_uuid tmp; - int rc = -ENOENT; - - obd_str2uuid(&tmp, uuid); - spin_lock(&g_uuid_lock); - list_for_each_entry(data, &g_uuid_list, un_list) { - if (obd_uuid_equals(&data->un_uuid, &tmp)) { - if (index >= data->un_nid_count) - break; - - rc = 0; - *peer_nid = data->un_nids[index]; - break; - } - } - spin_unlock(&g_uuid_lock); - return rc; -} -EXPORT_SYMBOL(lustre_uuid_to_peer); - -/* Add a nid to a niduuid. Multiple nids can be added to a single uuid; - * LNET will choose the best one. - */ -int class_add_uuid(const char *uuid, __u64 nid) -{ - struct uuid_nid_data *data, *entry; - int found = 0; - - LASSERT(nid != 0); /* valid newconfig NID is never zero */ - - if (strlen(uuid) > UUID_MAX - 1) - return -EOVERFLOW; - - data = kzalloc(sizeof(*data), GFP_NOFS); - if (!data) - return -ENOMEM; - - obd_str2uuid(&data->un_uuid, uuid); - data->un_nids[0] = nid; - data->un_nid_count = 1; - - spin_lock(&g_uuid_lock); - list_for_each_entry(entry, &g_uuid_list, un_list) { - if (obd_uuid_equals(&entry->un_uuid, &data->un_uuid)) { - int i; - - found = 1; - for (i = 0; i < entry->un_nid_count; i++) - if (nid == entry->un_nids[i]) - break; - - if (i == entry->un_nid_count) { - LASSERT(entry->un_nid_count < NIDS_MAX); - entry->un_nids[entry->un_nid_count++] = nid; - } - break; - } - } - if (!found) - list_add(&data->un_list, &g_uuid_list); - spin_unlock(&g_uuid_lock); - - if (found) { - CDEBUG(D_INFO, "found uuid %s %s cnt=%d\n", uuid, - libcfs_nid2str(nid), entry->un_nid_count); - kfree(data); - } else { - CDEBUG(D_INFO, "add uuid %s %s\n", uuid, libcfs_nid2str(nid)); - } - return 0; -} - -/* Delete the nids for one uuid if specified, otherwise delete all */ -int class_del_uuid(const char *uuid) -{ - LIST_HEAD(deathrow); - struct uuid_nid_data *data; - struct uuid_nid_data *temp; - - spin_lock(&g_uuid_lock); - if (uuid) { - struct obd_uuid tmp; - - obd_str2uuid(&tmp, uuid); - list_for_each_entry(data, &g_uuid_list, un_list) { - if (obd_uuid_equals(&data->un_uuid, &tmp)) { - list_move(&data->un_list, &deathrow); - break; - } - } - } else { - list_splice_init(&g_uuid_list, &deathrow); - } - spin_unlock(&g_uuid_lock); - - if (uuid && list_empty(&deathrow)) { - CDEBUG(D_INFO, "Try to delete a non-existent uuid %s\n", uuid); - return -EINVAL; - } - - list_for_each_entry_safe(data, temp, &deathrow, un_list) { - list_del(&data->un_list); - - CDEBUG(D_INFO, "del uuid %s %s/%d\n", - obd_uuid2str(&data->un_uuid), - libcfs_nid2str(data->un_nids[0]), - data->un_nid_count); - - kfree(data); - } - - return 0; -} - -/* check if @nid exists in nid list of @uuid */ -int class_check_uuid(struct obd_uuid *uuid, __u64 nid) -{ - struct uuid_nid_data *entry; - int found = 0; - - CDEBUG(D_INFO, "check if uuid %s has %s.\n", - obd_uuid2str(uuid), libcfs_nid2str(nid)); - - spin_lock(&g_uuid_lock); - list_for_each_entry(entry, &g_uuid_list, un_list) { - int i; - - if (!obd_uuid_equals(&entry->un_uuid, uuid)) - continue; - - /* found the uuid, check if it has @nid */ - for (i = 0; i < entry->un_nid_count; i++) { - if (entry->un_nids[i] == nid) { - found = 1; - break; - } - } - break; - } - spin_unlock(&g_uuid_lock); - return found; -} -EXPORT_SYMBOL(class_check_uuid); diff --git a/drivers/staging/lustre/lustre/obdclass/obd_config.c b/drivers/staging/lustre/lustre/obdclass/obd_config.c deleted file mode 100644 index 277576b586db..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/obd_config.c +++ /dev/null @@ -1,1559 +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) 2003, 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. - * - * lustre/obdclass/obd_config.c - * - * Config API - */ - -#define DEBUG_SUBSYSTEM S_CLASS - -#include <linux/string.h> - -#include <uapi/linux/lustre/lustre_ioctl.h> -#include <llog_swab.h> -#include <lprocfs_status.h> -#include <lustre_log.h> -#include <uapi/linux/lustre/lustre_param.h> -#include <obd_class.h> - -#include "llog_internal.h" - -static struct cfs_hash_ops uuid_hash_ops; - -/*********** string parsing utils *********/ - -/* returns 0 if we find this key in the buffer, else 1 */ -int class_find_param(char *buf, char *key, char **valp) -{ - char *ptr; - - if (!buf) - return 1; - - ptr = strstr(buf, key); - if (!ptr) - return 1; - - if (valp) - *valp = ptr + strlen(key); - - return 0; -} -EXPORT_SYMBOL(class_find_param); - -/* returns 0 if this is the first key in the buffer, else 1. - * valp points to first char after key. - */ -static int class_match_param(char *buf, const char *key, char **valp) -{ - if (!buf) - return 1; - - if (memcmp(buf, key, strlen(key)) != 0) - return 1; - - if (valp) - *valp = buf + strlen(key); - - return 0; -} - -static int parse_nid(char *buf, void *value, int quiet) -{ - lnet_nid_t *nid = value; - - *nid = libcfs_str2nid(buf); - if (*nid != LNET_NID_ANY) - return 0; - - if (!quiet) - LCONSOLE_ERROR_MSG(0x159, "Can't parse NID '%s'\n", buf); - return -EINVAL; -} - -static int parse_net(char *buf, void *value) -{ - __u32 *net = value; - - *net = libcfs_str2net(buf); - CDEBUG(D_INFO, "Net %s\n", libcfs_net2str(*net)); - return 0; -} - -enum { - CLASS_PARSE_NID = 1, - CLASS_PARSE_NET, -}; - -/* 0 is good nid, - * 1 not found - * < 0 error - * endh is set to next separator - */ -static int class_parse_value(char *buf, int opc, void *value, char **endh, - int quiet) -{ - char *endp; - char tmp; - int rc = 0; - - if (!buf) - return 1; - while (*buf == ',' || *buf == ':') - buf++; - if (*buf == ' ' || *buf == '/' || *buf == '\0') - return 1; - - /* nid separators or end of nids */ - endp = strpbrk(buf, ",: /"); - if (!endp) - endp = buf + strlen(buf); - - tmp = *endp; - *endp = '\0'; - switch (opc) { - default: - LBUG(); - case CLASS_PARSE_NID: - rc = parse_nid(buf, value, quiet); - break; - case CLASS_PARSE_NET: - rc = parse_net(buf, value); - break; - } - *endp = tmp; - if (rc != 0) - return rc; - if (endh) - *endh = endp; - return 0; -} - -int class_parse_nid(char *buf, lnet_nid_t *nid, char **endh) -{ - return class_parse_value(buf, CLASS_PARSE_NID, (void *)nid, endh, 0); -} -EXPORT_SYMBOL(class_parse_nid); - -int class_parse_nid_quiet(char *buf, lnet_nid_t *nid, char **endh) -{ - return class_parse_value(buf, CLASS_PARSE_NID, (void *)nid, endh, 1); -} -EXPORT_SYMBOL(class_parse_nid_quiet); - -char *lustre_cfg_string(struct lustre_cfg *lcfg, u32 index) -{ - char *s; - - if (!lcfg->lcfg_buflens[index]) - return NULL; - - s = lustre_cfg_buf(lcfg, index); - if (!s) - return NULL; - - /* - * make sure it's NULL terminated, even if this kills a char - * of data. Try to use the padding first though. - */ - if (s[lcfg->lcfg_buflens[index] - 1] != '\0') { - size_t last = ALIGN(lcfg->lcfg_buflens[index], 8) - 1; - char lost; - - /* Use the smaller value */ - if (last > lcfg->lcfg_buflens[index]) - last = lcfg->lcfg_buflens[index]; - - lost = s[last]; - s[last] = '\0'; - if (lost != '\0') { - CWARN("Truncated buf %d to '%s' (lost '%c'...)\n", - index, s, lost); - } - } - return s; -} -EXPORT_SYMBOL(lustre_cfg_string); - -/********************** class fns **********************/ - -/** - * Create a new obd device and set the type, name and uuid. If successful, - * the new device can be accessed by either name or uuid. - */ -static int class_attach(struct lustre_cfg *lcfg) -{ - struct obd_device *obd = NULL; - char *typename, *name, *uuid; - int rc, len; - - if (!LUSTRE_CFG_BUFLEN(lcfg, 1)) { - CERROR("No type passed!\n"); - return -EINVAL; - } - typename = lustre_cfg_string(lcfg, 1); - - if (!LUSTRE_CFG_BUFLEN(lcfg, 0)) { - CERROR("No name passed!\n"); - return -EINVAL; - } - name = lustre_cfg_string(lcfg, 0); - - if (!LUSTRE_CFG_BUFLEN(lcfg, 2)) { - CERROR("No UUID passed!\n"); - return -EINVAL; - } - uuid = lustre_cfg_string(lcfg, 2); - - CDEBUG(D_IOCTL, "attach type %s name: %s uuid: %s\n", - typename, name, uuid); - - obd = class_newdev(typename, name); - if (IS_ERR(obd)) { - /* Already exists or out of obds */ - rc = PTR_ERR(obd); - obd = NULL; - CERROR("Cannot create device %s of type %s : %d\n", - name, typename, rc); - goto out; - } - LASSERTF(obd, "Cannot get obd device %s of type %s\n", - name, typename); - LASSERTF(obd->obd_magic == OBD_DEVICE_MAGIC, - "obd %p obd_magic %08X != %08X\n", - obd, obd->obd_magic, OBD_DEVICE_MAGIC); - LASSERTF(strncmp(obd->obd_name, name, strlen(name)) == 0, - "%p obd_name %s != %s\n", obd, obd->obd_name, name); - - rwlock_init(&obd->obd_pool_lock); - obd->obd_pool_limit = 0; - obd->obd_pool_slv = 0; - - INIT_LIST_HEAD(&obd->obd_exports); - INIT_LIST_HEAD(&obd->obd_unlinked_exports); - INIT_LIST_HEAD(&obd->obd_delayed_exports); - spin_lock_init(&obd->obd_nid_lock); - spin_lock_init(&obd->obd_dev_lock); - mutex_init(&obd->obd_dev_mutex); - spin_lock_init(&obd->obd_osfs_lock); - /* obd->obd_osfs_age must be set to a value in the distant - * past to guarantee a fresh statfs is fetched on mount. - */ - obd->obd_osfs_age = cfs_time_shift_64(-1000); - - /* XXX belongs in setup not attach */ - init_rwsem(&obd->obd_observer_link_sem); - /* recovery data */ - init_waitqueue_head(&obd->obd_evict_inprogress_waitq); - - llog_group_init(&obd->obd_olg); - - obd->obd_conn_inprogress = 0; - - len = strlen(uuid); - if (len >= sizeof(obd->obd_uuid)) { - CERROR("uuid must be < %d bytes long\n", - (int)sizeof(obd->obd_uuid)); - rc = -EINVAL; - goto out; - } - memcpy(obd->obd_uuid.uuid, uuid, len); - - /* Detach drops this */ - spin_lock(&obd->obd_dev_lock); - atomic_set(&obd->obd_refcount, 1); - spin_unlock(&obd->obd_dev_lock); - lu_ref_init(&obd->obd_reference); - lu_ref_add(&obd->obd_reference, "attach", obd); - - obd->obd_attached = 1; - CDEBUG(D_IOCTL, "OBD: dev %d attached type %s with refcount %d\n", - obd->obd_minor, typename, atomic_read(&obd->obd_refcount)); - return 0; - out: - if (obd) - class_release_dev(obd); - - return rc; -} - -/** Create hashes, self-export, and call type-specific setup. - * Setup is effectively the "start this obd" call. - */ -static int class_setup(struct obd_device *obd, struct lustre_cfg *lcfg) -{ - int err = 0; - struct obd_export *exp; - - LASSERT(obd); - LASSERTF(obd == class_num2obd(obd->obd_minor), - "obd %p != obd_devs[%d] %p\n", - obd, obd->obd_minor, class_num2obd(obd->obd_minor)); - LASSERTF(obd->obd_magic == OBD_DEVICE_MAGIC, - "obd %p obd_magic %08x != %08x\n", - obd, obd->obd_magic, OBD_DEVICE_MAGIC); - - /* have we attached a type to this device? */ - if (!obd->obd_attached) { - CERROR("Device %d not attached\n", obd->obd_minor); - return -ENODEV; - } - - if (obd->obd_set_up) { - CERROR("Device %d already setup (type %s)\n", - obd->obd_minor, obd->obd_type->typ_name); - return -EEXIST; - } - - /* is someone else setting us up right now? (attach inits spinlock) */ - spin_lock(&obd->obd_dev_lock); - if (obd->obd_starting) { - spin_unlock(&obd->obd_dev_lock); - CERROR("Device %d setup in progress (type %s)\n", - obd->obd_minor, obd->obd_type->typ_name); - return -EEXIST; - } - /* just leave this on forever. I can't use obd_set_up here because - * other fns check that status, and we're not actually set up yet. - */ - obd->obd_starting = 1; - obd->obd_uuid_hash = NULL; - spin_unlock(&obd->obd_dev_lock); - - /* create an uuid-export lustre hash */ - obd->obd_uuid_hash = cfs_hash_create("UUID_HASH", - HASH_UUID_CUR_BITS, - HASH_UUID_MAX_BITS, - HASH_UUID_BKT_BITS, 0, - CFS_HASH_MIN_THETA, - CFS_HASH_MAX_THETA, - &uuid_hash_ops, CFS_HASH_DEFAULT); - if (!obd->obd_uuid_hash) { - err = -ENOMEM; - goto err_hash; - } - - exp = class_new_export(obd, &obd->obd_uuid); - if (IS_ERR(exp)) { - err = PTR_ERR(exp); - goto err_hash; - } - - obd->obd_self_export = exp; - class_export_put(exp); - - err = obd_setup(obd, lcfg); - if (err) - goto err_exp; - - obd->obd_set_up = 1; - - spin_lock(&obd->obd_dev_lock); - /* cleanup drops this */ - class_incref(obd, "setup", obd); - spin_unlock(&obd->obd_dev_lock); - - CDEBUG(D_IOCTL, "finished setup of obd %s (uuid %s)\n", - obd->obd_name, obd->obd_uuid.uuid); - - return 0; -err_exp: - if (obd->obd_self_export) { - class_unlink_export(obd->obd_self_export); - obd->obd_self_export = NULL; - } -err_hash: - if (obd->obd_uuid_hash) { - cfs_hash_putref(obd->obd_uuid_hash); - obd->obd_uuid_hash = NULL; - } - obd->obd_starting = 0; - CERROR("setup %s failed (%d)\n", obd->obd_name, err); - return err; -} - -/** We have finished using this obd and are ready to destroy it. - * There can be no more references to this obd. - */ -static int class_detach(struct obd_device *obd, struct lustre_cfg *lcfg) -{ - if (obd->obd_set_up) { - CERROR("OBD device %d still set up\n", obd->obd_minor); - return -EBUSY; - } - - spin_lock(&obd->obd_dev_lock); - if (!obd->obd_attached) { - spin_unlock(&obd->obd_dev_lock); - CERROR("OBD device %d not attached\n", obd->obd_minor); - return -ENODEV; - } - obd->obd_attached = 0; - spin_unlock(&obd->obd_dev_lock); - - CDEBUG(D_IOCTL, "detach on obd %s (uuid %s)\n", - obd->obd_name, obd->obd_uuid.uuid); - - class_decref(obd, "attach", obd); - return 0; -} - -/** Start shutting down the obd. There may be in-progress ops when - * this is called. We tell them to start shutting down with a call - * to class_disconnect_exports(). - */ -static int class_cleanup(struct obd_device *obd, struct lustre_cfg *lcfg) -{ - int err = 0; - char *flag; - - OBD_RACE(OBD_FAIL_LDLM_RECOV_CLIENTS); - - if (!obd->obd_set_up) { - CERROR("Device %d not setup\n", obd->obd_minor); - return -ENODEV; - } - - spin_lock(&obd->obd_dev_lock); - if (obd->obd_stopping) { - spin_unlock(&obd->obd_dev_lock); - CERROR("OBD %d already stopping\n", obd->obd_minor); - return -ENODEV; - } - /* Leave this on forever */ - obd->obd_stopping = 1; - spin_unlock(&obd->obd_dev_lock); - - while (obd->obd_conn_inprogress > 0) - cond_resched(); - smp_rmb(); - - if (lcfg->lcfg_bufcount >= 2 && LUSTRE_CFG_BUFLEN(lcfg, 1) > 0) { - for (flag = lustre_cfg_string(lcfg, 1); *flag != 0; flag++) - switch (*flag) { - case 'F': - obd->obd_force = 1; - break; - case 'A': - LCONSOLE_WARN("Failing over %s\n", - obd->obd_name); - obd->obd_fail = 1; - obd->obd_no_transno = 1; - obd->obd_no_recov = 1; - if (OBP(obd, iocontrol)) { - obd_iocontrol(OBD_IOC_SYNC, - obd->obd_self_export, - 0, NULL, NULL); - } - break; - default: - CERROR("Unrecognised flag '%c'\n", *flag); - } - } - - LASSERT(obd->obd_self_export); - - /* Precleanup, we must make sure all exports get destroyed. */ - err = obd_precleanup(obd); - if (err) - CERROR("Precleanup %s returned %d\n", - obd->obd_name, err); - - /* destroy an uuid-export hash body */ - if (obd->obd_uuid_hash) { - cfs_hash_putref(obd->obd_uuid_hash); - obd->obd_uuid_hash = NULL; - } - - class_decref(obd, "setup", obd); - obd->obd_set_up = 0; - - return 0; -} - -struct obd_device *class_incref(struct obd_device *obd, - const char *scope, const void *source) -{ - lu_ref_add_atomic(&obd->obd_reference, scope, source); - atomic_inc(&obd->obd_refcount); - CDEBUG(D_INFO, "incref %s (%p) now %d\n", obd->obd_name, obd, - atomic_read(&obd->obd_refcount)); - - return obd; -} -EXPORT_SYMBOL(class_incref); - -void class_decref(struct obd_device *obd, const char *scope, const void *source) -{ - int err; - int refs; - - spin_lock(&obd->obd_dev_lock); - atomic_dec(&obd->obd_refcount); - refs = atomic_read(&obd->obd_refcount); - spin_unlock(&obd->obd_dev_lock); - lu_ref_del(&obd->obd_reference, scope, source); - - CDEBUG(D_INFO, "Decref %s (%p) now %d\n", obd->obd_name, obd, refs); - - if ((refs == 1) && obd->obd_stopping) { - /* All exports have been destroyed; there should - * be no more in-progress ops by this point. - */ - - spin_lock(&obd->obd_self_export->exp_lock); - obd->obd_self_export->exp_flags |= exp_flags_from_obd(obd); - spin_unlock(&obd->obd_self_export->exp_lock); - - /* note that we'll recurse into class_decref again */ - class_unlink_export(obd->obd_self_export); - return; - } - - if (refs == 0) { - CDEBUG(D_CONFIG, "finishing cleanup of obd %s (%s)\n", - obd->obd_name, obd->obd_uuid.uuid); - LASSERT(!obd->obd_attached); - if (obd->obd_stopping) { - /* If we're not stopping, we were never set up */ - err = obd_cleanup(obd); - if (err) - CERROR("Cleanup %s returned %d\n", - obd->obd_name, err); - } - class_release_dev(obd); - } -} -EXPORT_SYMBOL(class_decref); - -/** Add a failover nid location. - * Client obd types contact server obd types using this nid list. - */ -static int class_add_conn(struct obd_device *obd, struct lustre_cfg *lcfg) -{ - struct obd_import *imp; - struct obd_uuid uuid; - int rc; - - if (LUSTRE_CFG_BUFLEN(lcfg, 1) < 1 || - LUSTRE_CFG_BUFLEN(lcfg, 1) > sizeof(struct obd_uuid)) { - CERROR("invalid conn_uuid\n"); - 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_OSP_NAME) && - strcmp(obd->obd_type->typ_name, LUSTRE_LWP_NAME) && - strcmp(obd->obd_type->typ_name, LUSTRE_MGC_NAME)) { - CERROR("can't add connection on non-client dev\n"); - return -EINVAL; - } - - imp = obd->u.cli.cl_import; - if (!imp) { - CERROR("try to add conn on immature client dev\n"); - return -EINVAL; - } - - obd_str2uuid(&uuid, lustre_cfg_string(lcfg, 1)); - rc = obd_add_conn(imp, &uuid, lcfg->lcfg_num); - - return rc; -} - -/** Remove a failover nid location. - */ -static int class_del_conn(struct obd_device *obd, struct lustre_cfg *lcfg) -{ - struct obd_import *imp; - struct obd_uuid uuid; - int rc; - - if (LUSTRE_CFG_BUFLEN(lcfg, 1) < 1 || - LUSTRE_CFG_BUFLEN(lcfg, 1) > sizeof(struct obd_uuid)) { - CERROR("invalid conn_uuid\n"); - return -EINVAL; - } - if (strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) && - strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME)) { - CERROR("can't del connection on non-client dev\n"); - return -EINVAL; - } - - imp = obd->u.cli.cl_import; - if (!imp) { - CERROR("try to del conn on immature client dev\n"); - return -EINVAL; - } - - obd_str2uuid(&uuid, lustre_cfg_string(lcfg, 1)); - rc = obd_del_conn(imp, &uuid); - - return rc; -} - -static LIST_HEAD(lustre_profile_list); -static DEFINE_SPINLOCK(lustre_profile_list_lock); - -struct lustre_profile *class_get_profile(const char *prof) -{ - struct lustre_profile *lprof; - - spin_lock(&lustre_profile_list_lock); - list_for_each_entry(lprof, &lustre_profile_list, lp_list) { - if (!strcmp(lprof->lp_profile, prof)) { - lprof->lp_refs++; - spin_unlock(&lustre_profile_list_lock); - return lprof; - } - } - spin_unlock(&lustre_profile_list_lock); - return NULL; -} -EXPORT_SYMBOL(class_get_profile); - -/** Create a named "profile". - * This defines the mdc and osc names to use for a client. - * This also is used to define the lov to be used by a mdt. - */ -static int class_add_profile(int proflen, char *prof, int osclen, char *osc, - int mdclen, char *mdc) -{ - struct lustre_profile *lprof; - int err = 0; - - CDEBUG(D_CONFIG, "Add profile %s\n", prof); - - lprof = kzalloc(sizeof(*lprof), GFP_NOFS); - if (!lprof) - return -ENOMEM; - INIT_LIST_HEAD(&lprof->lp_list); - - LASSERT(proflen == (strlen(prof) + 1)); - lprof->lp_profile = kmemdup(prof, proflen, GFP_NOFS); - if (!lprof->lp_profile) { - err = -ENOMEM; - goto free_lprof; - } - - LASSERT(osclen == (strlen(osc) + 1)); - lprof->lp_dt = kmemdup(osc, osclen, GFP_NOFS); - if (!lprof->lp_dt) { - err = -ENOMEM; - goto free_lp_profile; - } - - if (mdclen > 0) { - LASSERT(mdclen == (strlen(mdc) + 1)); - lprof->lp_md = kmemdup(mdc, mdclen, GFP_NOFS); - if (!lprof->lp_md) { - err = -ENOMEM; - goto free_lp_dt; - } - } - - spin_lock(&lustre_profile_list_lock); - lprof->lp_refs = 1; - lprof->lp_list_deleted = false; - list_add(&lprof->lp_list, &lustre_profile_list); - spin_unlock(&lustre_profile_list_lock); - return err; - -free_lp_dt: - kfree(lprof->lp_dt); -free_lp_profile: - kfree(lprof->lp_profile); -free_lprof: - kfree(lprof); - return err; -} - -void class_del_profile(const char *prof) -{ - struct lustre_profile *lprof; - - CDEBUG(D_CONFIG, "Del profile %s\n", prof); - - lprof = class_get_profile(prof); - if (lprof) { - spin_lock(&lustre_profile_list_lock); - /* because get profile increments the ref counter */ - lprof->lp_refs--; - list_del(&lprof->lp_list); - lprof->lp_list_deleted = true; - spin_unlock(&lustre_profile_list_lock); - - class_put_profile(lprof); - } -} -EXPORT_SYMBOL(class_del_profile); - -void class_put_profile(struct lustre_profile *lprof) -{ - spin_lock(&lustre_profile_list_lock); - if (--lprof->lp_refs > 0) { - LASSERT(lprof->lp_refs > 0); - spin_unlock(&lustre_profile_list_lock); - return; - } - spin_unlock(&lustre_profile_list_lock); - - /* confirm not a negative number */ - LASSERT(!lprof->lp_refs); - - /* - * At least one class_del_profile/profiles must be called - * on the target profile or lustre_profile_list will corrupt - */ - LASSERT(lprof->lp_list_deleted); - kfree(lprof->lp_profile); - kfree(lprof->lp_dt); - kfree(lprof->lp_md); - kfree(lprof); -} -EXPORT_SYMBOL(class_put_profile); - -/* COMPAT_146 */ -void class_del_profiles(void) -{ - struct lustre_profile *lprof, *n; - - spin_lock(&lustre_profile_list_lock); - list_for_each_entry_safe(lprof, n, &lustre_profile_list, lp_list) { - list_del(&lprof->lp_list); - lprof->lp_list_deleted = true; - spin_unlock(&lustre_profile_list_lock); - - class_put_profile(lprof); - - spin_lock(&lustre_profile_list_lock); - } - spin_unlock(&lustre_profile_list_lock); -} -EXPORT_SYMBOL(class_del_profiles); - -static int class_set_global(char *ptr, int val, struct lustre_cfg *lcfg) -{ - if (class_match_param(ptr, PARAM_AT_MIN, NULL) == 0) - at_min = val; - else if (class_match_param(ptr, PARAM_AT_MAX, NULL) == 0) - at_max = val; - else if (class_match_param(ptr, PARAM_AT_EXTRA, NULL) == 0) - at_extra = val; - else if (class_match_param(ptr, PARAM_AT_EARLY_MARGIN, NULL) == 0) - at_early_margin = val; - else if (class_match_param(ptr, PARAM_AT_HISTORY, NULL) == 0) - at_history = val; - else if (class_match_param(ptr, PARAM_JOBID_VAR, NULL) == 0) - strlcpy(obd_jobid_var, lustre_cfg_string(lcfg, 2), - JOBSTATS_JOBID_VAR_MAX_LEN + 1); - else - return -EINVAL; - - CDEBUG(D_IOCTL, "global %s = %d\n", ptr, val); - return 0; -} - -/* We can't call ll_process_config or lquota_process_config directly because - * it lives in a module that must be loaded after this one. - */ -static int (*client_process_config)(struct lustre_cfg *lcfg); -static int (*quota_process_config)(struct lustre_cfg *lcfg); - -void lustre_register_client_process_config(int (*cpc)(struct lustre_cfg *lcfg)) -{ - client_process_config = cpc; -} -EXPORT_SYMBOL(lustre_register_client_process_config); - -static int process_param2_config(struct lustre_cfg *lcfg) -{ - char *param = lustre_cfg_string(lcfg, 1); - char *upcall = lustre_cfg_string(lcfg, 2); - char *argv[] = { - [0] = "/usr/sbin/lctl", - [1] = "set_param", - [2] = param, - [3] = NULL - }; - ktime_t start; - ktime_t end; - int rc; - - /* Add upcall processing here. Now only lctl is supported */ - if (strcmp(upcall, LCTL_UPCALL) != 0) { - CERROR("Unsupported upcall %s\n", upcall); - return -EINVAL; - } - - start = ktime_get(); - rc = call_usermodehelper(argv[0], argv, NULL, UMH_WAIT_PROC); - end = ktime_get(); - - if (rc < 0) { - CERROR( - "lctl: error invoking upcall %s %s %s: rc = %d; time %ldus\n", - argv[0], argv[1], argv[2], rc, - (long)ktime_us_delta(end, start)); - } else { - CDEBUG(D_HA, "lctl: invoked upcall %s %s %s, time %ldus\n", - argv[0], argv[1], argv[2], - (long)ktime_us_delta(end, start)); - rc = 0; - } - - return rc; -} - -/** Process configuration commands given in lustre_cfg form. - * These may come from direct calls (e.g. class_manual_cleanup) - * or processing the config llog, or ioctl from lctl. - */ -int class_process_config(struct lustre_cfg *lcfg) -{ - struct obd_device *obd; - int err; - - LASSERT(lcfg && !IS_ERR(lcfg)); - CDEBUG(D_IOCTL, "processing cmd: %x\n", lcfg->lcfg_command); - - /* Commands that don't need a device */ - switch (lcfg->lcfg_command) { - case LCFG_ATTACH: { - err = class_attach(lcfg); - goto out; - } - case LCFG_ADD_UUID: { - CDEBUG(D_IOCTL, "adding mapping from uuid %s to nid %#llx (%s)\n", - lustre_cfg_string(lcfg, 1), lcfg->lcfg_nid, - libcfs_nid2str(lcfg->lcfg_nid)); - - err = class_add_uuid(lustre_cfg_string(lcfg, 1), lcfg->lcfg_nid); - goto out; - } - case LCFG_DEL_UUID: { - CDEBUG(D_IOCTL, "removing mappings for uuid %s\n", - (lcfg->lcfg_bufcount < 2 || LUSTRE_CFG_BUFLEN(lcfg, 1) == 0) - ? "<all uuids>" : lustre_cfg_string(lcfg, 1)); - - err = class_del_uuid(lustre_cfg_string(lcfg, 1)); - goto out; - } - case LCFG_MOUNTOPT: { - CDEBUG(D_IOCTL, "mountopt: profile %s osc %s mdc %s\n", - lustre_cfg_string(lcfg, 1), - lustre_cfg_string(lcfg, 2), - lustre_cfg_string(lcfg, 3)); - /* set these mount options somewhere, so ll_fill_super - * can find them. - */ - err = class_add_profile(LUSTRE_CFG_BUFLEN(lcfg, 1), - lustre_cfg_string(lcfg, 1), - LUSTRE_CFG_BUFLEN(lcfg, 2), - lustre_cfg_string(lcfg, 2), - LUSTRE_CFG_BUFLEN(lcfg, 3), - lustre_cfg_string(lcfg, 3)); - goto out; - } - case LCFG_DEL_MOUNTOPT: { - CDEBUG(D_IOCTL, "mountopt: profile %s\n", - lustre_cfg_string(lcfg, 1)); - class_del_profile(lustre_cfg_string(lcfg, 1)); - err = 0; - goto out; - } - case LCFG_SET_TIMEOUT: { - CDEBUG(D_IOCTL, "changing lustre timeout from %d to %d\n", - obd_timeout, lcfg->lcfg_num); - obd_timeout = max(lcfg->lcfg_num, 1U); - obd_timeout_set = 1; - err = 0; - goto out; - } - case LCFG_SET_LDLM_TIMEOUT: { - /* ldlm_timeout is not used on the client */ - err = 0; - goto out; - } - case LCFG_SET_UPCALL: { - LCONSOLE_ERROR_MSG(0x15a, "recovery upcall is deprecated\n"); - /* COMPAT_146 Don't fail on old configs */ - err = 0; - goto out; - } - case LCFG_MARKER: { - struct cfg_marker *marker; - - marker = lustre_cfg_buf(lcfg, 1); - CDEBUG(D_IOCTL, "marker %d (%#x) %.16s %s\n", marker->cm_step, - marker->cm_flags, marker->cm_tgtname, marker->cm_comment); - err = 0; - goto out; - } - case LCFG_PARAM: { - char *tmp; - /* llite has no obd */ - if ((class_match_param(lustre_cfg_string(lcfg, 1), - PARAM_LLITE, NULL) == 0) && - client_process_config) { - err = (*client_process_config)(lcfg); - goto out; - } else if ((class_match_param(lustre_cfg_string(lcfg, 1), - PARAM_SYS, &tmp) == 0)) { - /* Global param settings */ - err = class_set_global(tmp, lcfg->lcfg_num, lcfg); - /* - * Client or server should not fail to mount if - * it hits an unknown configuration parameter. - */ - if (err != 0) - CWARN("Ignoring unknown param %s\n", tmp); - - err = 0; - goto out; - } else if ((class_match_param(lustre_cfg_string(lcfg, 1), - PARAM_QUOTA, &tmp) == 0) && - quota_process_config) { - err = (*quota_process_config)(lcfg); - goto out; - } - - break; - } - case LCFG_SET_PARAM: { - err = process_param2_config(lcfg); - goto out; - } - } - /* Commands that require a device */ - obd = class_name2obd(lustre_cfg_string(lcfg, 0)); - if (!obd) { - if (!LUSTRE_CFG_BUFLEN(lcfg, 0)) - CERROR("this lcfg command requires a device name\n"); - else - CERROR("no device for: %s\n", - lustre_cfg_string(lcfg, 0)); - - err = -EINVAL; - goto out; - } - - switch (lcfg->lcfg_command) { - case LCFG_SETUP: { - err = class_setup(obd, lcfg); - goto out; - } - case LCFG_DETACH: { - err = class_detach(obd, lcfg); - err = 0; - goto out; - } - case LCFG_CLEANUP: { - err = class_cleanup(obd, lcfg); - err = 0; - goto out; - } - case LCFG_ADD_CONN: { - err = class_add_conn(obd, lcfg); - err = 0; - goto out; - } - case LCFG_DEL_CONN: { - err = class_del_conn(obd, lcfg); - err = 0; - goto out; - } - case LCFG_POOL_NEW: { - err = obd_pool_new(obd, lustre_cfg_string(lcfg, 2)); - err = 0; - goto out; - } - case LCFG_POOL_ADD: { - err = obd_pool_add(obd, lustre_cfg_string(lcfg, 2), - lustre_cfg_string(lcfg, 3)); - err = 0; - goto out; - } - case LCFG_POOL_REM: { - err = obd_pool_rem(obd, lustre_cfg_string(lcfg, 2), - lustre_cfg_string(lcfg, 3)); - err = 0; - goto out; - } - case LCFG_POOL_DEL: { - err = obd_pool_del(obd, lustre_cfg_string(lcfg, 2)); - err = 0; - goto out; - } - default: { - err = obd_process_config(obd, sizeof(*lcfg), lcfg); - goto out; - } - } -out: - if ((err < 0) && !(lcfg->lcfg_command & LCFG_REQUIRED)) { - CWARN("Ignoring error %d on optional command %#x\n", err, - lcfg->lcfg_command); - err = 0; - } - return err; -} -EXPORT_SYMBOL(class_process_config); - -int class_process_proc_param(char *prefix, struct lprocfs_vars *lvars, - struct lustre_cfg *lcfg, void *data) -{ - struct lprocfs_vars *var; - struct file fakefile; - struct seq_file fake_seqfile; - char *key, *sval; - int i, keylen, vallen; - int matched = 0, j = 0; - int rc = 0; - int skip = 0; - - if (lcfg->lcfg_command != LCFG_PARAM) { - CERROR("Unknown command: %d\n", lcfg->lcfg_command); - return -EINVAL; - } - - /* fake a seq file so that var->fops->write can work... */ - fakefile.private_data = &fake_seqfile; - fake_seqfile.private = data; - /* e.g. tunefs.lustre --param mdt.group_upcall=foo /r/tmp/lustre-mdt - * or lctl conf_param lustre-MDT0000.mdt.group_upcall=bar - * or lctl conf_param lustre-OST0000.osc.max_dirty_mb=36 - */ - for (i = 1; i < lcfg->lcfg_bufcount; i++) { - key = lustre_cfg_buf(lcfg, i); - /* Strip off prefix */ - if (class_match_param(key, prefix, &key)) { - /* - * If the prefix doesn't match, return error so we - * can pass it down the stack - */ - return -ENOSYS; - } - sval = strchr(key, '='); - if (!sval || (*(sval + 1) == 0)) { - CERROR("Can't parse param %s (missing '=')\n", key); - /* rc = -EINVAL; continue parsing other params */ - continue; - } - keylen = sval - key; - sval++; - vallen = strlen(sval); - matched = 0; - j = 0; - /* Search proc entries */ - while (lvars[j].name) { - var = &lvars[j]; - if (!class_match_param(key, var->name, NULL) && - keylen == strlen(var->name)) { - matched++; - rc = -EROFS; - if (var->fops && var->fops->write) { - mm_segment_t oldfs; - - oldfs = get_fs(); - set_fs(KERNEL_DS); - rc = var->fops->write(&fakefile, - (const char __user *)sval, - vallen, NULL); - set_fs(oldfs); - } - break; - } - j++; - } - if (!matched) { - CERROR("%.*s: %s unknown param %s\n", - (int)strlen(prefix) - 1, prefix, - (char *)lustre_cfg_string(lcfg, 0), key); - /* rc = -EINVAL; continue parsing other params */ - skip++; - } else if (rc < 0) { - CERROR("%s: error writing proc entry '%s': rc = %d\n", - prefix, var->name, rc); - rc = 0; - } else { - CDEBUG(D_CONFIG, "%s.%.*s: Set parameter %.*s=%s\n", - lustre_cfg_string(lcfg, 0), - (int)strlen(prefix) - 1, prefix, - (int)(sval - key - 1), key, sval); - } - } - - if (rc > 0) - rc = 0; - if (!rc && skip) - rc = skip; - return rc; -} -EXPORT_SYMBOL(class_process_proc_param); - -/** Parse a configuration llog, doing various manipulations on them - * for various reasons, (modifications for compatibility, skip obsolete - * records, change uuids, etc), then class_process_config() resulting - * net records. - */ -int class_config_llog_handler(const struct lu_env *env, - struct llog_handle *handle, - struct llog_rec_hdr *rec, void *data) -{ - struct config_llog_instance *clli = data; - int cfg_len = rec->lrh_len; - char *cfg_buf = (char *)(rec + 1); - int rc = 0; - - switch (rec->lrh_type) { - case OBD_CFG_REC: { - struct lustre_cfg *lcfg, *lcfg_new; - struct lustre_cfg_bufs bufs; - char *inst_name = NULL; - int inst_len = 0; - size_t lcfg_len; - int swab = 0; - - lcfg = (struct lustre_cfg *)cfg_buf; - if (lcfg->lcfg_version == __swab32(LUSTRE_CFG_VERSION)) { - lustre_swab_lustre_cfg(lcfg); - swab = 1; - } - - rc = lustre_cfg_sanity_check(cfg_buf, cfg_len); - if (rc) - goto out; - - /* Figure out config state info */ - if (lcfg->lcfg_command == LCFG_MARKER) { - struct cfg_marker *marker = lustre_cfg_buf(lcfg, 1); - - lustre_swab_cfg_marker(marker, swab, - LUSTRE_CFG_BUFLEN(lcfg, 1)); - CDEBUG(D_CONFIG, "Marker, inst_flg=%#x mark_flg=%#x\n", - clli->cfg_flags, marker->cm_flags); - if (marker->cm_flags & CM_START) { - /* all previous flags off */ - clli->cfg_flags = CFG_F_MARKER; - if (marker->cm_flags & CM_SKIP) { - clli->cfg_flags |= CFG_F_SKIP; - CDEBUG(D_CONFIG, "SKIP #%d\n", - marker->cm_step); - } else if ((marker->cm_flags & CM_EXCLUDE) || - (clli->cfg_sb && - lustre_check_exclusion(clli->cfg_sb, - marker->cm_tgtname))) { - clli->cfg_flags |= CFG_F_EXCLUDE; - CDEBUG(D_CONFIG, "EXCLUDE %d\n", - marker->cm_step); - } - } else if (marker->cm_flags & CM_END) { - clli->cfg_flags = 0; - } - } - /* A config command without a start marker before it is - * illegal (post 146) - */ - if (!(clli->cfg_flags & CFG_F_COMPAT146) && - !(clli->cfg_flags & CFG_F_MARKER) && - (lcfg->lcfg_command != LCFG_MARKER)) { - CWARN("Config not inside markers, ignoring! (inst: %p, uuid: %s, flags: %#x)\n", - clli->cfg_instance, - clli->cfg_uuid.uuid, clli->cfg_flags); - clli->cfg_flags |= CFG_F_SKIP; - } - if (clli->cfg_flags & CFG_F_SKIP) { - CDEBUG(D_CONFIG, "skipping %#x\n", - clli->cfg_flags); - rc = 0; - /* No processing! */ - break; - } - - /* - * For interoperability between 1.8 and 2.0, - * rename "mds" obd device type to "mdt". - */ - { - char *typename = lustre_cfg_string(lcfg, 1); - char *index = lustre_cfg_string(lcfg, 2); - - if ((lcfg->lcfg_command == LCFG_ATTACH && typename && - strcmp(typename, "mds") == 0)) { - CWARN("For 1.8 interoperability, rename obd type from mds to mdt\n"); - typename[2] = 't'; - } - if ((lcfg->lcfg_command == LCFG_SETUP && index && - strcmp(index, "type") == 0)) { - CDEBUG(D_INFO, "For 1.8 interoperability, set this index to '0'\n"); - index[0] = '0'; - index[1] = 0; - } - } - - if (clli->cfg_flags & CFG_F_EXCLUDE) { - CDEBUG(D_CONFIG, "cmd: %x marked EXCLUDED\n", - lcfg->lcfg_command); - if (lcfg->lcfg_command == LCFG_LOV_ADD_OBD) - /* Add inactive instead */ - lcfg->lcfg_command = LCFG_LOV_ADD_INA; - } - - lustre_cfg_bufs_init(&bufs, lcfg); - - if (clli && clli->cfg_instance && - LUSTRE_CFG_BUFLEN(lcfg, 0) > 0) { - inst_len = LUSTRE_CFG_BUFLEN(lcfg, 0) + - sizeof(clli->cfg_instance) * 2 + 4; - inst_name = kasprintf(GFP_NOFS, "%s-%p", - lustre_cfg_string(lcfg, 0), - clli->cfg_instance); - if (!inst_name) { - rc = -ENOMEM; - goto out; - } - lustre_cfg_bufs_set_string(&bufs, 0, inst_name); - CDEBUG(D_CONFIG, "cmd %x, instance name: %s\n", - lcfg->lcfg_command, inst_name); - } - - /* we override the llog's uuid for clients, to insure they - * are unique - */ - if (clli && clli->cfg_instance && - lcfg->lcfg_command == LCFG_ATTACH) { - lustre_cfg_bufs_set_string(&bufs, 2, - clli->cfg_uuid.uuid); - } - /* - * sptlrpc config record, we expect 2 data segments: - * [0]: fs_name/target_name, - * [1]: rule string - * moving them to index [1] and [2], and insert MGC's - * obdname at index [0]. - */ - if (clli && !clli->cfg_instance && - lcfg->lcfg_command == LCFG_SPTLRPC_CONF) { - lustre_cfg_bufs_set(&bufs, 2, bufs.lcfg_buf[1], - bufs.lcfg_buflen[1]); - lustre_cfg_bufs_set(&bufs, 1, bufs.lcfg_buf[0], - bufs.lcfg_buflen[0]); - lustre_cfg_bufs_set_string(&bufs, 0, - clli->cfg_obdname); - } - - lcfg_len = lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen); - lcfg_new = kzalloc(lcfg_len, GFP_NOFS); - if (!lcfg_new) { - rc = -ENOMEM; - goto out; - } - - lustre_cfg_init(lcfg_new, lcfg->lcfg_command, &bufs); - lcfg_new->lcfg_num = lcfg->lcfg_num; - lcfg_new->lcfg_flags = lcfg->lcfg_flags; - - /* XXX Hack to try to remain binary compatible with - * pre-newconfig logs - */ - if (lcfg->lcfg_nal != 0 && /* pre-newconfig log? */ - (lcfg->lcfg_nid >> 32) == 0) { - __u32 addr = (__u32)(lcfg->lcfg_nid & 0xffffffff); - - lcfg_new->lcfg_nid = - LNET_MKNID(LNET_MKNET(lcfg->lcfg_nal, 0), addr); - CWARN("Converted pre-newconfig NAL %d NID %x to %s\n", - lcfg->lcfg_nal, addr, - libcfs_nid2str(lcfg_new->lcfg_nid)); - } else { - lcfg_new->lcfg_nid = lcfg->lcfg_nid; - } - - lcfg_new->lcfg_nal = 0; /* illegal value for obsolete field */ - - rc = class_process_config(lcfg_new); - kfree(lcfg_new); - kfree(inst_name); - break; - } - default: - CERROR("Unknown llog record type %#x encountered\n", - rec->lrh_type); - break; - } -out: - if (rc) { - CERROR("%s: cfg command failed: rc = %d\n", - handle->lgh_ctxt->loc_obd->obd_name, rc); - class_config_dump_handler(NULL, handle, rec, data); - } - return rc; -} -EXPORT_SYMBOL(class_config_llog_handler); - -int class_config_parse_llog(const struct lu_env *env, struct llog_ctxt *ctxt, - char *name, struct config_llog_instance *cfg) -{ - struct llog_process_cat_data cd = {0, 0}; - struct llog_handle *llh; - llog_cb_t callback; - int rc; - - CDEBUG(D_INFO, "looking up llog %s\n", name); - rc = llog_open(env, ctxt, &llh, NULL, name, LLOG_OPEN_EXISTS); - if (rc) - return rc; - - rc = llog_init_handle(env, llh, LLOG_F_IS_PLAIN, NULL); - if (rc) - goto parse_out; - - /* continue processing from where we last stopped to end-of-log */ - if (cfg) { - cd.lpcd_first_idx = cfg->cfg_last_idx; - callback = cfg->cfg_callback; - LASSERT(callback); - } else { - callback = class_config_llog_handler; - } - - cd.lpcd_last_idx = 0; - - rc = llog_process(env, llh, callback, cfg, &cd); - - CDEBUG(D_CONFIG, "Processed log %s gen %d-%d (rc=%d)\n", name, - cd.lpcd_first_idx + 1, cd.lpcd_last_idx, rc); - if (cfg) - cfg->cfg_last_idx = cd.lpcd_last_idx; - -parse_out: - llog_close(env, llh); - return rc; -} -EXPORT_SYMBOL(class_config_parse_llog); - -/** - * parse config record and output dump in supplied buffer. - * This is separated from class_config_dump_handler() to use - * for ioctl needs as well - */ -static int class_config_parse_rec(struct llog_rec_hdr *rec, char *buf, - int size) -{ - struct lustre_cfg *lcfg = (struct lustre_cfg *)(rec + 1); - char *ptr = buf; - char *end = buf + size; - int rc = 0; - - LASSERT(rec->lrh_type == OBD_CFG_REC); - rc = lustre_cfg_sanity_check(lcfg, rec->lrh_len); - if (rc < 0) - return rc; - - ptr += snprintf(ptr, end - ptr, "cmd=%05x ", lcfg->lcfg_command); - if (lcfg->lcfg_flags) - ptr += snprintf(ptr, end - ptr, "flags=%#08x ", - lcfg->lcfg_flags); - - if (lcfg->lcfg_num) - ptr += snprintf(ptr, end - ptr, "num=%#08x ", lcfg->lcfg_num); - - if (lcfg->lcfg_nid) { - char nidstr[LNET_NIDSTR_SIZE]; - - libcfs_nid2str_r(lcfg->lcfg_nid, nidstr, sizeof(nidstr)); - ptr += snprintf(ptr, end - ptr, "nid=%s(%#llx)\n ", - nidstr, lcfg->lcfg_nid); - } - - if (lcfg->lcfg_command == LCFG_MARKER) { - struct cfg_marker *marker = lustre_cfg_buf(lcfg, 1); - - ptr += snprintf(ptr, end - ptr, "marker=%d(%#x)%s '%s'", - marker->cm_step, marker->cm_flags, - marker->cm_tgtname, marker->cm_comment); - } else { - int i; - - for (i = 0; i < lcfg->lcfg_bufcount; i++) { - ptr += snprintf(ptr, end - ptr, "%d:%s ", i, - lustre_cfg_string(lcfg, i)); - } - } - ptr += snprintf(ptr, end - ptr, "\n"); - /* return consumed bytes */ - rc = ptr - buf; - return rc; -} - -int class_config_dump_handler(const struct lu_env *env, - struct llog_handle *handle, - struct llog_rec_hdr *rec, void *data) -{ - char *outstr; - int rc = 0; - - outstr = kzalloc(256, GFP_NOFS); - if (!outstr) - return -ENOMEM; - - if (rec->lrh_type == OBD_CFG_REC) { - class_config_parse_rec(rec, outstr, 256); - LCONSOLE(D_WARNING, " %s", outstr); - } else { - LCONSOLE(D_WARNING, "unhandled lrh_type: %#x\n", rec->lrh_type); - rc = -EINVAL; - } - - kfree(outstr); - return rc; -} - -/** Call class_cleanup and class_detach. - * "Manual" only in the sense that we're faking lcfg commands. - */ -int class_manual_cleanup(struct obd_device *obd) -{ - char flags[3] = ""; - struct lustre_cfg *lcfg; - struct lustre_cfg_bufs bufs; - int rc; - - if (!obd) { - CERROR("empty cleanup\n"); - return -EALREADY; - } - - if (obd->obd_force) - strcat(flags, "F"); - if (obd->obd_fail) - strcat(flags, "A"); - - CDEBUG(D_CONFIG, "Manual cleanup of %s (flags='%s')\n", - obd->obd_name, flags); - - lustre_cfg_bufs_reset(&bufs, obd->obd_name); - lustre_cfg_bufs_set_string(&bufs, 1, flags); - lcfg = kzalloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen), - GFP_NOFS); - if (!lcfg) - return -ENOMEM; - lustre_cfg_init(lcfg, LCFG_CLEANUP, &bufs); - - rc = class_process_config(lcfg); - if (rc) { - CERROR("cleanup failed %d: %s\n", rc, obd->obd_name); - goto out; - } - - /* the lcfg is almost the same for both ops */ - lcfg->lcfg_command = LCFG_DETACH; - rc = class_process_config(lcfg); - if (rc) - CERROR("detach failed %d: %s\n", rc, obd->obd_name); -out: - kfree(lcfg); - return rc; -} -EXPORT_SYMBOL(class_manual_cleanup); - -/* - * uuid<->export lustre hash operations - */ - -static unsigned int -uuid_hash(struct cfs_hash *hs, const void *key, unsigned int mask) -{ - return cfs_hash_djb2_hash(((struct obd_uuid *)key)->uuid, - sizeof(((struct obd_uuid *)key)->uuid), mask); -} - -static void * -uuid_key(struct hlist_node *hnode) -{ - struct obd_export *exp; - - exp = hlist_entry(hnode, struct obd_export, exp_uuid_hash); - - return &exp->exp_client_uuid; -} - -/* - * NOTE: It is impossible to find an export that is in failed - * state with this function - */ -static int -uuid_keycmp(const void *key, struct hlist_node *hnode) -{ - struct obd_export *exp; - - LASSERT(key); - exp = hlist_entry(hnode, struct obd_export, exp_uuid_hash); - - return obd_uuid_equals(key, &exp->exp_client_uuid) && - !exp->exp_failed; -} - -static void * -uuid_export_object(struct hlist_node *hnode) -{ - return hlist_entry(hnode, struct obd_export, exp_uuid_hash); -} - -static void -uuid_export_get(struct cfs_hash *hs, struct hlist_node *hnode) -{ - struct obd_export *exp; - - exp = hlist_entry(hnode, struct obd_export, exp_uuid_hash); - class_export_get(exp); -} - -static void -uuid_export_put_locked(struct cfs_hash *hs, struct hlist_node *hnode) -{ - struct obd_export *exp; - - exp = hlist_entry(hnode, struct obd_export, exp_uuid_hash); - class_export_put(exp); -} - -static struct cfs_hash_ops uuid_hash_ops = { - .hs_hash = uuid_hash, - .hs_key = uuid_key, - .hs_keycmp = uuid_keycmp, - .hs_object = uuid_export_object, - .hs_get = uuid_export_get, - .hs_put_locked = uuid_export_put_locked, -}; diff --git a/drivers/staging/lustre/lustre/obdclass/obd_mount.c b/drivers/staging/lustre/lustre/obdclass/obd_mount.c deleted file mode 100644 index f5e8214ac37b..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/obd_mount.c +++ /dev/null @@ -1,1244 +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) 2007, 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. - * - * lustre/obdclass/obd_mount.c - * - * Client mount routines - * - * Author: Nathan Rutman <nathan@clusterfs.com> - */ - -#define DEBUG_SUBSYSTEM S_CLASS -#define D_MOUNT (D_SUPER | D_CONFIG/*|D_WARNING */) -#define PRINT_CMD CDEBUG - -#include <obd.h> -#include <lustre_compat.h> -#include <obd_class.h> -#include <uapi/linux/lustre/lustre_idl.h> -#include <lustre_log.h> -#include <lustre_disk.h> -#include <uapi/linux/lustre/lustre_param.h> - -static DEFINE_SPINLOCK(client_lock); -static struct module *client_mod; -static int (*client_fill_super)(struct super_block *sb); -static void (*kill_super_cb)(struct super_block *sb); - -/**************** config llog ********************/ - -/** Get a config log from the MGS and process it. - * This func is called for both clients and servers. - * Continue to process new statements appended to the logs - * (whenever the config lock is revoked) until lustre_end_log - * is called. - * @param sb The superblock is used by the MGC to write to the local copy of - * the config log - * @param logname The name of the llog to replicate from the MGS - * @param cfg Since the same mgc may be used to follow multiple config logs - * (e.g. ost1, ost2, client), the config_llog_instance keeps the state for - * this log, and is added to the mgc's list of logs to follow. - */ -int lustre_process_log(struct super_block *sb, char *logname, - struct config_llog_instance *cfg) -{ - struct lustre_cfg *lcfg; - struct lustre_cfg_bufs *bufs; - struct lustre_sb_info *lsi = s2lsi(sb); - struct obd_device *mgc = lsi->lsi_mgc; - int rc; - - LASSERT(mgc); - LASSERT(cfg); - - bufs = kzalloc(sizeof(*bufs), GFP_NOFS); - if (!bufs) - return -ENOMEM; - - /* mgc_process_config */ - lustre_cfg_bufs_reset(bufs, mgc->obd_name); - lustre_cfg_bufs_set_string(bufs, 1, logname); - lustre_cfg_bufs_set(bufs, 2, cfg, sizeof(*cfg)); - lustre_cfg_bufs_set(bufs, 3, &sb, sizeof(sb)); - lcfg = kzalloc(lustre_cfg_len(bufs->lcfg_bufcount, bufs->lcfg_buflen), - GFP_NOFS); - if (!lcfg) { - rc = -ENOMEM; - goto out; - } - lustre_cfg_init(lcfg, LCFG_LOG_START, bufs); - - rc = obd_process_config(mgc, sizeof(*lcfg), lcfg); - kfree(lcfg); -out: - kfree(bufs); - - if (rc == -EINVAL) - LCONSOLE_ERROR_MSG(0x15b, "%s: The configuration from log '%s' failed from the MGS (%d). Make sure this client and the MGS are running compatible versions of Lustre.\n", - mgc->obd_name, logname, rc); - - else if (rc) - LCONSOLE_ERROR_MSG(0x15c, "%s: The configuration from log '%s' failed (%d). This may be the result of communication errors between this node and the MGS, a bad configuration, or other errors. See the syslog for more information.\n", - mgc->obd_name, logname, - rc); - - /* class_obd_list(); */ - return rc; -} -EXPORT_SYMBOL(lustre_process_log); - -/* Stop watching this config log for updates */ -int lustre_end_log(struct super_block *sb, char *logname, - struct config_llog_instance *cfg) -{ - struct lustre_cfg *lcfg; - struct lustre_cfg_bufs bufs; - struct lustre_sb_info *lsi = s2lsi(sb); - struct obd_device *mgc = lsi->lsi_mgc; - int rc; - - if (!mgc) - return -ENOENT; - - /* mgc_process_config */ - lustre_cfg_bufs_reset(&bufs, mgc->obd_name); - lustre_cfg_bufs_set_string(&bufs, 1, logname); - if (cfg) - lustre_cfg_bufs_set(&bufs, 2, cfg, sizeof(*cfg)); - lcfg = kzalloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen), - GFP_NOFS); - if (!lcfg) - return -ENOMEM; - lustre_cfg_init(lcfg, LCFG_LOG_END, &bufs); - - rc = obd_process_config(mgc, sizeof(*lcfg), lcfg); - kfree(lcfg); - return rc; -} -EXPORT_SYMBOL(lustre_end_log); - -/**************** obd start *******************/ - -/** lustre_cfg_bufs are a holdover from 1.4; we can still set these up from - * lctl (and do for echo cli/srv. - */ -static int do_lcfg(char *cfgname, lnet_nid_t nid, int cmd, - char *s1, char *s2, char *s3, char *s4) -{ - struct lustre_cfg_bufs bufs; - struct lustre_cfg *lcfg = NULL; - int rc; - - CDEBUG(D_TRACE, "lcfg %s %#x %s %s %s %s\n", cfgname, - cmd, s1, s2, s3, s4); - - lustre_cfg_bufs_reset(&bufs, cfgname); - if (s1) - lustre_cfg_bufs_set_string(&bufs, 1, s1); - if (s2) - lustre_cfg_bufs_set_string(&bufs, 2, s2); - if (s3) - lustre_cfg_bufs_set_string(&bufs, 3, s3); - if (s4) - lustre_cfg_bufs_set_string(&bufs, 4, s4); - - lcfg = kzalloc(lustre_cfg_len(bufs.lcfg_bufcount, bufs.lcfg_buflen), - GFP_NOFS); - if (!lcfg) - return -ENOMEM; - lustre_cfg_init(lcfg, cmd, &bufs); - lcfg->lcfg_nid = nid; - rc = class_process_config(lcfg); - kfree(lcfg); - return rc; -} - -/** Call class_attach and class_setup. These methods in turn call - * obd type-specific methods. - */ -static int lustre_start_simple(char *obdname, char *type, char *uuid, - char *s1, char *s2, char *s3, char *s4) -{ - int rc; - - CDEBUG(D_MOUNT, "Starting obd %s (typ=%s)\n", obdname, type); - - rc = do_lcfg(obdname, 0, LCFG_ATTACH, type, uuid, NULL, NULL); - if (rc) { - CERROR("%s attach error %d\n", obdname, rc); - return rc; - } - rc = do_lcfg(obdname, 0, LCFG_SETUP, s1, s2, s3, s4); - if (rc) { - CERROR("%s setup error %d\n", obdname, rc); - do_lcfg(obdname, 0, LCFG_DETACH, NULL, NULL, NULL, NULL); - } - return rc; -} - -static DEFINE_MUTEX(mgc_start_lock); - -/** Set up a mgc obd to process startup logs - * - * \param sb [in] super block of the mgc obd - * - * \retval 0 success, otherwise error code - */ -int lustre_start_mgc(struct super_block *sb) -{ - struct obd_connect_data *data = NULL; - struct lustre_sb_info *lsi = s2lsi(sb); - struct obd_device *obd; - struct obd_export *exp; - struct obd_uuid *uuid; - class_uuid_t uuidc; - lnet_nid_t nid; - char nidstr[LNET_NIDSTR_SIZE]; - char *mgcname = NULL, *niduuid = NULL, *mgssec = NULL; - char *ptr; - int rc = 0, i = 0, j; - - LASSERT(lsi->lsi_lmd); - - /* Use nids from mount line: uml1,1@elan:uml2,2@elan:/lustre */ - ptr = lsi->lsi_lmd->lmd_dev; - if (class_parse_nid(ptr, &nid, &ptr) == 0) - i++; - if (i == 0) { - CERROR("No valid MGS nids found.\n"); - return -EINVAL; - } - - mutex_lock(&mgc_start_lock); - - libcfs_nid2str_r(nid, nidstr, sizeof(nidstr)); - mgcname = kasprintf(GFP_NOFS, - "%s%s", LUSTRE_MGC_OBDNAME, nidstr); - niduuid = kasprintf(GFP_NOFS, "%s_%x", mgcname, 0); - if (!mgcname || !niduuid) { - rc = -ENOMEM; - goto out_free; - } - - mgssec = lsi->lsi_lmd->lmd_mgssec ? lsi->lsi_lmd->lmd_mgssec : ""; - - data = kzalloc(sizeof(*data), GFP_NOFS); - if (!data) { - rc = -ENOMEM; - goto out_free; - } - - obd = class_name2obd(mgcname); - if (obd && !obd->obd_stopping) { - int recov_bk; - - rc = obd_set_info_async(NULL, obd->obd_self_export, - strlen(KEY_MGSSEC), KEY_MGSSEC, - strlen(mgssec), mgssec, NULL); - if (rc) - goto out_free; - - /* Re-using an existing MGC */ - atomic_inc(&obd->u.cli.cl_mgc_refcount); - - /* IR compatibility check, only for clients */ - if (lmd_is_client(lsi->lsi_lmd)) { - int has_ir; - int vallen = sizeof(*data); - __u32 *flags = &lsi->lsi_lmd->lmd_flags; - - rc = obd_get_info(NULL, obd->obd_self_export, - strlen(KEY_CONN_DATA), KEY_CONN_DATA, - &vallen, data); - LASSERT(rc == 0); - has_ir = OCD_HAS_FLAG(data, IMP_RECOV); - if (has_ir ^ !(*flags & LMD_FLG_NOIR)) { - /* LMD_FLG_NOIR is for test purpose only */ - LCONSOLE_WARN( - "Trying to mount a client with IR setting not compatible with current mgc. Force to use current mgc setting that is IR %s.\n", - has_ir ? "enabled" : "disabled"); - if (has_ir) - *flags &= ~LMD_FLG_NOIR; - else - *flags |= LMD_FLG_NOIR; - } - } - - recov_bk = 0; - - /* Try all connections, but only once (again). - * We don't want to block another target from starting - * (using its local copy of the log), but we do want to connect - * if at all possible. - */ - recov_bk++; - CDEBUG(D_MOUNT, "%s: Set MGC reconnect %d\n", mgcname, - recov_bk); - rc = obd_set_info_async(NULL, obd->obd_self_export, - sizeof(KEY_INIT_RECOV_BACKUP), - KEY_INIT_RECOV_BACKUP, - sizeof(recov_bk), &recov_bk, NULL); - rc = 0; - goto out; - } - - CDEBUG(D_MOUNT, "Start MGC '%s'\n", mgcname); - - /* Add the primary nids for the MGS */ - i = 0; - /* Use nids from mount line: uml1,1@elan:uml2,2@elan:/lustre */ - ptr = lsi->lsi_lmd->lmd_dev; - while (class_parse_nid(ptr, &nid, &ptr) == 0) { - rc = do_lcfg(mgcname, nid, - LCFG_ADD_UUID, niduuid, NULL, NULL, NULL); - if (!rc) - i++; - /* Stop at the first failover nid */ - if (*ptr == ':') - break; - } - if (i == 0) { - CERROR("No valid MGS nids found.\n"); - rc = -EINVAL; - goto out_free; - } - lsi->lsi_lmd->lmd_mgs_failnodes = 1; - - /* Random uuid for MGC allows easier reconnects */ - uuid = kzalloc(sizeof(*uuid), GFP_NOFS); - if (!uuid) { - rc = -ENOMEM; - goto out_free; - } - - ll_generate_random_uuid(uuidc); - class_uuid_unparse(uuidc, uuid); - - /* Start the MGC */ - rc = lustre_start_simple(mgcname, LUSTRE_MGC_NAME, - (char *)uuid->uuid, LUSTRE_MGS_OBDNAME, - niduuid, NULL, NULL); - kfree(uuid); - if (rc) - goto out_free; - - /* Add any failover MGS nids */ - i = 1; - while (ptr && ((*ptr == ':' || - class_find_param(ptr, PARAM_MGSNODE, &ptr) == 0))) { - /* New failover node */ - sprintf(niduuid, "%s_%x", mgcname, i); - j = 0; - while (class_parse_nid_quiet(ptr, &nid, &ptr) == 0) { - rc = do_lcfg(mgcname, nid, LCFG_ADD_UUID, niduuid, - NULL, NULL, NULL); - if (!rc) - ++j; - if (*ptr == ':') - break; - } - if (j > 0) { - rc = do_lcfg(mgcname, 0, LCFG_ADD_CONN, - niduuid, NULL, NULL, NULL); - if (!rc) - i++; - } else { - /* at ":/fsname" */ - break; - } - } - lsi->lsi_lmd->lmd_mgs_failnodes = i; - - obd = class_name2obd(mgcname); - if (!obd) { - CERROR("Can't find mgcobd %s\n", mgcname); - rc = -ENOTCONN; - goto out_free; - } - - rc = obd_set_info_async(NULL, obd->obd_self_export, - strlen(KEY_MGSSEC), KEY_MGSSEC, - strlen(mgssec), mgssec, NULL); - if (rc) - goto out_free; - - /* Keep a refcount of servers/clients who started with "mount", - * so we know when we can get rid of the mgc. - */ - atomic_set(&obd->u.cli.cl_mgc_refcount, 1); - - /* We connect to the MGS at setup, and don't disconnect until cleanup */ - data->ocd_connect_flags = OBD_CONNECT_VERSION | OBD_CONNECT_AT | - OBD_CONNECT_FULL20 | OBD_CONNECT_IMP_RECOV | - OBD_CONNECT_LVB_TYPE | OBD_CONNECT_BULK_MBITS; - -#if OBD_OCD_VERSION(3, 0, 53, 0) > LUSTRE_VERSION_CODE - data->ocd_connect_flags |= OBD_CONNECT_MNE_SWAB; -#endif - - if (lmd_is_client(lsi->lsi_lmd) && - lsi->lsi_lmd->lmd_flags & LMD_FLG_NOIR) - data->ocd_connect_flags &= ~OBD_CONNECT_IMP_RECOV; - data->ocd_version = LUSTRE_VERSION_CODE; - rc = obd_connect(NULL, &exp, obd, &obd->obd_uuid, data, NULL); - if (rc) { - CERROR("connect failed %d\n", rc); - goto out; - } - - obd->u.cli.cl_mgc_mgsexp = exp; - -out: - /* Keep the mgc info in the sb. Note that many lsi's can point - * to the same mgc. - */ - lsi->lsi_mgc = obd; -out_free: - mutex_unlock(&mgc_start_lock); - - kfree(data); - kfree(mgcname); - kfree(niduuid); - return rc; -} - -static int lustre_stop_mgc(struct super_block *sb) -{ - struct lustre_sb_info *lsi = s2lsi(sb); - struct obd_device *obd; - char *niduuid = NULL, *ptr = NULL; - int i, rc = 0, len = 0; - - if (!lsi) - return -ENOENT; - obd = lsi->lsi_mgc; - if (!obd) - return -ENOENT; - lsi->lsi_mgc = NULL; - - mutex_lock(&mgc_start_lock); - LASSERT(atomic_read(&obd->u.cli.cl_mgc_refcount) > 0); - if (!atomic_dec_and_test(&obd->u.cli.cl_mgc_refcount)) { - /* This is not fatal, every client that stops - * will call in here. - */ - CDEBUG(D_MOUNT, "mgc still has %d references.\n", - atomic_read(&obd->u.cli.cl_mgc_refcount)); - rc = -EBUSY; - goto out; - } - - /* The MGC has no recoverable data in any case. - * force shutdown set in umount_begin - */ - obd->obd_no_recov = 1; - - if (obd->u.cli.cl_mgc_mgsexp) { - /* An error is not fatal, if we are unable to send the - * disconnect mgs ping evictor cleans up the export - */ - rc = obd_disconnect(obd->u.cli.cl_mgc_mgsexp); - if (rc) - CDEBUG(D_MOUNT, "disconnect failed %d\n", rc); - } - - /* Save the obdname for cleaning the nid uuids, which are obdname_XX */ - len = strlen(obd->obd_name) + 6; - niduuid = kzalloc(len, GFP_NOFS); - if (niduuid) { - strcpy(niduuid, obd->obd_name); - ptr = niduuid + strlen(niduuid); - } - - rc = class_manual_cleanup(obd); - if (rc) - goto out; - - /* Clean the nid uuids */ - if (!niduuid) { - rc = -ENOMEM; - goto out; - } - - for (i = 0; i < lsi->lsi_lmd->lmd_mgs_failnodes; i++) { - sprintf(ptr, "_%x", i); - rc = do_lcfg(LUSTRE_MGC_OBDNAME, 0, LCFG_DEL_UUID, - niduuid, NULL, NULL, NULL); - if (rc) - CERROR("del MDC UUID %s failed: rc = %d\n", - niduuid, rc); - } -out: - kfree(niduuid); - - /* class_import_put will get rid of the additional connections */ - mutex_unlock(&mgc_start_lock); - return rc; -} - -/***************** lustre superblock **************/ - -static struct lustre_sb_info *lustre_init_lsi(struct super_block *sb) -{ - struct lustre_sb_info *lsi; - - lsi = kzalloc(sizeof(*lsi), GFP_NOFS); - if (!lsi) - return NULL; - lsi->lsi_lmd = kzalloc(sizeof(*lsi->lsi_lmd), GFP_NOFS); - if (!lsi->lsi_lmd) { - kfree(lsi); - return NULL; - } - - lsi->lsi_lmd->lmd_exclude_count = 0; - lsi->lsi_lmd->lmd_recovery_time_soft = 0; - lsi->lsi_lmd->lmd_recovery_time_hard = 0; - s2lsi_nocast(sb) = lsi; - /* we take 1 extra ref for our setup */ - atomic_set(&lsi->lsi_mounts, 1); - - /* Default umount style */ - lsi->lsi_flags = LSI_UMOUNT_FAILOVER; - - return lsi; -} - -static int lustre_free_lsi(struct super_block *sb) -{ - struct lustre_sb_info *lsi = s2lsi(sb); - - CDEBUG(D_MOUNT, "Freeing lsi %p\n", lsi); - - /* someone didn't call server_put_mount. */ - LASSERT(atomic_read(&lsi->lsi_mounts) == 0); - - if (lsi->lsi_lmd) { - kfree(lsi->lsi_lmd->lmd_dev); - kfree(lsi->lsi_lmd->lmd_profile); - kfree(lsi->lsi_lmd->lmd_mgssec); - kfree(lsi->lsi_lmd->lmd_opts); - if (lsi->lsi_lmd->lmd_exclude_count) - kfree(lsi->lsi_lmd->lmd_exclude); - kfree(lsi->lsi_lmd->lmd_mgs); - kfree(lsi->lsi_lmd->lmd_osd_type); - kfree(lsi->lsi_lmd->lmd_params); - - kfree(lsi->lsi_lmd); - } - - LASSERT(!lsi->lsi_llsbi); - kfree(lsi); - s2lsi_nocast(sb) = NULL; - - return 0; -} - -/* The lsi has one reference for every server that is using the disk - - * e.g. MDT, MGS, and potentially MGC - */ -static int lustre_put_lsi(struct super_block *sb) -{ - struct lustre_sb_info *lsi = s2lsi(sb); - - CDEBUG(D_MOUNT, "put %p %d\n", sb, atomic_read(&lsi->lsi_mounts)); - if (atomic_dec_and_test(&lsi->lsi_mounts)) { - lustre_free_lsi(sb); - return 1; - } - return 0; -} - -/*** SERVER NAME *** - * <FSNAME><SEPARATOR><TYPE><INDEX> - * FSNAME is between 1 and 8 characters (inclusive). - * Excluded characters are '/' and ':' - * SEPARATOR is either ':' or '-' - * TYPE: "OST", "MDT", etc. - * INDEX: Hex representation of the index - */ - -/** Get the fsname ("lustre") from the server name ("lustre-OST003F"). - * @param [in] svname server name including type and index - * @param [out] fsname Buffer to copy filesystem name prefix into. - * Must have at least 'strlen(fsname) + 1' chars. - * @param [out] endptr if endptr isn't NULL it is set to end of fsname - * rc < 0 on error - */ -static int server_name2fsname(const char *svname, char *fsname, - const char **endptr) -{ - const char *dash; - - dash = svname + strnlen(svname, 8); /* max fsname length is 8 */ - for (; dash > svname && *dash != '-' && *dash != ':'; dash--) - ; - if (dash == svname) - return -EINVAL; - - if (fsname) { - strncpy(fsname, svname, dash - svname); - fsname[dash - svname] = '\0'; - } - - if (endptr) - *endptr = dash; - - return 0; -} - -/* Get the index from the obd name. - * rc = server type, or - * rc < 0 on error - * if endptr isn't NULL it is set to end of name - */ -static int server_name2index(const char *svname, __u32 *idx, - const char **endptr) -{ - unsigned long index; - int rc; - const char *dash; - - /* We use server_name2fsname() just for parsing */ - rc = server_name2fsname(svname, NULL, &dash); - if (rc != 0) - return rc; - - dash++; - - if (strncmp(dash, "MDT", 3) == 0) - rc = LDD_F_SV_TYPE_MDT; - else if (strncmp(dash, "OST", 3) == 0) - rc = LDD_F_SV_TYPE_OST; - else - return -EINVAL; - - dash += 3; - - if (strncmp(dash, "all", 3) == 0) { - if (endptr) - *endptr = dash + 3; - return rc | LDD_F_SV_ALL; - } - - index = simple_strtoul(dash, (char **)endptr, 16); - if (idx) - *idx = index; - - /* Account for -mdc after index that is possible when specifying mdt */ - if (endptr && strncmp(LUSTRE_MDC_NAME, *endptr + 1, - sizeof(LUSTRE_MDC_NAME) - 1) == 0) - *endptr += sizeof(LUSTRE_MDC_NAME); - - return rc; -} - -/*************** mount common between server and client ***************/ - -/* Common umount */ -int lustre_common_put_super(struct super_block *sb) -{ - int rc; - - CDEBUG(D_MOUNT, "dropping sb %p\n", sb); - - /* Drop a ref to the MGC */ - rc = lustre_stop_mgc(sb); - if (rc && (rc != -ENOENT)) { - if (rc != -EBUSY) { - CERROR("Can't stop MGC: %d\n", rc); - return rc; - } - /* BUSY just means that there's some other obd that - * needs the mgc. Let him clean it up. - */ - CDEBUG(D_MOUNT, "MGC still in use\n"); - } - /* Drop a ref to the mounted disk */ - lustre_put_lsi(sb); - return rc; -} -EXPORT_SYMBOL(lustre_common_put_super); - -static void lmd_print(struct lustre_mount_data *lmd) -{ - int i; - - PRINT_CMD(D_MOUNT, " mount data:\n"); - if (lmd_is_client(lmd)) - PRINT_CMD(D_MOUNT, "profile: %s\n", lmd->lmd_profile); - PRINT_CMD(D_MOUNT, "device: %s\n", lmd->lmd_dev); - PRINT_CMD(D_MOUNT, "flags: %x\n", lmd->lmd_flags); - - if (lmd->lmd_opts) - PRINT_CMD(D_MOUNT, "options: %s\n", lmd->lmd_opts); - - if (lmd->lmd_recovery_time_soft) - PRINT_CMD(D_MOUNT, "recovery time soft: %d\n", - lmd->lmd_recovery_time_soft); - - if (lmd->lmd_recovery_time_hard) - PRINT_CMD(D_MOUNT, "recovery time hard: %d\n", - lmd->lmd_recovery_time_hard); - - for (i = 0; i < lmd->lmd_exclude_count; i++) { - PRINT_CMD(D_MOUNT, "exclude %d: OST%04x\n", i, - lmd->lmd_exclude[i]); - } -} - -/* Is this server on the exclusion list */ -int lustre_check_exclusion(struct super_block *sb, char *svname) -{ - struct lustre_sb_info *lsi = s2lsi(sb); - struct lustre_mount_data *lmd = lsi->lsi_lmd; - __u32 index; - int i, rc; - - rc = server_name2index(svname, &index, NULL); - if (rc != LDD_F_SV_TYPE_OST) - /* Only exclude OSTs */ - return 0; - - CDEBUG(D_MOUNT, "Check exclusion %s (%d) in %d of %s\n", svname, - index, lmd->lmd_exclude_count, lmd->lmd_dev); - - for (i = 0; i < lmd->lmd_exclude_count; i++) { - if (index == lmd->lmd_exclude[i]) { - CWARN("Excluding %s (on exclusion list)\n", svname); - return 1; - } - } - return 0; -} - -/* mount -v -o exclude=lustre-OST0001:lustre-OST0002 -t lustre ... */ -static int lmd_make_exclusion(struct lustre_mount_data *lmd, const char *ptr) -{ - const char *s1 = ptr, *s2; - __u32 index = 0, *exclude_list; - int rc = 0, devmax; - - /* The shortest an ost name can be is 8 chars: -OST0000. - * We don't actually know the fsname at this time, so in fact - * a user could specify any fsname. - */ - devmax = strlen(ptr) / 8 + 1; - - /* temp storage until we figure out how many we have */ - exclude_list = kcalloc(devmax, sizeof(index), GFP_NOFS); - if (!exclude_list) - return -ENOMEM; - - /* we enter this fn pointing at the '=' */ - while (*s1 && *s1 != ' ' && *s1 != ',') { - s1++; - rc = server_name2index(s1, &index, &s2); - if (rc < 0) { - CERROR("Can't parse server name '%s': rc = %d\n", - s1, rc); - break; - } - if (rc == LDD_F_SV_TYPE_OST) - exclude_list[lmd->lmd_exclude_count++] = index; - else - CDEBUG(D_MOUNT, "ignoring exclude %.*s: type = %#x\n", - (uint)(s2 - s1), s1, rc); - s1 = s2; - /* now we are pointing at ':' (next exclude) - * or ',' (end of excludes) - */ - if (lmd->lmd_exclude_count >= devmax) - break; - } - if (rc >= 0) /* non-err */ - rc = 0; - - if (lmd->lmd_exclude_count) { - /* permanent, freed in lustre_free_lsi */ - lmd->lmd_exclude = kcalloc(lmd->lmd_exclude_count, - sizeof(index), GFP_NOFS); - if (lmd->lmd_exclude) { - memcpy(lmd->lmd_exclude, exclude_list, - sizeof(index) * lmd->lmd_exclude_count); - } else { - rc = -ENOMEM; - lmd->lmd_exclude_count = 0; - } - } - kfree(exclude_list); - return rc; -} - -static int lmd_parse_mgssec(struct lustre_mount_data *lmd, char *ptr) -{ - char *tail; - int length; - - kfree(lmd->lmd_mgssec); - lmd->lmd_mgssec = NULL; - - tail = strchr(ptr, ','); - if (!tail) - length = strlen(ptr); - else - length = tail - ptr; - - lmd->lmd_mgssec = kzalloc(length + 1, GFP_NOFS); - if (!lmd->lmd_mgssec) - return -ENOMEM; - - memcpy(lmd->lmd_mgssec, ptr, length); - lmd->lmd_mgssec[length] = '\0'; - return 0; -} - -static int lmd_parse_string(char **handle, char *ptr) -{ - char *tail; - int length; - - if (!handle || !ptr) - return -EINVAL; - - kfree(*handle); - *handle = NULL; - - tail = strchr(ptr, ','); - if (!tail) - length = strlen(ptr); - else - length = tail - ptr; - - *handle = kzalloc(length + 1, GFP_NOFS); - if (!*handle) - return -ENOMEM; - - memcpy(*handle, ptr, length); - (*handle)[length] = '\0'; - - return 0; -} - -/* Collect multiple values for mgsnid specifiers */ -static int lmd_parse_mgs(struct lustre_mount_data *lmd, char **ptr) -{ - lnet_nid_t nid; - char *tail = *ptr; - char *mgsnid; - int length; - int oldlen = 0; - - /* Find end of nidlist */ - while (class_parse_nid_quiet(tail, &nid, &tail) == 0) - ; - length = tail - *ptr; - if (length == 0) { - LCONSOLE_ERROR_MSG(0x159, "Can't parse NID '%s'\n", *ptr); - return -EINVAL; - } - - if (lmd->lmd_mgs) - oldlen = strlen(lmd->lmd_mgs) + 1; - - mgsnid = kzalloc(oldlen + length + 1, GFP_NOFS); - if (!mgsnid) - return -ENOMEM; - - if (lmd->lmd_mgs) { - /* Multiple mgsnid= are taken to mean failover locations */ - memcpy(mgsnid, lmd->lmd_mgs, oldlen); - mgsnid[oldlen - 1] = ':'; - kfree(lmd->lmd_mgs); - } - memcpy(mgsnid + oldlen, *ptr, length); - mgsnid[oldlen + length] = '\0'; - lmd->lmd_mgs = mgsnid; - *ptr = tail; - - return 0; -} - -/** Parse mount line options - * e.g. mount -v -t lustre -o abort_recov uml1:uml2:/lustre-client /mnt/lustre - * dev is passed as device=uml1:/lustre by mount.lustre - */ -static int lmd_parse(char *options, struct lustre_mount_data *lmd) -{ - char *s1, *s2, *devname = NULL; - struct lustre_mount_data *raw = (struct lustre_mount_data *)options; - int rc = 0; - - LASSERT(lmd); - if (!options) { - LCONSOLE_ERROR_MSG(0x162, "Missing mount data: check that /sbin/mount.lustre is installed.\n"); - return -EINVAL; - } - - /* Options should be a string - try to detect old lmd data */ - if ((raw->lmd_magic & 0xffffff00) == (LMD_MAGIC & 0xffffff00)) { - LCONSOLE_ERROR_MSG(0x163, "You're using an old version of /sbin/mount.lustre. Please install version %s\n", - LUSTRE_VERSION_STRING); - return -EINVAL; - } - lmd->lmd_magic = LMD_MAGIC; - - lmd->lmd_params = kzalloc(LMD_PARAMS_MAXLEN, GFP_NOFS); - if (!lmd->lmd_params) - return -ENOMEM; - lmd->lmd_params[0] = '\0'; - - /* Set default flags here */ - - s1 = options; - while (*s1) { - int clear = 0; - int time_min = OBD_RECOVERY_TIME_MIN; - char *s3; - - /* Skip whitespace and extra commas */ - while (*s1 == ' ' || *s1 == ',') - s1++; - s3 = s1; - - /* Client options are parsed in ll_options: eg. flock, - * user_xattr, acl - */ - - /* Parse non-ldiskfs options here. Rather than modifying - * ldiskfs, we just zero these out here - */ - if (strncmp(s1, "abort_recov", 11) == 0) { - lmd->lmd_flags |= LMD_FLG_ABORT_RECOV; - clear++; - } else if (strncmp(s1, "recovery_time_soft=", 19) == 0) { - lmd->lmd_recovery_time_soft = max_t(int, - simple_strtoul(s1 + 19, NULL, 10), time_min); - clear++; - } else if (strncmp(s1, "recovery_time_hard=", 19) == 0) { - lmd->lmd_recovery_time_hard = max_t(int, - simple_strtoul(s1 + 19, NULL, 10), time_min); - clear++; - } else if (strncmp(s1, "noir", 4) == 0) { - lmd->lmd_flags |= LMD_FLG_NOIR; /* test purpose only. */ - clear++; - } else if (strncmp(s1, "nosvc", 5) == 0) { - lmd->lmd_flags |= LMD_FLG_NOSVC; - clear++; - } else if (strncmp(s1, "nomgs", 5) == 0) { - lmd->lmd_flags |= LMD_FLG_NOMGS; - clear++; - } else if (strncmp(s1, "noscrub", 7) == 0) { - lmd->lmd_flags |= LMD_FLG_NOSCRUB; - clear++; - } else if (strncmp(s1, PARAM_MGSNODE, - sizeof(PARAM_MGSNODE) - 1) == 0) { - s2 = s1 + sizeof(PARAM_MGSNODE) - 1; - /* Assume the next mount opt is the first - * invalid nid we get to. - */ - rc = lmd_parse_mgs(lmd, &s2); - if (rc) - goto invalid; - clear++; - } else if (strncmp(s1, "writeconf", 9) == 0) { - lmd->lmd_flags |= LMD_FLG_WRITECONF; - clear++; - } else if (strncmp(s1, "update", 6) == 0) { - lmd->lmd_flags |= LMD_FLG_UPDATE; - clear++; - } else if (strncmp(s1, "virgin", 6) == 0) { - lmd->lmd_flags |= LMD_FLG_VIRGIN; - clear++; - } else if (strncmp(s1, "noprimnode", 10) == 0) { - lmd->lmd_flags |= LMD_FLG_NO_PRIMNODE; - clear++; - } else if (strncmp(s1, "mgssec=", 7) == 0) { - rc = lmd_parse_mgssec(lmd, s1 + 7); - if (rc) - goto invalid; - s3 = s2; - clear++; - /* ost exclusion list */ - } else if (strncmp(s1, "exclude=", 8) == 0) { - rc = lmd_make_exclusion(lmd, s1 + 7); - if (rc) - goto invalid; - clear++; - } else if (strncmp(s1, "mgs", 3) == 0) { - /* We are an MGS */ - lmd->lmd_flags |= LMD_FLG_MGS; - clear++; - } else if (strncmp(s1, "svname=", 7) == 0) { - rc = lmd_parse_string(&lmd->lmd_profile, s1 + 7); - if (rc) - goto invalid; - clear++; - } else if (strncmp(s1, "param=", 6) == 0) { - size_t length, params_length; - char *tail = strchr(s1 + 6, ','); - - if (!tail) { - length = strlen(s1); - } else { - lnet_nid_t nid; - char *param_str = tail + 1; - int supplementary = 1; - - while (!class_parse_nid_quiet(param_str, &nid, - ¶m_str)) { - supplementary = 0; - } - length = param_str - s1 - supplementary; - } - length -= 6; - params_length = strlen(lmd->lmd_params); - if (params_length + length + 1 >= LMD_PARAMS_MAXLEN) - return -E2BIG; - strncat(lmd->lmd_params, s1 + 6, length); - lmd->lmd_params[params_length + length] = '\0'; - strlcat(lmd->lmd_params, " ", LMD_PARAMS_MAXLEN); - s3 = s1 + 6 + length; - clear++; - } else if (strncmp(s1, "osd=", 4) == 0) { - rc = lmd_parse_string(&lmd->lmd_osd_type, s1 + 4); - if (rc) - goto invalid; - clear++; - } - /* Linux 2.4 doesn't pass the device, so we stuck it at the - * end of the options. - */ - else if (strncmp(s1, "device=", 7) == 0) { - devname = s1 + 7; - /* terminate options right before device. device - * must be the last one. - */ - *s1 = '\0'; - break; - } - - /* Find next opt */ - s2 = strchr(s1, ','); - if (!s2) { - if (clear) - *s1 = '\0'; - break; - } - s2++; - if (clear) - memmove(s1, s2, strlen(s2) + 1); - else - s1 = s2; - } - - if (!devname) { - LCONSOLE_ERROR_MSG(0x164, "Can't find the device name (need mount option 'device=...')\n"); - goto invalid; - } - - s1 = strstr(devname, ":/"); - if (s1) { - ++s1; - lmd->lmd_flags |= LMD_FLG_CLIENT; - /* Remove leading /s from fsname */ - while (*++s1 == '/') - ; - /* Freed in lustre_free_lsi */ - lmd->lmd_profile = kasprintf(GFP_NOFS, "%s-client", s1); - if (!lmd->lmd_profile) - return -ENOMEM; - } - - /* Freed in lustre_free_lsi */ - lmd->lmd_dev = kzalloc(strlen(devname) + 1, GFP_NOFS); - if (!lmd->lmd_dev) - return -ENOMEM; - strcpy(lmd->lmd_dev, devname); - - /* Save mount options */ - s1 = options + strlen(options) - 1; - while (s1 >= options && (*s1 == ',' || *s1 == ' ')) - *s1-- = 0; - if (*options != 0) { - /* Freed in lustre_free_lsi */ - lmd->lmd_opts = kzalloc(strlen(options) + 1, GFP_NOFS); - if (!lmd->lmd_opts) - return -ENOMEM; - strcpy(lmd->lmd_opts, options); - } - - lmd_print(lmd); - lmd->lmd_magic = LMD_MAGIC; - - return rc; - -invalid: - CERROR("Bad mount options %s\n", options); - return -EINVAL; -} - -/** This is the entry point for the mount call into Lustre. - * This is called when a server or client is mounted, - * and this is where we start setting things up. - * @param data Mount options (e.g. -o flock,abort_recov) - */ -static int lustre_fill_super(struct super_block *sb, void *lmd2_data, int silent) -{ - struct lustre_mount_data *lmd; - struct lustre_sb_info *lsi; - int rc; - - CDEBUG(D_MOUNT | D_VFSTRACE, "VFS Op: sb %p\n", sb); - - lsi = lustre_init_lsi(sb); - if (!lsi) - return -ENOMEM; - lmd = lsi->lsi_lmd; - - /* - * Disable lockdep during mount, because mount locking patterns are - * `special'. - */ - lockdep_off(); - - /* - * LU-639: the obd cleanup of last mount may not finish yet, wait here. - */ - obd_zombie_barrier(); - - /* Figure out the lmd from the mount options */ - if (lmd_parse(lmd2_data, lmd)) { - lustre_put_lsi(sb); - rc = -EINVAL; - goto out; - } - - if (lmd_is_client(lmd)) { - bool have_client = false; - CDEBUG(D_MOUNT, "Mounting client %s\n", lmd->lmd_profile); - if (!client_fill_super) - request_module("lustre"); - spin_lock(&client_lock); - if (client_fill_super && try_module_get(client_mod)) - have_client = true; - spin_unlock(&client_lock); - if (!have_client) { - LCONSOLE_ERROR_MSG(0x165, "Nothing registered for client mount! Is the 'lustre' module loaded?\n"); - lustre_put_lsi(sb); - rc = -ENODEV; - } else { - rc = lustre_start_mgc(sb); - if (rc) { - lustre_common_put_super(sb); - goto out; - } - /* Connect and start */ - /* (should always be ll_fill_super) */ - rc = (*client_fill_super)(sb); - /* c_f_s will call lustre_common_put_super on failure, otherwise - * c_f_s will have taken another reference to the module */ - module_put(client_mod); - } - } else { - CERROR("This is client-side-only module, cannot handle server mount.\n"); - rc = -EINVAL; - } - - /* If error happens in fill_super() call, @lsi will be killed there. - * This is why we do not put it here. - */ - goto out; -out: - if (rc) { - CERROR("Unable to mount %s (%d)\n", - s2lsi(sb) ? lmd->lmd_dev : "", rc); - } else { - CDEBUG(D_SUPER, "Mount %s complete\n", - lmd->lmd_dev); - } - lockdep_on(); - return rc; -} - -/* We can't call ll_fill_super by name because it lives in a module that - * must be loaded after this one. - */ -void lustre_register_super_ops(struct module *mod, - int (*cfs)(struct super_block *sb), - void (*ksc)(struct super_block *sb)) -{ - spin_lock(&client_lock); - client_mod = mod; - client_fill_super = cfs; - kill_super_cb = ksc; - spin_unlock(&client_lock); -} -EXPORT_SYMBOL(lustre_register_super_ops); - -/***************** FS registration ******************/ -static struct dentry *lustre_mount(struct file_system_type *fs_type, int flags, - const char *devname, void *data) -{ - return mount_nodev(fs_type, flags, data, lustre_fill_super); -} - -static void lustre_kill_super(struct super_block *sb) -{ - struct lustre_sb_info *lsi = s2lsi(sb); - - if (kill_super_cb && lsi) - (*kill_super_cb)(sb); - - kill_anon_super(sb); -} - -/** Register the "lustre" fs type - */ -static struct file_system_type lustre_fs_type = { - .owner = THIS_MODULE, - .name = "lustre", - .mount = lustre_mount, - .kill_sb = lustre_kill_super, - .fs_flags = FS_RENAME_DOES_D_MOVE, -}; -MODULE_ALIAS_FS("lustre"); - -int lustre_register_fs(void) -{ - return register_filesystem(&lustre_fs_type); -} - -int lustre_unregister_fs(void) -{ - return unregister_filesystem(&lustre_fs_type); -} diff --git a/drivers/staging/lustre/lustre/obdclass/obdo.c b/drivers/staging/lustre/lustre/obdclass/obdo.c deleted file mode 100644 index c4503bc36591..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/obdo.c +++ /dev/null @@ -1,181 +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) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2011, 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lustre/obdclass/obdo.c - * - * Object Devices Class Driver - * These are the only exported functions, they provide some generic - * infrastructure for managing object devices - */ - -#define DEBUG_SUBSYSTEM S_CLASS - -#include <obd_class.h> -#include <uapi/linux/lustre/lustre_idl.h> -#include <lustre_obdo.h> - -void obdo_set_parent_fid(struct obdo *dst, const struct lu_fid *parent) -{ - dst->o_parent_oid = fid_oid(parent); - dst->o_parent_seq = fid_seq(parent); - dst->o_parent_ver = fid_ver(parent); - dst->o_valid |= OBD_MD_FLGENER | OBD_MD_FLFID; -} -EXPORT_SYMBOL(obdo_set_parent_fid); - -/* WARNING: the file systems must take care not to tinker with - * attributes they don't manage (such as blocks). - */ -void obdo_from_inode(struct obdo *dst, struct inode *src, u32 valid) -{ - u32 newvalid = 0; - - if (valid & (OBD_MD_FLCTIME | OBD_MD_FLMTIME)) - CDEBUG(D_INODE, "valid %x, new time %lu/%lu\n", - valid, LTIME_S(src->i_mtime), - LTIME_S(src->i_ctime)); - - if (valid & OBD_MD_FLATIME) { - dst->o_atime = LTIME_S(src->i_atime); - newvalid |= OBD_MD_FLATIME; - } - if (valid & OBD_MD_FLMTIME) { - dst->o_mtime = LTIME_S(src->i_mtime); - newvalid |= OBD_MD_FLMTIME; - } - if (valid & OBD_MD_FLCTIME) { - dst->o_ctime = LTIME_S(src->i_ctime); - newvalid |= OBD_MD_FLCTIME; - } - if (valid & OBD_MD_FLSIZE) { - dst->o_size = i_size_read(src); - newvalid |= OBD_MD_FLSIZE; - } - if (valid & OBD_MD_FLBLOCKS) { /* allocation of space (x512 bytes) */ - dst->o_blocks = src->i_blocks; - newvalid |= OBD_MD_FLBLOCKS; - } - if (valid & OBD_MD_FLBLKSZ) { /* optimal block size */ - dst->o_blksize = 1 << src->i_blkbits; - newvalid |= OBD_MD_FLBLKSZ; - } - if (valid & OBD_MD_FLTYPE) { - dst->o_mode = (dst->o_mode & S_IALLUGO) | - (src->i_mode & S_IFMT); - newvalid |= OBD_MD_FLTYPE; - } - if (valid & OBD_MD_FLMODE) { - dst->o_mode = (dst->o_mode & S_IFMT) | - (src->i_mode & S_IALLUGO); - newvalid |= OBD_MD_FLMODE; - } - if (valid & OBD_MD_FLUID) { - dst->o_uid = from_kuid(&init_user_ns, src->i_uid); - newvalid |= OBD_MD_FLUID; - } - if (valid & OBD_MD_FLGID) { - dst->o_gid = from_kgid(&init_user_ns, src->i_gid); - newvalid |= OBD_MD_FLGID; - } - if (valid & OBD_MD_FLFLAGS) { - dst->o_flags = src->i_flags; - newvalid |= OBD_MD_FLFLAGS; - } - dst->o_valid |= newvalid; -} -EXPORT_SYMBOL(obdo_from_inode); - -void obdo_to_ioobj(const struct obdo *oa, struct obd_ioobj *ioobj) -{ - ioobj->ioo_oid = oa->o_oi; - if (unlikely(!(oa->o_valid & OBD_MD_FLGROUP))) - ostid_set_seq_mdt0(&ioobj->ioo_oid); - - /* Since 2.4 this does not contain o_mode in the low 16 bits. - * Instead, it holds (bd_md_max_brw - 1) for multi-bulk BRW RPCs - */ - ioobj->ioo_max_brw = 0; -} -EXPORT_SYMBOL(obdo_to_ioobj); - -/** - * Create an obdo to send over the wire - */ -void lustre_set_wire_obdo(const struct obd_connect_data *ocd, - struct obdo *wobdo, const struct obdo *lobdo) -{ - *wobdo = *lobdo; - wobdo->o_flags &= ~OBD_FL_LOCAL_MASK; - if (!ocd) - return; - - if (unlikely(!(ocd->ocd_connect_flags & OBD_CONNECT_FID)) && - fid_seq_is_echo(ostid_seq(&lobdo->o_oi))) { - /* - * Currently OBD_FL_OSTID will only be used when 2.4 echo - * client communicate with pre-2.4 server - */ - wobdo->o_oi.oi.oi_id = fid_oid(&lobdo->o_oi.oi_fid); - wobdo->o_oi.oi.oi_seq = fid_seq(&lobdo->o_oi.oi_fid); - } -} -EXPORT_SYMBOL(lustre_set_wire_obdo); - -/** - * Create a local obdo from a wire based odbo - */ -void lustre_get_wire_obdo(const struct obd_connect_data *ocd, - struct obdo *lobdo, const struct obdo *wobdo) -{ - u32 local_flags = 0; - - if (lobdo->o_valid & OBD_MD_FLFLAGS) - local_flags = lobdo->o_flags & OBD_FL_LOCAL_MASK; - - *lobdo = *wobdo; - if (local_flags) { - lobdo->o_valid |= OBD_MD_FLFLAGS; - lobdo->o_flags &= ~OBD_FL_LOCAL_MASK; - lobdo->o_flags |= local_flags; - } - if (!ocd) - return; - - if (unlikely(!(ocd->ocd_connect_flags & OBD_CONNECT_FID)) && - fid_seq_is_echo(wobdo->o_oi.oi.oi_seq)) { - /* see above */ - lobdo->o_oi.oi_fid.f_seq = wobdo->o_oi.oi.oi_seq; - lobdo->o_oi.oi_fid.f_oid = wobdo->o_oi.oi.oi_id; - lobdo->o_oi.oi_fid.f_ver = 0; - } -} -EXPORT_SYMBOL(lustre_get_wire_obdo); diff --git a/drivers/staging/lustre/lustre/obdclass/statfs_pack.c b/drivers/staging/lustre/lustre/obdclass/statfs_pack.c deleted file mode 100644 index 355e888885f4..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/statfs_pack.c +++ /dev/null @@ -1,58 +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. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lustre/obdclass/statfs_pack.c - * - * (Un)packing of OST/MDS requests - * - * Author: Andreas Dilger <adilger@clusterfs.com> - */ - -#define DEBUG_SUBSYSTEM S_CLASS - -#include <linux/statfs.h> -#include <lustre_export.h> -#include <lustre_net.h> -#include <obd_support.h> -#include <obd_class.h> - -void statfs_unpack(struct kstatfs *sfs, struct obd_statfs *osfs) -{ - memset(sfs, 0, sizeof(*sfs)); - sfs->f_type = osfs->os_type; - sfs->f_blocks = osfs->os_blocks; - sfs->f_bfree = osfs->os_bfree; - sfs->f_bavail = osfs->os_bavail; - sfs->f_files = osfs->os_files; - sfs->f_ffree = osfs->os_ffree; - sfs->f_bsize = osfs->os_bsize; - sfs->f_namelen = osfs->os_namelen; -} -EXPORT_SYMBOL(statfs_unpack); diff --git a/drivers/staging/lustre/lustre/obdclass/uuid.c b/drivers/staging/lustre/lustre/obdclass/uuid.c deleted file mode 100644 index 6cf7a03f048f..000000000000 --- a/drivers/staging/lustre/lustre/obdclass/uuid.c +++ /dev/null @@ -1,47 +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. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lustre/obdclass/uuid.c - * - * Public include file for the UUID library - */ - -#define DEBUG_SUBSYSTEM S_CLASS - -#include <linux/libcfs/libcfs.h> - -#include <obd_support.h> -#include <obd_class.h> - -void class_uuid_unparse(class_uuid_t uu, struct obd_uuid *out) -{ - sprintf(out->uuid, "%pU", uu); -} -EXPORT_SYMBOL(class_uuid_unparse); |