(file) Return to emlog.c CVS log (file) Jump to this file's LXR Page (dir) Up to [CENS] / misc / emlog

Diff for /misc/emlog/emlog.c between version 1.4 and 1.5

version 1.4, 2001/08/13 06:01:31 version 1.5, 2001/08/13 08:10:18
Line 70 
Line 70 
   if (minor < 1 || minor > EMLOG_MAX_SIZE)   if (minor < 1 || minor > EMLOG_MAX_SIZE)
     return -EINVAL;     return -EINVAL;
  
   /* allocate space for our metadata */    /* allocate space for our metadata and initialize it */
   if ((einfo = kmalloc(sizeof(struct emlog_info), GFP_KERNEL)) == NULL)   if ((einfo = kmalloc(sizeof(struct emlog_info), GFP_KERNEL)) == NULL)
     goto struct_malloc_failed;     goto struct_malloc_failed;
  
   /* figure out how much of a buffer this should be and allocate the buffer */    memset(einfo, 0, sizeof(struct emlog_info));
   einfo->size = 1024 * minor;  
   if ((einfo->data = (char *) vmalloc(sizeof(char) * einfo->size)) == NULL)  
     goto data_malloc_failed;  
   
   /* init the rest of the structure */  
   einfo->i_ino = inode->i_ino;   einfo->i_ino = inode->i_ino;
   einfo->refcount = 0;  
   einfo->read_point = 0;  
   einfo->write_point = 0;  
  
 #if defined(DECLARE_WAIT_QUEUE_HEAD) #if defined(DECLARE_WAIT_QUEUE_HEAD)
   init_waitqueue_head(&einfo->read_q);   init_waitqueue_head(&einfo->read_q);
Line 91 
Line 83 
   init_waitqueue(&einfo->read_q);   init_waitqueue(&einfo->read_q);
 #endif #endif
  
     /* figure out how much of a buffer this should be and allocate the buffer */
     einfo->size = 1024 * minor;
     if ((einfo->data = (char *) vmalloc(sizeof(char) * einfo->size)) == NULL)
       goto data_malloc_failed;
   
   /* add it to our linked list */   /* add it to our linked list */
   einfo->next = emlog_info_list;   einfo->next = emlog_info_list;
   emlog_info_list = einfo;   emlog_info_list = einfo;
Line 169 
Line 166 
     return -EIO;     return -EIO;
   }   }
  
   EMLOG_REFCOUNT(einfo)++;    einfo->refcount++;
   MOD_INC_USE_COUNT;   MOD_INC_USE_COUNT;
   return 0;   return 0;
 } }
Line 201 
Line 198 
  
 /* read_from_emlog reads bytes out of a circular buffer with /* read_from_emlog reads bytes out of a circular buffer with
  * wraparound.  returns caddr_t, pointer to data read, which the  * wraparound.  returns caddr_t, pointer to data read, which the
  * caller must free.  length is the number of bytes to be read, which   * caller must free.  length is (a pointer to) the number of bytes to
  * we assume is <= the number of bytes available. */   * be read, which will be set by this function to be the number of
 caddr_t read_from_emlog(struct emlog_info *einfo, int length)   * bytes actually returned */
   caddr_t read_from_emlog(struct emlog_info *einfo, int *length, loff_t *offset)
 { {
   caddr_t retval;   caddr_t retval;
   int bytes_copied = 0, n;    int bytes_copied = 0, n, start_point, remaining;
  
   if (length > EMLOG_SIZE(einfo)) {    /* is the user trying to read data that has already scrolled off? */
     printk("emlog: trying to read more (%d) than we have (%d)\n",    if (*offset < einfo->offset)
            length, EMLOG_SIZE(einfo));      *offset = einfo->offset;
   
     /* is the user trying to read past EOF? */
     if (*offset >= einfo->offset + EMLOG_QLEN(einfo))
     return NULL;     return NULL;
   }  
  
   if ((retval = kmalloc(sizeof(char) * length, GFP_KERNEL)) == NULL)    /* find the smaller of the total bytes we have available and what
      * the user is asking for */
     *length = MIN(*length, EMLOG_QLEN(einfo) - (*offset - einfo->offset));
     remaining = *length;
   
     /* figure out where to start based on user's offset */
     start_point = einfo->read_point + (*offset - einfo->offset);
     start_point = start_point % einfo->size;
   
     /* allocate memory to return */
     if ((retval = kmalloc(sizeof(char) * remaining, GFP_KERNEL)) == NULL)
     return NULL;     return NULL;
  
   while (length) {    /* copy the (possibly noncontiguous) data to our buffer */
     n = MIN(length, einfo->size - einfo->read_point /* contiguous bytes */);    while (remaining) {
     memcpy(retval + bytes_copied, einfo->data + einfo->read_point, n);      n = MIN(remaining, einfo->size - start_point);
       memcpy(retval + bytes_copied, einfo->data + start_point, n);
     bytes_copied += n;     bytes_copied += n;
     length -= n;      remaining -= n;
     einfo->read_point = (einfo->read_point + n) % einfo->size;      start_point = (start_point + n) % einfo->size;
   }   }
  
     /* advance user's file pointer */
     *offset += *length;
   return retval;   return retval;
 } }
  
