Whamcloud - gitweb
LU-1576 llite: correct page usage count
[fs/lustre-release.git] / lnet / klnds / ptllnd / ptllnd_ptltrace.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  */
30 /*
31  * This file is part of Lustre, http://www.lustre.org/
32  * Lustre is a trademark of Sun Microsystems, Inc.
33  */
34
35 #include "ptllnd.h"
36
37 #ifdef CRAY_XT3
38 static cfs_mutex_t        ptltrace_mutex;
39 static cfs_waitq_t        ptltrace_debug_ctlwq;
40
41 void
42 kptllnd_ptltrace_to_file(char *filename)
43 {
44         CFS_DECL_JOURNAL_DATA;
45         CFS_DECL_MMSPACE;
46
47         cfs_file_t *filp;
48         char       *start;
49         char       *tmpbuf;
50         int         len;
51         int         rc;
52         loff_t      offset = 0;
53         int         eof = 0;
54
55         CWARN("dumping ptltrace to %s\n", filename);
56
57         LIBCFS_ALLOC(tmpbuf, PAGE_SIZE);
58         if (tmpbuf == NULL) {
59                 CERROR("Can't allocate page buffer to dump %s\n", filename);
60                 return;
61         }
62         
63         CFS_PUSH_JOURNAL;
64
65         filp = cfs_filp_open(filename,
66                              O_CREAT|O_EXCL|O_WRONLY|O_LARGEFILE, 0600, &rc);
67         if (filp == NULL) {
68                 if (rc != -EEXIST)
69                         CERROR("Error %d creating %s\n", rc, filename);
70                 goto out;
71         }
72
73         CFS_MMSPACE_OPEN;
74
75         while (!eof) { 
76                 start = NULL; 
77                 len = ptl_proc_read(tmpbuf, &start, offset,
78                                     PAGE_SIZE, &eof, NULL);
79
80                 /* we don't allow ptl_proc_read to mimic case 0 or 1 behavior
81                  * for a proc_read method, only #2: from proc_file_read
82                  *
83                  * 2) Set *start = an address within the buffer.
84                  *    Put the data of the requested offset at *start.
85                  *    Return the number of bytes of data placed there.
86                  *    If this number is greater than zero and you
87                  *    didn't signal eof and the reader is prepared to
88                  *    take more data you will be called again with the
89                  *    requested offset advanced by the number of bytes
90                  *    absorbed.
91                  */
92
93                 if (len == 0)   /* end of file */
94                         break;
95
96                 if (len < 0) {
97                         CERROR("ptl_proc_read: error %d\n", len);
98                         break;
99                 }
100
101                 if (start < tmpbuf || start + len > tmpbuf + PAGE_SIZE) {
102                         CERROR("ptl_proc_read bug: %p for %d not in %p for %ld\n",
103                                start, len, tmpbuf, PAGE_SIZE);
104                         break;
105                 }
106
107                 rc = cfs_filp_write(filp, start, len, cfs_filp_poff(filp));
108                 if (rc != len) {
109                         if (rc < 0)
110                                 CERROR("Error %d writing %s\n", rc, filename);
111                         else
112                                 CERROR("Partial write %d(%d) to %s\n",
113                                        rc, len, filename);
114                         break;
115                 }
116
117                 offset += len;
118         }
119
120         CFS_MMSPACE_CLOSE;
121
122         rc = cfs_filp_fsync(filp);
123         if (rc != 0)
124                 CERROR("Error %d syncing %s\n", rc, filename);
125
126         cfs_filp_close(filp);
127 out:
128         CFS_POP_JOURNAL;
129         LIBCFS_FREE(tmpbuf, PAGE_SIZE);
130 }
131
132 int
133 kptllnd_dump_ptltrace_thread(void *arg)
134 {
135         static char fname[1024];
136
137         libcfs_daemonize("kpt_ptltrace_dump");
138
139         /* serialise with other instances of me */
140         cfs_mutex_lock(&ptltrace_mutex);
141
142         snprintf(fname, sizeof(fname), "%s.%ld.%ld",
143                  *kptllnd_tunables.kptl_ptltrace_basename,
144                  cfs_time_current_sec(), (long)arg);
145
146         kptllnd_ptltrace_to_file(fname);
147
148         cfs_mutex_unlock(&ptltrace_mutex);
149
150         /* unblock my creator */
151         cfs_waitq_signal(&ptltrace_debug_ctlwq);
152         return 0;
153 }
154
155 void
156 kptllnd_dump_ptltrace(void)
157 {
158         int            rc;
159         cfs_waitlink_t wait;
160         ENTRY;
161
162         /* taken from libcfs_debug_dumplog */
163         cfs_waitlink_init(&wait);
164         cfs_set_current_state(CFS_TASK_INTERRUPTIBLE);
165         cfs_waitq_add(&ptltrace_debug_ctlwq, &wait);
166
167         rc = cfs_create_thread(kptllnd_dump_ptltrace_thread,
168                                (void *)(long)cfs_curproc_pid(),
169                                CFS_DAEMON_FLAGS | CLONE_FS);
170         if (rc < 0) {
171                 CERROR("Error %d starting ptltrace dump thread\n", rc);
172         } else {
173                 cfs_waitq_wait(&wait, CFS_TASK_INTERRUPTIBLE);
174         }
175
176         /* teardown if cfs_kernel_thread() failed */
177         cfs_waitq_del(&ptltrace_debug_ctlwq, &wait);
178         cfs_set_current_state(CFS_TASK_RUNNING);
179         EXIT;
180 }
181
182 void
183 kptllnd_init_ptltrace(void)
184 {
185         cfs_waitq_init(&ptltrace_debug_ctlwq);
186         cfs_mutex_init(&ptltrace_mutex);
187 }
188 #endif