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