/******************************************************************************* ** **_DebugFSWrite ** *******************************************************************************/ static ssize_t _DebugFSWrite ( struct file *file , const char __user * buffer , size_t length , loff_t * offset ) { caddr_t message = NULL ; int n ; gcsDebugFileSystemNode*node ; /* get the metadata about this log */ if ( ( node = _GetNodeInfo ( file->f_dentry->d_inode ) ) == NULL ) { return - EIO ; } if ( down_interruptible ( gcmkNODE_SEM ( node ) ) ) { return - ERESTARTSYS ; } /* if the message is longer than the buffer, just take the beginning * of it, in hopes that the reader (if any) will have time to read * before we wrap around and obliterate it */ n = gcmkMIN ( length , node->size - 1 ) ; /* make sure we have the memory for it */ if ( ( message = kmalloc ( n , GFP_KERNEL ) ) == NULL ) { up ( gcmkNODE_SEM ( node ) ) ; return - ENOMEM ; } /* copy into our temp buffer */ if ( copy_from_user ( message , buffer , n ) > 0 ) { up ( gcmkNODE_SEM ( node ) ) ; kfree ( message ) ; return - EFAULT ; } /* now copy it into the circular buffer and free our temp copy */ _WriteToNode ( node , message , n ) ; kfree ( message ) ; up ( gcmkNODE_SEM ( node ) ) ; /* 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 ( gcmkNODE_READQ ( node ) ) ; return n ; }
gctINT gckDebugFileSystemCreateNode ( IN gctINT SizeInKB , IN gctCONST_STRING ParentName , IN gctCONST_STRING NodeName , OUT gcsDebugFileSystemNode **Node ) { gcsDebugFileSystemNode*node ; /* allocate space for our metadata and initialize it */ if ( ( node = kmalloc ( sizeof (gcsDebugFileSystemNode ) , GFP_KERNEL ) ) == NULL ) goto struct_malloc_failed ; /*Zero it out*/ memset ( node , 0 , sizeof (gcsDebugFileSystemNode ) ) ; /*Init the sync primitives*/ #if defined(DECLARE_WAIT_QUEUE_HEAD) init_waitqueue_head ( gcmkNODE_READQ ( node ) ) ; #else init_waitqueue ( gcmkNODE_READQ ( node ) ) ; #endif #if defined(DECLARE_WAIT_QUEUE_HEAD) init_waitqueue_head ( gcmkNODE_WRITEQ ( node ) ) ; #else init_waitqueue ( gcmkNODE_WRITEQ ( node ) ) ; #endif sema_init ( gcmkNODE_SEM ( node ) , 1 ) ; /*End the sync primitives*/ /* figure out how much of a buffer this should be and allocate the buffer */ node->size = 1024 * SizeInKB ; if ( ( node->data = ( char * ) vmalloc ( sizeof (char ) * node->size ) ) == NULL ) goto data_malloc_failed ; /*creating the debug file system*/ node->parent = debugfs_create_dir ( ParentName , NULL ) ; /*creating the file*/ node->filen = debugfs_create_file ( NodeName , S_IRUGO | S_IWUSR , node->parent , NULL , &debugfs_operations ) ; /* add it to our linked list */ node->next = gc_dbgfs.linkedlist ; gc_dbgfs.linkedlist = node ; /* pass the struct back */ *Node = node ; return 0 ; vfree ( node->data ) ; data_malloc_failed: kfree ( node ) ; struct_malloc_failed: return - ENOMEM ; }
/******************************************************************************* ** ** gckDebugFileSystemFreeNode ** ** ** INPUT: ** ** OUTPUT: ** *******************************************************************************/ void gckDebugFileSystemFreeNode ( IN gcsDebugFileSystemNode * Node ) { gcsDebugFileSystemNode **ptr ; if ( Node == NULL ) { printk ( "null passed to free_vinfo\n" ) ; return ; } down ( gcmkNODE_SEM ( Node ) ) ; /*free data*/ vfree ( Node->data ) ; /*Close Debug fs*/ if ( Node->filen ) { debugfs_remove ( Node->filen ) ; } if ( Node->parent ) { debugfs_remove ( Node->parent ) ; } /* now delete the node from the linked list */ ptr = & ( gc_dbgfs.linkedlist ) ; while ( *ptr != Node ) { if ( ! *ptr ) { printk ( "corrupt info list!\n" ) ; break ; } else ptr = & ( ( **ptr ).next ) ; } *ptr = Node->next ; up ( gcmkNODE_SEM ( Node ) ) ; }
/******************************************************************************* ** ** _DebugFSPrint ** ** *******************************************************************************/ static void _DebugFSPrint ( IN unsigned int ArgumentSize , IN const char* Message , IN gctDBGARGS Arguments ) { char buffer[MAX_LINE_SIZE] ; int len ; down ( gcmkNODE_SEM ( gc_dbgfs.currentNode ) ) ; len = vsnprintf ( buffer , sizeof (buffer ) , Message , *( va_list * ) & Arguments ) ; buffer[len] = '\0' ; if ( buffer[len - 1] != '\n' ) { buffer[len ++] = '\n' ; buffer[len] = '\0' ; } _AppendString ( gc_dbgfs.currentNode , buffer , len ) ; up ( gcmkNODE_SEM ( gc_dbgfs.currentNode ) ) ; wake_up_interruptible ( gcmkNODE_READQ ( gc_dbgfs.currentNode ) ) ; /* blocked in read*/ }
/******************************************************************************* ** ** _DebugFSRead ** *******************************************************************************/ static ssize_t _DebugFSRead ( struct file *file , char __user * buffer , size_t length , loff_t * offset ) { int retval ; caddr_t data_to_return ; gcsDebugFileSystemNode* node ; /* get the metadata about this emlog */ if ( ( node = _GetNodeInfo ( file->f_dentry->d_inode ) ) == NULL ) { printk ( "debugfs_read: record not found\n" ) ; return - EIO ; } if ( down_interruptible ( gcmkNODE_SEM ( node ) ) ) { return - ERESTARTSYS ; } /* wait until there's data available (unless we do nonblocking reads) */ while ( *offset >= gcmkNODE_FIRST_EMPTY_BYTE ( node ) ) { up ( gcmkNODE_SEM ( node ) ) ; if ( file->f_flags & O_NONBLOCK ) { return - EAGAIN ; } if ( wait_event_interruptible ( ( *( gcmkNODE_READQ ( node ) ) ) , ( *offset < gcmkNODE_FIRST_EMPTY_BYTE ( node ) ) ) ) { return - ERESTARTSYS ; /* signal: tell the fs layer to handle it */ } /* otherwise loop, but first reacquire the lock */ if ( down_interruptible ( gcmkNODE_SEM ( node ) ) ) { return - ERESTARTSYS ; } } data_to_return = _ReadFromNode ( node , &length , offset ) ; if ( data_to_return == NULL ) { retval = 0 ; goto unlock ; } if ( copy_to_user ( buffer , data_to_return , length ) > 0 ) { retval = - EFAULT ; } else { retval = length ; } kfree ( data_to_return ) ; unlock: up ( gcmkNODE_SEM ( node ) ) ; wake_up_interruptible ( gcmkNODE_WRITEQ ( node ) ) ; return retval ; }