1 jelson 1.1 /*
2 * EMLOG: the EMbedded-device LOGger
3 *
|
4 jelson 1.6 * Jeremy Elson <jelson@circlemud.org>
5 * USC/Information Sciences Institute
|
6 jelson 1.1 *
|
7 jelson 1.6 * This code is released under the GPL
8 *
9 * This is emlog version 0.40, released 13 August 2001
10 * For more information see http://www.circlemud.org/~jelson/software/emlog
11 *
|
12 jelson 1.7 * $Id: emlog.c,v 1.6 2001/08/13 21:12:48 jelson Exp $
|
13 jelson 1.1 */
14
|
15 jelson 1.3 #ifdef MODVERSIONS
16 #include <linux/modversions.h>
17 #endif
|
18 jelson 1.1
19 #include <linux/config.h>
20 #include <linux/stddef.h>
21 #include <linux/tqueue.h>
22 #include <linux/sched.h>
23 #include <linux/kernel.h>
24 #ifdef MODULE
25 #include <linux/module.h>
26 #endif
27 #include <linux/timer.h>
28 #include <linux/delay.h>
29 #include <linux/errno.h>
30 #include <linux/malloc.h>
|
31 jelson 1.4 #include <linux/vmalloc.h>
|
32 jelson 1.1 #include <linux/types.h>
33 #include <linux/fs.h>
34 #include <linux/poll.h>
35
36 #include <asm/uaccess.h>
37
38
39 #include "emlog.h"
40
41 MODULE_PARM(emlog_debug, "i");
42
43 struct emlog_info *emlog_info_list = NULL;
44 static int emlog_debug;
45
46 #define MIN(x, y) ((x) < (y) ? (x) : y)
47
48
49 /* find the emlog-info structure associated with an inode. returns a
50 * pointer to the structure if found, NULL if not found */
51 static struct emlog_info *get_einfo(struct inode *inode)
52 {
53 jelson 1.1 struct emlog_info *einfo;
54
55 if (inode == NULL)
56 return NULL;
57
58 for (einfo = emlog_info_list; einfo != NULL; einfo = einfo->next)
|
59 jelson 1.7 if (einfo->i_ino == inode->i_ino && einfo->i_dev == inode->i_dev)
|
60 jelson 1.1 return einfo;
61
62 return NULL;
63 }
64
65
66 /* create a new emlog buffer and its associated info structure.
67 * returns an errno on failure, or 0 on success. on success, the
68 * pointer to the new struct is passed back using peinfo */
69 static int create_einfo(struct inode *inode, int minor,
70 struct emlog_info **peinfo)
71 {
72 struct emlog_info *einfo;
73
74 /* make sure the memory requirement is legal */
75 if (minor < 1 || minor > EMLOG_MAX_SIZE)
76 return -EINVAL;
77
|
78 jelson 1.5 /* allocate space for our metadata and initialize it */
|
79 jelson 1.1 if ((einfo = kmalloc(sizeof(struct emlog_info), GFP_KERNEL)) == NULL)
80 goto struct_malloc_failed;
81
|
82 jelson 1.5 memset(einfo, 0, sizeof(struct emlog_info));
|
83 jelson 1.1 einfo->i_ino = inode->i_ino;
|
84 jelson 1.7 einfo->i_dev = inode->i_dev;
|
85 jelson 1.2
86 #if defined(DECLARE_WAIT_QUEUE_HEAD)
|
87 jelson 1.6 init_waitqueue_head(EMLOG_READQ(einfo));
|
88 jelson 1.2 #else
|
89 jelson 1.6 init_waitqueue(EMLOG_READQ(einfo));
|
90 jelson 1.2 #endif
91
|
92 jelson 1.5 /* figure out how much of a buffer this should be and allocate the buffer */
93 einfo->size = 1024 * minor;
94 if ((einfo->data = (char *) vmalloc(sizeof(char) * einfo->size)) == NULL)
95 goto data_malloc_failed;
96
|
97 jelson 1.1 /* add it to our linked list */
98 einfo->next = emlog_info_list;
99 emlog_info_list = einfo;
100
101 if (emlog_debug)
|
102 jelson 1.6 printk("allocating resources associated with inode %ld\n", einfo->i_ino);
|
103 jelson 1.1
104 /* pass the struct back */
105 *peinfo = einfo;
106 return 0;
107
|
108 jelson 1.6 #if 0
|
109 jelson 1.1 other_failure: /* if we check for other errors later, jump here */
|
110 jelson 1.6 #endif
|
111 jelson 1.4 vfree(einfo->data);
|
112 jelson 1.1 data_malloc_failed:
113 kfree(einfo);
114 struct_malloc_failed:
115 return -ENOMEM;
116 }
117
118
119 /* this frees all data associated with an emlog_info buffer, including
120 * the struct that you pass to the function. don't dereference this
121 * structure after calling free_einfo! */
122 void free_einfo(struct emlog_info *einfo)
123 {
124 struct emlog_info **ptr;
125
126 if (einfo == NULL) {
127 printk("null passed to free_einfo... which is bad\n");
128 return;
129 }
130
131 if (emlog_debug)
|
132 jelson 1.6 printk("freeing resources associated with inode %ld\n", einfo->i_ino);
|
133 jelson 1.1
|
134 jelson 1.4 vfree(einfo->data);
|
135 jelson 1.1
136 /* now delete the 'einfo' structure from the linked list. 'ptr' is
137 * the pointer that needs to be changed... which is either the list
138 * head or one of the 'next' pointers on the list. */
139 ptr = &emlog_info_list;
140 while (*ptr != einfo) {
141 if (!*ptr) {
142 printk("corrupt einfo list!\n");
143 break;
144 } else
145 ptr = &((**ptr).next);
146
147 }
148 *ptr = einfo->next;
149
150
151 }
152
153
154
155 /************************ File Interface Functions ************************/
156 jelson 1.1
157
158
159 static int emlog_open(struct inode *inode, struct file *file)
160 {
161 int minor = MINOR(inode->i_rdev);
162
163 struct emlog_info *einfo = NULL;
164 int retval;
165
166 if ((einfo = get_einfo(inode)) == NULL) {
167 /* never heard of this inode before... create a new record */
168 if ((retval = create_einfo(inode, minor, &einfo)) < 0)
169 return retval;
170 }
171
172 if (einfo == NULL) {
173 printk("BUG IN EMLOG!\n");
174 return -EIO;
175 }
176
|
177 jelson 1.5 einfo->refcount++;
|
178 jelson 1.1 MOD_INC_USE_COUNT;
179 return 0;
180 }
181
182
183 /* this is called when a file is closed */
184 static int emlog_release(struct inode *inode, struct file *file)
185 {
186 struct emlog_info *einfo;
|
187 jelson 1.6 int retval = 0;
|
188 jelson 1.1
189 /* get the buffer info */
190 if ((einfo = get_einfo(inode)) == NULL) {
191 printk("emlog: releasing unknown file! zoinks!\n");
192 return -EINVAL;
|
193 jelson 1.6 goto out;
|
194 jelson 1.1 }
195
196 /* decrement the reference count. if no one has this file open and
197 * it's not holding any data, delete the record. */
198 einfo->refcount--;
199
|
200 jelson 1.6 if (einfo->refcount == 0 && EMLOG_QLEN(einfo) == 0)
|
201 jelson 1.1 free_einfo(einfo);
202
|
203 jelson 1.6 out:
204 MOD_DEC_USE_COUNT;
205 return retval;
|
206 jelson 1.1 }
207
208
209 /* read_from_emlog reads bytes out of a circular buffer with
210 * wraparound. returns caddr_t, pointer to data read, which the
|
211 jelson 1.5 * caller must free. length is (a pointer to) the number of bytes to
212 * be read, which will be set by this function to be the number of
213 * bytes actually returned */
214 caddr_t read_from_emlog(struct emlog_info *einfo, int *length, loff_t *offset)
|
215 jelson 1.1 {
216 caddr_t retval;
|
217 jelson 1.5 int bytes_copied = 0, n, start_point, remaining;
218
219 /* is the user trying to read data that has already scrolled off? */
220 if (*offset < einfo->offset)
221 *offset = einfo->offset;
222
223 /* is the user trying to read past EOF? */
|
224 jelson 1.6 if (*offset >= EMLOG_FIRST_EMPTY_BYTE(einfo))
|
225 jelson 1.1 return NULL;
226
|
227 jelson 1.5 /* find the smaller of the total bytes we have available and what
228 * the user is asking for */
|
229 jelson 1.6 *length = MIN(*length, EMLOG_FIRST_EMPTY_BYTE(einfo) - *offset);
|
230 jelson 1.5 remaining = *length;
231
232 /* figure out where to start based on user's offset */
233 start_point = einfo->read_point + (*offset - einfo->offset);
234 start_point = start_point % einfo->size;
235
236 /* allocate memory to return */
237 if ((retval = kmalloc(sizeof(char) * remaining, GFP_KERNEL)) == NULL)
|
238 jelson 1.1 return NULL;
239
|
240 jelson 1.5 /* copy the (possibly noncontiguous) data to our buffer */
241 while (remaining) {
242 n = MIN(remaining, einfo->size - start_point);
243 memcpy(retval + bytes_copied, einfo->data + start_point, n);
|
244 jelson 1.1 bytes_copied += n;
|
245 jelson 1.5 remaining -= n;
246 start_point = (start_point + n) % einfo->size;
|
247 jelson 1.1 }
248
|
249 jelson 1.5 /* advance user's file pointer */
250 *offset += *length;
|
251 jelson 1.1 return retval;
252 }
253
254 static ssize_t emlog_read(struct file *file,
255 char *buffer, /* The buffer to fill with data */
256 size_t length, /* The length of the buffer */
257 loff_t *offset) /* Our offset in the file */
258 {
|
259 jelson 1.5 int retval;
|
260 jelson 1.1 caddr_t data_to_return;
261 struct emlog_info *einfo;
262
|
263 jelson 1.5 /* get the metadata about this emlog */
|
264 jelson 1.1 if ((einfo = get_einfo(file->f_dentry->d_inode)) == NULL) {
265 printk("emlog_read: record not found\n");
266 return -EIO;
267 }
268
269 /* wait until there's data available (unless we do nonblocking reads) */
|
270 jelson 1.6 while (*offset >= EMLOG_FIRST_EMPTY_BYTE(einfo)) {
|
271 jelson 1.1 if (file->f_flags & O_NONBLOCK)
272 return -EAGAIN;
273
|
274 jelson 1.2 interruptible_sleep_on(EMLOG_READQ(einfo));
|
275 jelson 1.1
276 /* see if a signal woke us up */
277 if (signal_pending(current))
278 return -ERESTARTSYS;
279 }
280
|
281 jelson 1.5 if ((data_to_return = read_from_emlog(einfo, &length, offset)) == NULL)
282 return 0;
|
283 jelson 1.1
|
284 jelson 1.5 if (copy_to_user(buffer, data_to_return, length) > 0)
|
285 jelson 1.1 retval = -EFAULT;
286 else
|
287 jelson 1.5 retval = length;
|
288 jelson 1.1 kfree(data_to_return);
289 return retval;
290 }
291
292
293
294 /* write_to_emlog writes to a circular buffer with wraparound. in the
295 * case of an overflow, it overwrites the oldest unread data. */
296 void write_to_emlog(struct emlog_info *einfo, caddr_t buf, int length)
297 {
|
298 jelson 1.5 int bytes_copied = 0;
299 int overflow = 0;
300 int n;
301
302 if (length + EMLOG_QLEN(einfo) >= (einfo->size-1)) {
303 overflow = 1;
|
304 jelson 1.1
|
305 jelson 1.5 /* in case of overflow, figure out where the new buffer will
306 * begin. we start by figuring out where the current buffer ENDS:
307 * einfo->offset + EMLOG_QLEN. we then advance the end-offset
308 * by the length of the current write, and work backwards to
309 * figure out what the oldest unoverwritten data will be (i.e.,
310 * size of the buffer). was that all quite clear? :-) */
311 einfo->offset = einfo->offset + EMLOG_QLEN(einfo) + length
312 - einfo->size + 1;
313 }
|
314 jelson 1.1
315 while (length) {
|
316 jelson 1.5 /* how many contiguous bytes are available from the write point to
317 * the end of the circular buffer? */
318 n = MIN(length, einfo->size - einfo->write_point);
|
319 jelson 1.1 memcpy(einfo->data + einfo->write_point, buf + bytes_copied, n);
320 bytes_copied += n;
321 length -= n;
322 einfo->write_point = (einfo->write_point + n) % einfo->size;
323 }
324
325 /* if there is an overflow, reset the read point to read whatever is
326 * the oldest data that we have, that has not yet been
327 * overwritten. */
328 if (overflow)
329 einfo->read_point = (einfo->write_point + 1) % einfo->size;
330 }
331
332
333 static ssize_t emlog_write(struct file *file,
334 const char *buffer,
335 size_t length,
336 loff_t *offset)
337 {
338 caddr_t message = NULL;
339 int n;
340 jelson 1.1 struct emlog_info *einfo;
341
|
342 jelson 1.5 /* get the metadata about this emlog */
|
343 jelson 1.1 if ((einfo = get_einfo(file->f_dentry->d_inode)) == NULL)
344 return -EIO;
345
346 /* if the message is longer than the buffer, just take the beginning
347 * of it, in hopes that the reader (if any) will have time to read
348 * before we wrap around and obliterate it */
349 n = MIN(length, einfo->size - 1);
350
351 /* make sure we have the memory for it */
352 if ((message = kmalloc(n, GFP_KERNEL)) == NULL)
353 return -ENOMEM;
354
|
355 jelson 1.5 /* copy into our temp buffer */
|
356 jelson 1.1 if (copy_from_user(message, buffer, n) > 0) {
357 kfree(message);
358 return -EFAULT;
359 }
360
|
361 jelson 1.5 /* now copy it into the circular buffer and free our temp copy */
|
362 jelson 1.1 write_to_emlog(einfo, message, n);
363 kfree(message);
|
364 jelson 1.5
365 /* wake up any readers that might be waiting for the data. we call
366 * schedule in the vague hope that a reader will run before the
367 * writer's next write, to avoid losing data. */
|
368 jelson 1.2 wake_up_interruptible(EMLOG_READQ(einfo));
|
369 jelson 1.5
|
370 jelson 1.1 return n;
371 }
372
|
373 jelson 1.2
374 static unsigned int emlog_poll(struct file *file, poll_table *wait)
375 {
376 struct emlog_info *einfo;
377
|
378 jelson 1.5 /* get the metadata about this emlog */
|
379 jelson 1.2 if ((einfo = get_einfo(file->f_dentry->d_inode)) == NULL)
380 return -EIO;
381
382 poll_wait(file, EMLOG_READQ(einfo), wait);
383
|
384 jelson 1.6 if (file->f_pos < EMLOG_FIRST_EMPTY_BYTE(einfo))
|
385 jelson 1.2 return POLLIN | POLLRDNORM;
386 else
387 return 0;
388 }
389
390
|
391 jelson 1.1 static struct file_operations emlog_fops = {
|
392 jelson 1.2 read : emlog_read,
393 write : emlog_write,
394 open : emlog_open,
395 release: emlog_release,
396 poll : emlog_poll,
|
397 jelson 1.1 };
398
399
400 int init_module(void)
401 {
402 if (register_chrdev(EMLOG_MAJOR_NUMBER, "emlog", &emlog_fops) < 0) {
403 printk("emlog: unable to register character device %d\n",
404 EMLOG_MAJOR_NUMBER);
405 return -EIO;
|
406 jelson 1.6 } else {
407 printk("emlog: version %s running, using major number %d\n", EMLOG_VERSION,
408 EMLOG_MAJOR_NUMBER);
|
409 jelson 1.1 }
410
411 return 0;
412 }
413
414
415 void cleanup_module(void)
416 {
417 unregister_chrdev(EMLOG_MAJOR_NUMBER, "emlog");
418
419 /* clean up any still-allocated memory */
420 while (emlog_info_list != NULL)
421 free_einfo(emlog_info_list);
|
422 jelson 1.6
423 printk("emlog: unloading\n");
|
424 jelson 1.1 }
425
|