|
version 1.5, 2001/08/13 08:10:18
|
version 1.6, 2001/08/13 21:12:48
|
|
|
|
| /* | /* |
| * EMLOG: the EMbedded-device LOGger | * EMLOG: the EMbedded-device LOGger |
| * | * |
| * Jeremy Elson |
* Jeremy Elson <jelson@circlemud.org> |
| * USC/ISI |
* USC/Information Sciences Institute |
| |
* |
| |
* This code is released under the GPL |
| |
* |
| |
* This is emlog version 0.40, released 13 August 2001 |
| |
* For more information see http://www.circlemud.org/~jelson/software/emlog |
| * | * |
| * $Id$ | * $Id$ |
| */ | */ |
|
|
|
| einfo->i_ino = inode->i_ino; | einfo->i_ino = inode->i_ino; |
| | |
| #if defined(DECLARE_WAIT_QUEUE_HEAD) | #if defined(DECLARE_WAIT_QUEUE_HEAD) |
| init_waitqueue_head(&einfo->read_q); |
init_waitqueue_head(EMLOG_READQ(einfo)); |
| #else | #else |
| init_waitqueue(&einfo->read_q); |
init_waitqueue(EMLOG_READQ(einfo)); |
| #endif | #endif |
| | |
| /* figure out how much of a buffer this should be and allocate the buffer */ | /* figure out how much of a buffer this should be and allocate the buffer */ |
|
|
|
| emlog_info_list = einfo; | emlog_info_list = einfo; |
| | |
| if (emlog_debug) | if (emlog_debug) |
| printk("allocating resources associated with inode %d\n", einfo->i_ino); |
printk("allocating resources associated with inode %ld\n", einfo->i_ino); |
| | |
| /* pass the struct back */ | /* pass the struct back */ |
| *peinfo = einfo; | *peinfo = einfo; |
| return 0; | return 0; |
| | |
| |
#if 0 |
| other_failure: /* if we check for other errors later, jump here */ | other_failure: /* if we check for other errors later, jump here */ |
| |
#endif |
| vfree(einfo->data); | vfree(einfo->data); |
| data_malloc_failed: | data_malloc_failed: |
| kfree(einfo); | kfree(einfo); |
|
|
|
| } | } |
| | |
| if (emlog_debug) | if (emlog_debug) |
| printk("freeing resources associated with inode %d\n", einfo->i_ino); |
printk("freeing resources associated with inode %ld\n", einfo->i_ino); |
| | |
| vfree(einfo->data); | vfree(einfo->data); |
| | |
|
|
|
| static int emlog_release(struct inode *inode, struct file *file) | static int emlog_release(struct inode *inode, struct file *file) |
| { | { |
| struct emlog_info *einfo; | struct emlog_info *einfo; |
| |
int retval = 0; |
| MOD_DEC_USE_COUNT; |
|
| | |
| /* get the buffer info */ | /* get the buffer info */ |
| if ((einfo = get_einfo(inode)) == NULL) { | if ((einfo = get_einfo(inode)) == NULL) { |
| printk("emlog: releasing unknown file! zoinks!\n"); | printk("emlog: releasing unknown file! zoinks!\n"); |
| return -EINVAL; | return -EINVAL; |
| |
goto out; |
| } | } |
| | |
| /* decrement the reference count. if no one has this file open and | /* decrement the reference count. if no one has this file open and |
| * it's not holding any data, delete the record. */ | * it's not holding any data, delete the record. */ |
| einfo->refcount--; | einfo->refcount--; |
| | |
| if (einfo->refcount == 0 && EMLOG_EMPTY(einfo)) |
if (einfo->refcount == 0 && EMLOG_QLEN(einfo) == 0) |
| free_einfo(einfo); | free_einfo(einfo); |
| | |
| return 0; |
out: |
| |
MOD_DEC_USE_COUNT; |
| |
return retval; |
| } | } |
| | |
| | |
|
|
|
| *offset = einfo->offset; | *offset = einfo->offset; |
| | |
| /* is the user trying to read past EOF? */ | /* is the user trying to read past EOF? */ |
| if (*offset >= einfo->offset + EMLOG_QLEN(einfo)) |
if (*offset >= EMLOG_FIRST_EMPTY_BYTE(einfo)) |
| return NULL; | return NULL; |
| | |
| /* find the smaller of the total bytes we have available and what | /* find the smaller of the total bytes we have available and what |
| * the user is asking for */ | * the user is asking for */ |
| *length = MIN(*length, EMLOG_QLEN(einfo) - (*offset - einfo->offset)); |
*length = MIN(*length, EMLOG_FIRST_EMPTY_BYTE(einfo) - *offset); |
| remaining = *length; | remaining = *length; |
| | |
| /* figure out where to start based on user's offset */ | /* figure out where to start based on user's offset */ |
|
|
|
| caddr_t data_to_return; | caddr_t data_to_return; |
| struct emlog_info *einfo; | struct emlog_info *einfo; |
| | |
| printk("got a read at offset %d\n", *offset); |
|
| |
|
| /* get the metadata about this emlog */ | /* get the metadata about this emlog */ |
| if ((einfo = get_einfo(file->f_dentry->d_inode)) == NULL) { | if ((einfo = get_einfo(file->f_dentry->d_inode)) == NULL) { |
| printk("emlog_read: record not found\n"); | printk("emlog_read: record not found\n"); |
| return -EIO; | return -EIO; |
| } | } |
| | |
| #if 0 |
|
| /* wait until there's data available (unless we do nonblocking reads) */ | /* wait until there's data available (unless we do nonblocking reads) */ |
| while (EMLOG_EMPTY(einfo)) { |
while (*offset >= EMLOG_FIRST_EMPTY_BYTE(einfo)) { |
| if (file->f_flags & O_NONBLOCK) | if (file->f_flags & O_NONBLOCK) |
| return -EAGAIN; | return -EAGAIN; |
| | |
|
|
|
| if (signal_pending(current)) | if (signal_pending(current)) |
| return -ERESTARTSYS; | return -ERESTARTSYS; |
| } | } |
| #endif |
|
| | |
| if ((data_to_return = read_from_emlog(einfo, &length, offset)) == NULL) | if ((data_to_return = read_from_emlog(einfo, &length, offset)) == NULL) |
| return 0; | return 0; |
|
|
|
| * case of an overflow, it overwrites the oldest unread data. */ | * case of an overflow, it overwrites the oldest unread data. */ |
| void write_to_emlog(struct emlog_info *einfo, caddr_t buf, int length) | void write_to_emlog(struct emlog_info *einfo, caddr_t buf, int length) |
| { | { |
| caddr_t retval; |
|
| int bytes_copied = 0; | int bytes_copied = 0; |
| int overflow = 0; | int overflow = 0; |
| int n; | int n; |
|
|
|
| write_to_emlog(einfo, message, n); | write_to_emlog(einfo, message, n); |
| kfree(message); | kfree(message); |
| | |
| /* update the size in the inode, so tail -f works */ |
|
| file->f_dentry->d_inode->i_size = EMLOG_QLEN(einfo) + einfo->offset - 1; |
|
| printk("size now %d\n", file->f_dentry->d_inode->i_size ); |
|
| |
|
| /* wake up any readers that might be waiting for the data. we call | /* wake up any readers that might be waiting for the data. we call |
| * schedule in the vague hope that a reader will run before the | * schedule in the vague hope that a reader will run before the |
| * writer's next write, to avoid losing data. */ | * writer's next write, to avoid losing data. */ |
| wake_up_interruptible(EMLOG_READQ(einfo)); | wake_up_interruptible(EMLOG_READQ(einfo)); |
| schedule(); |
|
| | |
| return n; | return n; |
| } | } |
|
|
|
| | |
| poll_wait(file, EMLOG_READQ(einfo), wait); | poll_wait(file, EMLOG_READQ(einfo), wait); |
| | |
| if (!EMLOG_EMPTY(einfo)) |
if (file->f_pos < EMLOG_FIRST_EMPTY_BYTE(einfo)) |
| return POLLIN | POLLRDNORM; | return POLLIN | POLLRDNORM; |
| else | else |
| return 0; | return 0; |
|
|
|
| printk("emlog: unable to register character device %d\n", | printk("emlog: unable to register character device %d\n", |
| EMLOG_MAJOR_NUMBER); | EMLOG_MAJOR_NUMBER); |
| return -EIO; | return -EIO; |
| |
} else { |
| |
printk("emlog: version %s running, using major number %d\n", EMLOG_VERSION, |
| |
EMLOG_MAJOR_NUMBER); |
| } | } |
| | |
| return 0; | return 0; |
|
|
|
| /* clean up any still-allocated memory */ | /* clean up any still-allocated memory */ |
| while (emlog_info_list != NULL) | while (emlog_info_list != NULL) |
| free_einfo(emlog_info_list); | free_einfo(emlog_info_list); |
| } |
|
| |
|
| | |
| |
printk("emlog: unloading\n"); |
| |
} |
| | |