2001-09-20 01:28:25 +04:00
/*
2001-09-26 12:06:46 +04:00
* dmfs - error . c
2001-09-20 01:28:25 +04:00
*
* Copyright ( C ) 2001 Sistina Software
*
* This software is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation ; either version 2 , or ( at
* your option ) any later version .
*
* This software is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with GNU CC ; see the file COPYING . If not , write to
* the Free Software Foundation , 59 Temple Place - Suite 330 ,
* Boston , MA 02111 - 1307 , USA .
*/
# include <linux/config.h>
2001-10-12 00:29:00 +04:00
# include <linux/list.h>
2001-09-20 01:28:25 +04:00
# include <linux/fs.h>
2001-10-11 01:49:21 +04:00
# include "dm.h"
2001-10-12 00:29:00 +04:00
struct dmfs_error {
struct list_head list ;
unsigned len ;
char * msg ;
} ;
2001-10-11 01:49:21 +04:00
void dmfs_add_error ( struct dm_table * t , unsigned num , char * str )
{
2001-10-12 14:06:40 +04:00
int len = strlen ( str ) + sizeof ( struct dmfs_error ) + 12 ;
2001-10-12 00:29:00 +04:00
struct dmfs_error * e = kmalloc ( len , GFP_KERNEL ) ;
if ( e ) {
e - > msg = ( char * ) ( e + 1 ) ;
e - > len = sprintf ( e - > msg , " %8u: %s \n " , num , str ) ;
list_add ( & e - > list , & t - > errors ) ;
}
}
void dmfs_zap_errors ( struct dm_table * t )
{
struct dmfs_error * e ;
2001-10-11 01:49:21 +04:00
2001-10-12 00:29:00 +04:00
while ( ! list_empty ( & t - > errors ) ) {
e = list_entry ( t - > errors . next , struct dmfs_error , list ) ;
kfree ( e ) ;
}
2001-10-11 01:49:21 +04:00
}
2001-10-12 14:06:40 +04:00
static struct dmfs_error * find_initial_message ( struct dm_table * t , loff_t * pos )
2001-10-12 00:29:00 +04:00
{
struct dmfs_error * e ;
struct list_head * tmp , * head ;
tmp = head = & t - > errors ;
for ( ; ; ) {
tmp = tmp - > next ;
if ( tmp = = head )
break ;
e = list_entry ( tmp , struct dmfs_error , list ) ;
if ( * pos < e - > len )
return e ;
( * pos ) - = e - > len ;
}
return NULL ;
}
static int copy_sequence ( struct dm_table * t , struct dmfs_error * e , char * buf ,
size_t size , loff_t offset )
{
char * from ;
int amount ;
int copied = 0 ;
do {
from = e - > msg + offset ;
amount = e - > len - offset ;
if ( copy_to_user ( buf , from , amount ) )
return - EFAULT ;
buf + = amount ;
copied + = amount ;
size - = amount ;
offset = 0 ;
if ( e - > list . next = = & t - > errors )
break ;
e = list_entry ( e - > list . next , struct dmfs_error , list ) ;
} while ( size > 0 ) ;
return amount ;
}
2001-10-11 01:49:21 +04:00
2001-09-26 12:06:46 +04:00
static ssize_t dmfs_error_read ( struct file * file , char * buf , size_t size , loff_t * pos )
2001-09-20 01:28:25 +04:00
{
2001-10-05 14:00:13 +04:00
struct dmfs_i * dmi = DMFS_I ( file - > f_dentry - > d_parent - > d_inode ) ;
struct dm_table * t = dmi - > table ;
int copied = 0 ;
2001-10-12 00:29:00 +04:00
loff_t offset = * pos ;
2001-09-21 02:58:06 +04:00
2001-10-12 14:06:40 +04:00
if ( ! access_ok ( VERIFY_WRITE , buf , size ) )
2001-10-05 14:00:13 +04:00
return - EFAULT ;
2001-10-11 01:49:21 +04:00
down ( & dmi - > sem ) ;
if ( dmi - > table ) {
2001-10-12 00:29:00 +04:00
struct dmfs_error * e = find_initial_message ( t , & offset ) ;
if ( e ) {
copied = copy_sequence ( t , e , buf , size , offset ) ;
if ( copied > 0 )
( * pos ) + = copied ;
}
2001-10-11 01:49:21 +04:00
}
up ( & dmi - > sem ) ;
2001-10-05 14:00:13 +04:00
return copied ;
2001-09-20 01:28:25 +04:00
}
2001-09-26 12:06:46 +04:00
static int dmfs_error_sync ( struct file * file , struct dentry * dentry , int datasync )
2001-09-20 01:28:25 +04:00
{
return 0 ;
}
2001-10-12 14:06:40 +04:00
static struct file_operations dmfs_error_file_operations = {
2001-09-26 12:06:46 +04:00
read : dmfs_error_read ,
fsync : dmfs_error_sync ,
2001-09-20 01:28:25 +04:00
} ;
2001-10-12 14:06:40 +04:00
static struct inode_operations dmfs_error_inode_operations = {
2001-09-20 01:28:25 +04:00
} ;
2001-10-12 14:06:40 +04:00
struct inode * dmfs_create_error ( struct inode * dir , int mode )
2001-09-20 01:28:25 +04:00
{
struct inode * inode = new_inode ( dir - > i_sb ) ;
if ( inode ) {
inode - > i_mode = mode | S_IFREG ;
inode - > i_uid = current - > fsuid ;
inode - > i_gid = current - > fsgid ;
inode - > i_blksize = PAGE_CACHE_SIZE ;
inode - > i_blocks = 0 ;
inode - > i_rdev = NODEV ;
inode - > i_atime = inode - > i_ctime = inode - > i_mtime = CURRENT_TIME ;
2001-09-26 12:06:46 +04:00
inode - > i_fop = & dmfs_error_file_operations ;
inode - > i_op = & dmfs_error_inode_operations ;
2001-09-20 01:28:25 +04:00
}
return inode ;
}