aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/lustre/lustre/libcfs/lwt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/lustre/lustre/libcfs/lwt.c')
-rw-r--r--drivers/staging/lustre/lustre/libcfs/lwt.c266
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