Line 233 
Line 246 
     size_t length,   /* The length of the buffer */     size_t length,   /* The length of the buffer */
     loff_t *offset)  /* Our offset in the file */     loff_t *offset)  /* Our offset in the file */
 { {
   int n, retval;    int retval;
   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 */
   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 (EMLOG_EMPTY(einfo)) {
     if (file->f_flags & O_NONBLOCK)     if (file->f_flags & O_NONBLOCK)
Line 253 
Line 270 
     if (signal_pending(current))     if (signal_pending(current))
       return -ERESTARTSYS;       return -ERESTARTSYS;
   }   }
   #endif
  
   /* read the data out of the internal buffer.  the following two    if ((data_to_return = read_from_emlog(einfo, &length, offset)) == NULL)
    * statements must be must be atomic with respect to      return 0;
    * emlog_info... okay since syscalls are not interrupted */  
   n = MIN(length, EMLOG_SIZE(einfo));  
   if ((data_to_return = read_from_emlog(einfo, n)) == NULL)  
     return -EIO;  
  
   /* another thread might run here if we block accessing userspace (in    if (copy_to_user(buffer, data_to_return, length) > 0)
    * copy_to_user).  this is why i remove the message from the read  
    * queue before copying it back to the user -- to preserve the  
    * atomicity of read_from_emlog.  otherwise, a block here might  
    * cause the same data to be returned to two different threads  
    * trying to read from the same device.  
    *  
    * note that this function is reentrant by virtue of the fact that  
    * each thread has its own stack, and we keep the message  
    * temporarily buffered in local variables (i.e. on the stack) */  
   if (copy_to_user(buffer, data_to_return, n) > 0)  
     retval = -EFAULT;     retval = -EFAULT;
   else   else
     retval = n;      retval = length;
   kfree(data_to_return);   kfree(data_to_return);
   return retval;   return retval;
 } }
Line 286 
Line 290 
 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;   caddr_t retval;
   int bytes_copied = 0, n;    int bytes_copied = 0;
   int overflow;    int overflow = 0;
     int n;
   
     if (length + EMLOG_QLEN(einfo) >= (einfo->size-1)) {
       overflow = 1;
  
   overflow = length + EMLOG_SIZE(einfo) > einfo->size;      /* in case of overflow, figure out where the new buffer will
        * begin.  we start by figuring out where the current buffer ENDS:
        * einfo->offset + EMLOG_QLEN.  we then advance the end-offset
        * by the length of the current write, and work backwards to
        * figure out what the oldest unoverwritten data will be (i.e.,
        * size of the buffer).  was that all quite clear? :-) */
       einfo->offset = einfo->offset + EMLOG_QLEN(einfo) + length
         - einfo->size + 1;
     }
  
   while (length) {   while (length) {
     n = MIN(length, einfo->size - einfo->write_point /* contiguous bytes */);      /* how many contiguous bytes are available from the write point to
        * the end of the circular buffer? */
       n = MIN(length, einfo->size - einfo->write_point);
     memcpy(einfo->data + einfo->write_point, buf + bytes_copied, n);     memcpy(einfo->data + einfo->write_point, buf + bytes_copied, n);
     bytes_copied += n;     bytes_copied += n;
     length -= n;     length -= n;
Line 316 
Line 334 
   int n;   int n;
   struct emlog_info *einfo;   struct emlog_info *einfo;
  
     /* 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)
     return -EIO;     return -EIO;
  
Line 328 
Line 347 
   if ((message = kmalloc(n, GFP_KERNEL)) == NULL)   if ((message = kmalloc(n, GFP_KERNEL)) == NULL)
     return -ENOMEM;     return -ENOMEM;
  
     /* copy into our temp buffer */
   if (copy_from_user(message, buffer, n) > 0) {   if (copy_from_user(message, buffer, n) > 0) {
     kfree(message);     kfree(message);
     return -EFAULT;     return -EFAULT;
   }   }
  
   /* another thread might run here if we end up blocking on the    /* now copy it into the circular buffer and free our temp copy */
    * user-space access, so it's important for reentrancy that the  
    * "message" variable is local.  see note about atomicity and  
    * reentrancy in emlog_read. */  
   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
      * schedule in the vague hope that a reader will run before the
      * writer's next write, to avoid losing data. */
   wake_up_interruptible(EMLOG_READQ(einfo));   wake_up_interruptible(EMLOG_READQ(einfo));
   schedule(); /* hope that a reader wakes up! */    schedule();
   
   return n;   return n;
 } }
  
Line 349 
Line 375 
 { {
   struct emlog_info *einfo;   struct emlog_info *einfo;
  
     /* 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)
     return -EIO;     return -EIO;
  


Legend:
Removed from v.1.4  
changed lines
  Added in v.1.5

CENS CVS Mailing List
Powered by
ViewCVS 0.9.2