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.8 * $Id: emlog.c,v 1.7 2001/08/13 21:29:20 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 jelson 1.8 struct emlog_info *einfo = NULL;
163 int retval = 0;
|
164 jelson 1.1
|
165 jelson 1.8 MOD_INC_USE_COUNT;
|
166 jelson 1.1
167 if ((einfo = get_einfo(inode)) == NULL) {
168 /* never heard of this inode before... create a new record */
169 if ((retval = create_einfo(inode, minor, &einfo)) < 0)
|
170 jelson 1.8 goto out;
|
171 jelson 1.1 }
172
173 if (einfo == NULL) {
174 printk("BUG IN EMLOG!\n");
|
175 jelson 1.8 retval = -EIO;
176 goto out;
|
177 jelson 1.1 }
178
|
179 jelson 1.8 /* success! */
|
180 jelson 1.5 einfo->refcount++;
|
181 jelson 1.8
182 out:
183 if (retval < 0)
184 MOD_DEC_USE_COUNT;
185 return retval;
|
186 jelson 1.1 }
187
188
189 /* this is called when a file is closed */
190 static int emlog_release(struct inode *inode, struct file *file)
191 {
192 struct emlog_info *einfo;
|
193 jelson 1.6 int retval = 0;
|
194 jelson 1.1
195 /* get the buffer info */
196 if ((einfo = get_einfo(inode)) == NULL) {
197 printk("emlog: releasing unknown file! zoinks!\n");
198 return -EINVAL;
|
199 jelson 1.6 goto out;
|
200 jelson 1.1 }
201
202 /* decrement the reference count. if no one has this file open and
203 * it's not holding any data, delete the record. */
204 einfo->refcount--;
205
|
206 jelson 1.6 if (einfo->refcount == 0 && EMLOG_QLEN(einfo) == 0)
|
207 jelson 1.1 free_einfo(einfo);
208
|
209 jelson 1.6 out:
210 MOD_DEC_USE_COUNT;
211 return retval;
|
212 jelson 1.1 }
213
214
215 /* read_from_emlog reads bytes out of a circular buffer with
216 * wraparound. returns caddr_t, pointer to data read, which the
|
217 jelson 1.5 * caller must free. length is (a pointer to) the number of bytes to
218 * be read, which will be set by this function to be the number of
219 * bytes actually returned */
220 caddr_t read_from_emlog(struct emlog_info *einfo, int *length, loff_t *offset)
|
221 jelson 1.1 {
222 caddr_t retval;
|
223 jelson 1.5 int bytes_copied = 0, n, start_point, remaining;
224
225 /* is the user trying to read data that has already scrolled off? */
226 if (*offset < einfo->offset)
227 *offset = einfo->offset;
228
229 /* is the user trying to read past EOF? */
|
230 jelson 1.6 if (*offset >= EMLOG_FIRST_EMPTY_BYTE(einfo))
|
231 jelson 1.1 return NULL;
232
|
233 jelson 1.5 /* find the smaller of the total bytes we have available and what
234 * the user is asking for */
|
235 jelson 1.6 *length = MIN(*length, EMLOG_FIRST_EMPTY_BYTE(einfo) - *offset);
|
236 jelson 1.5 remaining = *length;
237
238 /* figure out where to start based on user's offset */
239 start_point = einfo->read_point + (*offset - einfo->offset);
240 start_point = start_point % einfo->size;
241
242 /* allocate memory to return */
243 if ((retval = kmalloc(sizeof(char) * remaining, GFP_KERNEL)) == NULL)
|
244 jelson 1.1 return NULL;
245
|
246 jelson 1.5 /* copy the (possibly noncontiguous) data to our buffer */
247 while (remaining) {
248 n = MIN(remaining, einfo->size - start_point);
249 memcpy(retval + bytes_copied, einfo->data + start_point, n);
|
250 jelson 1.1 bytes_copied += n;
|
251 jelson 1.5 remaining -= n;
252 start_point = (start_point + n) % einfo->size;
|
253 jelson 1.1 }
254
|
255 jelson 1.5 /* advance user's file pointer */
256 *offset += *length;
|
257 jelson 1.1 return retval;
258 }
259
260 static ssize_t emlog_read(struct file *file,
261 char *buffer, /* The buffer to fill with data */
262 size_t length, /* The length of the buffer */
263 loff_t *offset) /* Our offset in the file */
264 {
|
265 jelson 1.5 int retval;
|
266 jelson 1.1 caddr_t data_to_return;
267 struct emlog_info *einfo;
268
|
269 jelson 1.5 /* get the metadata about this emlog */
|
270 jelson 1.1 if ((einfo = get_einfo(file->f_dentry->d_inode)) == NULL) {
271 printk("emlog_read: record not found\n");
272 return -EIO;
273 }
274
275 /* wait until there's data available (unless we do nonblocking reads) */
|
276 jelson 1.6 while (*offset >= EMLOG_FIRST_EMPTY_BYTE(einfo)) {
|
277 jelson 1.1 if (file->f_flags & O_NONBLOCK)
278 return -EAGAIN;
279
|
280 jelson 1.2 interruptible_sleep_on(EMLOG_READQ(einfo));
|
281 jelson 1.1
282 /* see if a signal woke us up */
283 if (signal_pending(current))
284 return -ERESTARTSYS;
285 }
286
|
287 jelson 1.5 if ((data_to_return = read_from_emlog(einfo, &length, offset)) == NULL)
288 return 0;
|
289 jelson 1.1
|
290 jelson 1.5 if (copy_to_user(buffer, data_to_return, length) > 0)
|
291 jelson 1.1 retval = -EFAULT;
292 else
|
293 jelson 1.5 retval = length;
|
294 jelson 1.1 kfree(data_to_return);
295 return retval;
296 }
297
298
299
300 /* write_to_emlog writes to a circular buffer with wraparound. in the
301 * case of an overflow, it overwrites the oldest unread data. */
302 void write_to_emlog(struct emlog_info *einfo, caddr_t buf, int length)
303 {
|
304 jelson 1.5 int bytes_copied = 0;
305 int overflow = 0;
306 int n;
307
308 if (length + EMLOG_QLEN(einfo) >= (einfo->size-1)) {
309 overflow = 1;
|
310 jelson 1.1
|
311 jelson 1.5 /* in case of overflow, figure out where the new buffer will
312 * begin. we start by figuring out where the current buffer ENDS:
313 * einfo->offset + EMLOG_QLEN. we then advance the end-offset
314 * by the length of the current write, and work backwards to
315 * figure out what the oldest unoverwritten data will be (i.e.,
316 * size of the buffer). was that all quite clear? :-) */
317 einfo->offset = einfo->offset + EMLOG_QLEN(einfo) + length
318 - einfo->size + 1;
319 }
|
320 jelson 1.1
321 while (length) {
|
322 jelson 1.5 /* how many contiguous bytes are available from the write point to
323 * the end of the circular buffer? */
324 n = MIN(length, einfo->size - einfo->write_point);
|
325 jelson 1.1 memcpy(einfo->data + einfo->write_point, buf + bytes_copied, n);
326 bytes_copied += n;
327 length -= n;
328 einfo->write_point = (einfo->write_point + n) % einfo->size;
329 }
330
331 /* if there is an overflow, reset the read point to read whatever is
332 * the oldest data that we have, that has not yet been
333 * overwritten. */
334 if (overflow)
335 einfo->read_point = (einfo->write_point + 1) % einfo->size;
336 }
337
338
339 static ssize_t emlog_write(struct file *file,
340 const char *buffer,
341 size_t length,
342 loff_t *offset)
343 {
344 caddr_t message = NULL;
345 int n;
346 jelson 1.1 struct emlog_info *einfo;
347
|
348 jelson 1.5 /* get the metadata about this emlog */
|
349 jelson 1.1 if ((einfo = get_einfo(file->f_dentry->d_inode)) == NULL)
350 return -EIO;
351
352 /* if the message is longer than the buffer, just take the beginning
353 * of it, in hopes that the reader (if any) will have time to read
354 * before we wrap around and obliterate it */
355 n = MIN(length, einfo->size - 1);
356
357 /* make sure we have the memory for it */
358 if ((message = kmalloc(n, GFP_KERNEL)) == NULL)
359 return -ENOMEM;
360
|
361 jelson 1.5 /* copy into our temp buffer */
|
362 jelson 1.1 if (copy_from_user(message, buffer, n) > 0) {
363 kfree(message);
364 return -EFAULT;
365 }
366
|
367 jelson 1.5 /* now copy it into the circular buffer and free our temp copy */
|
368 jelson 1.1 write_to_emlog(einfo, message, n);
369 kfree(message);
|
370 jelson 1.5
371 /* wake up any readers that might be waiting for the data. we call
372 * schedule in the vague hope that a reader will run before the
373 * writer's next write, to avoid losing data. */
|
374 jelson 1.2 wake_up_interruptible(EMLOG_READQ(einfo));
|
375 jelson 1.5
|
376 jelson 1.1 return n;
377 }
378
|
379 jelson 1.2
380 static unsigned int emlog_poll(struct file *file, poll_table *wait)
381 {
382 struct emlog_info *einfo;
383
|
384 jelson 1.5 /* get the metadata about this emlog */
|
385 jelson 1.2 if ((einfo = get_einfo(file->f_dentry->d_inode)) == NULL)
386 return -EIO;
387
388 poll_wait(file, EMLOG_READQ(einfo), wait);
389
|
390 jelson 1.6 if (file->f_pos < EMLOG_FIRST_EMPTY_BYTE(einfo))
|
391 jelson 1.2 return POLLIN | POLLRDNORM;
392 else
393 return 0;
394 }
395
396
|
397 jelson 1.1 static struct file_operations emlog_fops = {
|
398 jelson 1.2 read : emlog_read,
399 write : emlog_write,
400 open : emlog_open,
401 release: emlog_release,
402 poll : emlog_poll,
|
403 jelson 1.1 };
404
405
406 int init_module(void)
407 {
408 if (register_chrdev(EMLOG_MAJOR_NUMBER, "emlog", &emlog_fops) < 0) {
409 printk("emlog: unable to register character device %d\n",
410 EMLOG_MAJOR_NUMBER);
411 return -EIO;
|
412 jelson 1.6 } else {
413 printk("emlog: version %s running, using major number %d\n", EMLOG_VERSION,
414 EMLOG_MAJOR_NUMBER);
|
415 jelson 1.1 }
416
417 return 0;
418 }
419
420
421 void cleanup_module(void)
422 {
423 unregister_chrdev(EMLOG_MAJOR_NUMBER, "emlog");
424
425 /* clean up any still-allocated memory */
426 while (emlog_info_list != NULL)
427 free_einfo(emlog_info_list);
|
428 jelson 1.6
429 printk("emlog: unloading\n");
|
430 jelson 1.1 }
431
|