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-11-07 15:12:56 +03:00
# include <linux/seq_file.h>
2001-09-20 01:28:25 +04:00
2001-10-11 01:49:21 +04:00
# include "dm.h"
2001-11-07 15:12:56 +03:00
# include "dmfs.h"
2001-10-11 01:49:21 +04:00
2001-10-12 00:29:00 +04:00
struct dmfs_error {
struct list_head list ;
unsigned len ;
char * msg ;
} ;
2001-11-10 20:11:36 +03:00
static struct dmfs_error oom_error ;
static struct list_head oom_list = {
next : & oom_error . list ,
prev : & oom_error . list ,
} ;
static struct dmfs_error oom_error = {
list : { next : & oom_list , prev : & oom_list } ,
len : 39 ,
msg : " Out of memory during creation of table \n " ,
} ;
2001-10-24 12:26:10 +04:00
void dmfs_add_error ( struct inode * inode , unsigned num , char * str )
2001-10-11 01:49:21 +04:00
{
2001-10-24 12:26:10 +04:00
struct dmfs_i * dmi = DMFS_I ( inode ) ;
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 ) ;
2001-10-24 12:26:10 +04:00
list_add ( & e - > list , & dmi - > errors ) ;
2001-10-12 00:29:00 +04:00
}
}
2001-10-24 12:26:10 +04:00
void dmfs_zap_errors ( struct inode * inode )
2001-10-12 00:29:00 +04:00
{
2001-10-24 12:26:10 +04:00
struct dmfs_i * dmi = DMFS_I ( inode ) ;
2001-10-12 00:29:00 +04:00
struct dmfs_error * e ;
2001-10-11 01:49:21 +04:00
2001-10-24 12:26:10 +04:00
while ( ! list_empty ( & dmi - > errors ) ) {
e = list_entry ( dmi - > errors . next , struct dmfs_error , list ) ;
2001-10-16 21:09:27 +04:00
list_del ( & e - > list ) ;
2001-10-12 00:29:00 +04:00
kfree ( e ) ;
}
2001-10-11 01:49:21 +04:00
}
2001-11-07 15:12:56 +03:00
static void * e_start ( void * context , loff_t * pos )
2001-10-12 00:29:00 +04:00
{
2001-11-07 15:12:56 +03:00
struct list_head * p ;
loff_t n = * pos ;
struct dmfs_i * dmi = context ;
2001-10-12 00:29:00 +04:00
2001-11-07 15:12:56 +03:00
down ( & dmi - > sem ) ;
2001-11-10 20:11:36 +03:00
if ( dmi - > status ) {
list_for_each ( p , & oom_list )
if ( n - - = = 0 )
return list_entry ( p , struct dmfs_error , list ) ;
} else {
list_for_each ( p , & dmi - > errors )
if ( n - - = = 0 )
return list_entry ( p , struct dmfs_error , list ) ;
}
2001-10-12 00:29:00 +04:00
return NULL ;
}
2001-11-07 15:12:56 +03:00
static void * e_next ( void * context , void * v , loff_t * pos )
2001-10-12 00:29:00 +04:00
{
2001-11-07 15:12:56 +03:00
struct dmfs_i * dmi = context ;
struct list_head * p = ( ( struct dmfs_error * ) v ) - > list . next ;
( * pos ) + + ;
2001-11-10 20:11:36 +03:00
return ( p = = & dmi - > errors ) | | ( p = = & oom_list ) ? NULL
2001-11-07 15:12:56 +03:00
: list_entry ( p , struct dmfs_error , list ) ;
}
2001-10-12 00:29:00 +04:00
2001-11-07 15:12:56 +03:00
static void e_stop ( void * context , void * v )
{
struct dmfs_i * dmi = context ;
up ( & dmi - > sem ) ;
2001-10-12 00:29:00 +04:00
}
2001-10-11 01:49:21 +04:00
2001-11-07 15:12:56 +03:00
static int show_error ( struct seq_file * e , void * v )
2001-09-20 01:28:25 +04:00
{
2001-11-07 15:12:56 +03:00
struct dmfs_error * d = v ;
seq_puts ( e , d - > msg ) ;
return 0 ;
}
2001-09-21 02:58:06 +04:00
2001-11-07 15:12:56 +03:00
static struct seq_operations error_op = {
start : e_start ,
next : e_next ,
stop : e_stop ,
show : show_error ,
} ;
2001-10-05 14:00:13 +04:00
2001-11-07 15:12:56 +03:00
static int dmfs_error_open ( struct inode * inode , struct file * file )
{
return seq_open ( file , & error_op , DMFS_I ( file - > f_dentry - > d_parent - > d_inode ) ) ;
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-11-07 15:12:56 +03:00
open : dmfs_error_open ,
read : seq_read ,
llseek : seq_lseek ,
release : seq_release ,
2001-09-26 12:06:46 +04:00
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
{
2001-11-07 15:12:56 +03:00
struct inode * inode = dmfs_new_inode ( dir - > i_sb , mode | S_IFREG ) ;
2001-09-20 01:28:25 +04:00
if ( inode ) {
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 ;
}