diff options
Diffstat (limited to 'drivers/staging/lustre/lustre/libcfs/lwt.c')
-rw-r--r-- | drivers/staging/lustre/lustre/libcfs/lwt.c | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/drivers/staging/lustre/lustre/libcfs/lwt.c b/drivers/staging/lustre/lustre/libcfs/lwt.c new file mode 100644 index 000000000000..b631f7dde8e7 --- /dev/null +++ b/drivers/staging/lustre/lustre/libcfs/lwt.c @@ -0,0 +1,266 @@ +/* + * 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.sun.com/software/products/lustre/docs/GPLv2.pdf + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * GPL HEADER END + */ +/* + * Copyright (c) 2008, 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. + * + * libcfs/libcfs/lwt.c + * + * Author: Eric Barton <eeb@clusterfs.com> + */ + +#define DEBUG_SUBSYSTEM S_LNET + +#include <linux/libcfs/libcfs.h> + +#if LWT_SUPPORT + +#if !KLWT_SUPPORT +int lwt_enabled; +lwt_cpu_t lwt_cpus[NR_CPUS]; +#endif + +int lwt_pages_per_cpu; + +/* NB only root is allowed to retrieve LWT info; it's an open door into the + * kernel... */ + +int +lwt_lookup_string (int *size, char *knl_ptr, + char *user_ptr, int user_size) +{ + int maxsize = 128; + + /* knl_ptr was retrieved from an LWT snapshot and the caller wants to + * turn it into a string. NB we can crash with an access violation + * trying to determine the string length, so we're trusting our + * caller... */ + + if (!cfs_capable(CFS_CAP_SYS_ADMIN)) + return (-EPERM); + + if (user_size > 0 && + maxsize > user_size) + maxsize = user_size; + + *size = strnlen (knl_ptr, maxsize - 1) + 1; + + if (user_ptr != NULL) { + if (user_size < 4) + return (-EINVAL); + + if (copy_to_user (user_ptr, knl_ptr, *size)) + return (-EFAULT); + + /* Did I truncate the string? */ + if (knl_ptr[*size - 1] != 0) + copy_to_user (user_ptr + *size - 4, "...", 4); + } + + return (0); +} + +int +lwt_control (int enable, int clear) +{ + lwt_page_t *p; + int i; + int j; + + if (!cfs_capable(CFS_CAP_SYS_ADMIN)) + return (-EPERM); + + if (!enable) { + LWT_EVENT(0,0,0,0); + lwt_enabled = 0; + mb(); + /* give people some time to stop adding traces */ + schedule_timeout(10); + } + + for (i = 0; i < num_online_cpus(); i++) { + p = lwt_cpus[i].lwtc_current_page; + + if (p == NULL) + return (-ENODATA); + + if (!clear) + continue; + + for (j = 0; j < lwt_pages_per_cpu; j++) { + memset (p->lwtp_events, 0, PAGE_CACHE_SIZE); + + p = list_entry (p->lwtp_list.next, + lwt_page_t, lwtp_list); + } + } + + if (enable) { + lwt_enabled = 1; + mb(); + LWT_EVENT(0,0,0,0); + } + + return (0); +} + +int +lwt_snapshot (cfs_cycles_t *now, int *ncpu, int *total_size, + void *user_ptr, int user_size) +{ + const int events_per_page = PAGE_CACHE_SIZE / sizeof(lwt_event_t); + const int bytes_per_page = events_per_page * sizeof(lwt_event_t); + lwt_page_t *p; + int i; + int j; + + if (!cfs_capable(CFS_CAP_SYS_ADMIN)) + return (-EPERM); + + *ncpu = num_online_cpus(); + *total_size = num_online_cpus() * lwt_pages_per_cpu * + bytes_per_page; + *now = get_cycles(); + + if (user_ptr == NULL) + return (0); + + for (i = 0; i < num_online_cpus(); i++) { + p = lwt_cpus[i].lwtc_current_page; + + if (p == NULL) + return (-ENODATA); + + for (j = 0; j < lwt_pages_per_cpu; j++) { + if (copy_to_user(user_ptr, p->lwtp_events, + bytes_per_page)) + return (-EFAULT); + + user_ptr = ((char *)user_ptr) + bytes_per_page; + p = list_entry(p->lwtp_list.next, + lwt_page_t, lwtp_list); + } + } + + return (0); +} + +int +lwt_init () +{ + int i; + int j; + + for (i = 0; i < num_online_cpus(); i++) + if (lwt_cpus[i].lwtc_current_page != NULL) + return (-EALREADY); + + LASSERT (!lwt_enabled); + + /* NULL pointers, zero scalars */ + memset (lwt_cpus, 0, sizeof (lwt_cpus)); + lwt_pages_per_cpu = + LWT_MEMORY / (num_online_cpus() * PAGE_CACHE_SIZE); + + for (i = 0; i < num_online_cpus(); i++) + for (j = 0; j < lwt_pages_per_cpu; j++) { + struct page *page = alloc_page (GFP_KERNEL); + lwt_page_t *lwtp; + + if (page == NULL) { + CERROR ("Can't allocate page\n"); + lwt_fini (); + return (-ENOMEM); + } + + LIBCFS_ALLOC(lwtp, sizeof (*lwtp)); + if (lwtp == NULL) { + CERROR ("Can't allocate lwtp\n"); + __free_page(page); + lwt_fini (); + return (-ENOMEM); + } + + lwtp->lwtp_page = page; + lwtp->lwtp_events = page_address(page); + memset (lwtp->lwtp_events, 0, PAGE_CACHE_SIZE); + + if (j == 0) { + INIT_LIST_HEAD (&lwtp->lwtp_list); + lwt_cpus[i].lwtc_current_page = lwtp; + } else { + list_add (&lwtp->lwtp_list, + &lwt_cpus[i].lwtc_current_page->lwtp_list); + } + } + + lwt_enabled = 1; + mb(); + + LWT_EVENT(0,0,0,0); + + return (0); +} + +void +lwt_fini () +{ + int i; + + lwt_control(0, 0); + + for (i = 0; i < num_online_cpus(); i++) + while (lwt_cpus[i].lwtc_current_page != NULL) { + lwt_page_t *lwtp = lwt_cpus[i].lwtc_current_page; + + if (list_empty (&lwtp->lwtp_list)) { + lwt_cpus[i].lwtc_current_page = NULL; + } else { + lwt_cpus[i].lwtc_current_page = + list_entry (lwtp->lwtp_list.next, + lwt_page_t, lwtp_list); + + list_del (&lwtp->lwtp_list); + } + + __free_page (lwtp->lwtp_page); + LIBCFS_FREE (lwtp, sizeof (*lwtp)); + } +} + +EXPORT_SYMBOL(lwt_enabled); +EXPORT_SYMBOL(lwt_cpus); + +EXPORT_SYMBOL(lwt_init); +EXPORT_SYMBOL(lwt_fini); +EXPORT_SYMBOL(lwt_lookup_string); +EXPORT_SYMBOL(lwt_control); +EXPORT_SYMBOL(lwt_snapshot); +#endif |