diff options
author | cc4b05f61e2d8f77114750386c9f9a60 <cc4b05f61e2d8f7@7114750386c9f9a60> | 2023-05-11 14:38:47 +0000 |
---|---|---|
committer | cc4b05f61e2d8f77114750386c9f9a60 <cc4b05f61e2d8f7@7114750386c9f9a60> | 2023-05-11 14:38:47 +0000 |
commit | f5450bfd35a6410528d124f534c2b1a958cafe51 (patch) | |
tree | a808b12d6ad5343fabdec7b8918df6b4d844e03f /src/dblspace_ioctl.c | |
parent | 5ad2bb7a6ac7e97c031908d2439808a00fff6214 (diff) | |
download | dmsdosnow-dmsdos-0.9.2.2.tar.gz |
dmsdos-0.9.2.2 addeddmsdos-0.9.2.2
Diffstat (limited to 'src/dblspace_ioctl.c')
-rw-r--r-- | src/dblspace_ioctl.c | 971 |
1 files changed, 971 insertions, 0 deletions
diff --git a/src/dblspace_ioctl.c b/src/dblspace_ioctl.c new file mode 100644 index 0000000..6eecc28 --- /dev/null +++ b/src/dblspace_ioctl.c @@ -0,0 +1,971 @@ +/* +dblspace_ioctl.c + +DMSDOS CVF-FAT module: ioctl functions (interface for external utilities). + +****************************************************************************** +DMSDOS (compressed MSDOS filesystem support) for Linux +written 1995-1998 by Frank Gockel and Pavel Pisa + + (C) Copyright 1995-1998 by Frank Gockel + (C) Copyright 1996-1998 by Pavel Pisa + +Some code of dmsdos has been copied from the msdos filesystem +so there are the following additional copyrights: + + (C) Copyright 1992,1993 by Werner Almesberger (msdos filesystem) + (C) Copyright 1994,1995 by Jacques Gelinas (mmap code) + (C) Copyright 1992-1995 by Linus Torvalds + +DMSDOS was inspired by the THS filesystem (a simple doublespace +DS-0-2 compressed read-only filesystem) written 1994 by Thomas Scheuermann. + +The DMSDOS code is distributed under the Gnu General Public Licence. +See file COPYING for details. +****************************************************************************** + +*/ + +#ifndef __KERNEL__ +#error This file needs __KERNEL__ +#endif + +#include <asm/segment.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/msdos_fs.h> +#include <linux/mm.h> +#include <asm/semaphore.h> +#include "dmsdos.h" + +#ifdef INTERNAL_DAEMON +int idmsdosd(void*); +#define __KERNEL_SYSCALLS__ +#include <linux/unistd.h> +#endif + +extern unsigned long dmsdos_speedup; + +int daemon_present=0; +int must_maintain_list=0; +int listcount=0; +Rwlist rwlist[LISTSIZE]; +int rlist=0; +int wlist=0; + +#ifdef INTERNAL_DAEMON +DECLARE_WAIT_QUEUE_HEAD(daemon_wait); +DECLARE_WAIT_QUEUE_HEAD(daemon_exit_wait); +int daemon_go_home=0; +int internal_daemon_counter=0; +#else +int daemon_pid; +int daemon_task_nr; +#endif + +void dumpcache(void); +void dump_ccache(void); + +DECLARE_MUTEX(listaccess_sem); /* Must be initialized to green light */ +void lock_listaccess(void) {down(&listaccess_sem);} +void unlock_listaccess(void) {up(&listaccess_sem);} + +void log_statistics(void) +{ log_list_statistics(); + log_ccache_statistics(); + log_found_statistics(); + /*log_other_statistics();*/ +} + +#undef DEPRECATED_CODE +#ifdef DEPRECATED_CODE +int set_maxcluster(struct super_block*sb,int data) +{ struct buffer_head*bh,*bh2; + int i; + unsigned char*pp; + unsigned long int sectors; + Dblsb*dblsb=MSDOS_SB(sb)->private_data; + + if(dblsb->s_cvf_version>=DRVSP3) + { printk(KERN_ERR "DMSDOS: set_maxcluster refused - CVF is not in doublespace or drivespace<=2 format.\n"); + return -EINVAL; + } + if(data<2||data>dblsb->s_max_cluster2)return -EINVAL; + /* check if higher clusters are unused */ + for(i=dblsb->s_max_cluster2;i>data;--i) + { if(dbl_fat_nextcluster(sb,i,NULL)) + { printk(KERN_ERR "DMSDOS: set_maxcluster %d refused: cluster %d in use\n", + data,i); + return -EINVAL; + } + } + + bh=raw_bread(sb,0); + if(bh==NULL)return -EIO; + bh2=raw_bread(sb,dblsb->s_bootblock); + if(bh2==NULL) + { raw_brelse(sb,bh); + return -EIO; + } + + /* calculate number of sectors */ + /*sectors=(data-1)<<4;*/ + sectors=(data-1)*dblsb->s_sectperclust; + sectors+=dblsb->s_rootdirentries>>4; + pp=&(bh->b_data[14]); + sectors+=CHS(pp); + pp=&(bh->b_data[22]); + sectors+=CHS(pp); + bh->b_data[32]=sectors; + bh->b_data[33]=sectors>>8; + bh->b_data[34]=sectors>>16; + bh->b_data[35]=sectors>>24; + sectors+=CHS(pp); + bh2->b_data[32]=sectors; + bh2->b_data[33]=sectors>>8; + bh2->b_data[34]=sectors>>16; + bh2->b_data[35]=sectors>>24; + raw_mark_buffer_dirty(sb,bh,1); + raw_mark_buffer_dirty(sb,bh2,1); + raw_brelse(sb,bh); + raw_brelse(sb,bh2); + + dblsb->s_max_cluster=data; + MSDOS_SB(sb)->clusters=data; + MSDOS_SB(sb)->free_clusters=-1; + + return 0; +} +#endif + +void dmsdos_extra_statfs(struct super_block*sb, Dblstat*dblstat) +{ int sector,size,cluster; + Mdfat_entry mde; + Dblsb*dblsb=MSDOS_SB(sb)->private_data; + + dblstat->free_sectors=0; + dblstat->max_hole=0; + for(sector=dblsb->s_datastart;sector<dblsb->s_dataend; + ++sector) + { if(dbl_bitfat_value(sb,sector,NULL)==0) + { ++(dblstat->free_sectors); + size=1; + while(dbl_bitfat_value(sb,sector+size,NULL)==0)++size; + if(size>dblstat->max_hole)dblstat->max_hole=size; + sector+=size-1; + dblstat->free_sectors+=size-1; + } + } + dblstat->used_sectors=dblsb->s_dataend+1-dblsb->s_datastart + -dblstat->free_sectors; + dblstat->sectors_lo=0; + dblstat->sectors_hi=0; + dblstat->compressed_clusters=0; + dblstat->uncompressed_clusters=0; + dblstat->free_clusters=0; + dblstat->used_clusters=0; + dblstat->lost_clusters=0; + for(cluster=2;cluster<=dblsb->s_max_cluster;++cluster) + { if(dbl_fat_nextcluster(sb,cluster,NULL)!=0) + { dbl_mdfat_value(sb,cluster,NULL,&mde); + if(mde.flags&2) + { ++(dblstat->used_clusters); + if(mde.flags&1)++(dblstat->uncompressed_clusters); + else ++(dblstat->compressed_clusters); + dblstat->sectors_hi+=mde.size_hi_minus_1+1; + dblstat->sectors_lo+=mde.size_lo_minus_1+1; + } + else ++(dblstat->lost_clusters); + } + else ++(dblstat->free_clusters); + } +} + +int dmsdos_ioctl_dir( + struct inode *dir, + struct file *filp, + unsigned int cmd, + unsigned long data) +{ unsigned char* idata; + struct buffer_head*bh; + int newval; + int val; + int cluster; + int sector; + Dblstat dblstat; + Mdfat_entry mde,dummy; + unsigned char *clusterd; + int membytes; + struct super_block*sb=dir->i_sb; + Dblsb*dblsb=MSDOS_SB(sb)->private_data; + long lval; +#ifndef INTERNAL_DAEMON + int length; + int i; + int plist; + /*int sectors;*/ + int rawlength; +#endif + + idata=(unsigned char*)data; + + switch(cmd) + { case DMSDOS_GET_DBLSB: + /* check dutil version number */ + if(verify_area(VERIFY_READ, idata, sizeof(long)))return -EFAULT; + /*if(get_fs_long(idata)<DMSDOS_LOWEST_COMPATIBLE_VERSION)*/ + memcpy_fromfs(&lval,idata,sizeof(long)); + if(lval<DMSDOS_LOWEST_COMPATIBLE_VERSION) + return DMSDOS_VERSION|0x0f000000; + if(verify_area(VERIFY_WRITE, idata, sizeof(Dblsb)))return -EFAULT; + memcpy_tofs(idata,(unsigned char*)dblsb,sizeof(Dblsb)); + return DMSDOS_VERSION; + case DMSDOS_EXTRA_STATFS: + if(verify_area(VERIFY_WRITE, idata, sizeof(Dblstat)))return -EFAULT; + dmsdos_extra_statfs(dir->i_sb,&dblstat); + memcpy_tofs(idata,&dblstat,sizeof(Dblstat)); + return 0; + case DMSDOS_READ_BLOCK: + if(current->euid!=0)return -EPERM; + if(verify_area(VERIFY_READ, idata, sizeof(long)))return -EFAULT; + /*sector=get_fs_long(idata);*/ + memcpy_fromfs(§or,idata,sizeof(long)); + if(sector<0||sector>dblsb->s_dataend)return -EINVAL; + bh=raw_bread(dir->i_sb,sector); + if(bh==NULL)return -EIO; + if(verify_area(VERIFY_WRITE, idata+sizeof(long),SECTOR_SIZE))return -EFAULT; + memcpy_tofs(idata+sizeof(long),bh->b_data,SECTOR_SIZE); + raw_brelse(dir->i_sb,bh); + return 0; + case DMSDOS_WRITE_BLOCK: + if(current->euid!=0)return -EPERM; + if(verify_area(VERIFY_READ, idata, sizeof(long)+SECTOR_SIZE))return -EFAULT; + /*sector=get_fs_long(idata);*/ + memcpy_fromfs(§or,idata,sizeof(long)); + if(sector<0||sector>dblsb->s_dataend)return -EINVAL; + bh=raw_bread(dir->i_sb,sector); + if(bh==NULL)return -EIO; + memcpy_fromfs(bh->b_data,idata+sizeof(long),SECTOR_SIZE); + raw_mark_buffer_dirty(dir->i_sb,bh,1); + raw_brelse(dir->i_sb,bh); + return 0; + case DMSDOS_READ_DIRENTRY: + case DMSDOS_WRITE_DIRENTRY: + printk(KERN_WARNING "DMSDOS: READ/WRITE DIRENTRY ioctl has gone\n"); + return -EINVAL; + case DMSDOS_READ_BITFAT: + if(verify_area(VERIFY_READ, idata, sizeof(long)))return -EFAULT; + /*sector=get_fs_long(idata);*/ + memcpy_fromfs(§or,idata,sizeof(long)); + if(sector<0||sector>dblsb->s_dataend)return -EINVAL; + val=dbl_bitfat_value(sb,sector,NULL); + if(verify_area(VERIFY_WRITE, idata+sizeof(long),sizeof(long)))return -EFAULT; + /*put_fs_long(val,idata+sizeof(long));*/ + memcpy_tofs(idata+sizeof(long),&val,sizeof(long)); + return 0; + case DMSDOS_WRITE_BITFAT: + if(current->euid!=0)return -EPERM; + if(verify_area(VERIFY_READ, idata, 2*sizeof(long)))return -EFAULT; + /*sector=get_fs_long(idata);*/ + memcpy_fromfs(§or,idata,sizeof(long)); + if(sector<0||sector>dblsb->s_dataend)return -EINVAL; + /*newval=get_fs_long(idata+sizeof(long));*/ + memcpy_fromfs(&newval,idata+sizeof(long),sizeof(long)); + dbl_bitfat_value(sb,sector,&newval); + return 0; + case DMSDOS_READ_MDFAT: + if(verify_area(VERIFY_READ, idata, sizeof(long)))return -EFAULT; + /*cluster=get_fs_long(idata);*/ + memcpy_fromfs(&cluster,idata,sizeof(long)); + if(cluster>dblsb->s_max_cluster)return -EINVAL; + dbl_mdfat_value(sb,cluster,NULL,&mde); + if(verify_area(VERIFY_WRITE,idata+sizeof(long),sizeof(Mdfat_entry)))return -EFAULT; + memcpy_fromfs(&lval,idata+sizeof(long),sizeof(long)); + memcpy_tofs((Mdfat_entry*)lval,&mde,sizeof(Mdfat_entry)); + return 0; + case DMSDOS_WRITE_MDFAT: + if(current->euid!=0)return -EPERM; + if(verify_area(VERIFY_READ, idata, sizeof(long)+sizeof(Mdfat_entry)))return -EFAULT; + /*cluster=get_fs_long(idata);*/ + memcpy_fromfs(&cluster,idata,sizeof(long)); + if(cluster>dblsb->s_max_cluster)return -EINVAL; + memcpy_fromfs(&lval,idata+sizeof(long),sizeof(long)); + memcpy_fromfs(&mde,(Mdfat_entry*)lval, + sizeof(Mdfat_entry)); + dbl_mdfat_value(sb,cluster,&mde,&dummy); + return 0; + case DMSDOS_READ_DFAT: + if(verify_area(VERIFY_READ, idata, sizeof(long)))return -EFAULT; + /*cluster=get_fs_long(idata);*/ + memcpy_fromfs(&cluster,idata,sizeof(long)); + if(cluster>dblsb->s_max_cluster)return -EINVAL; + val=dbl_fat_nextcluster(sb,cluster,NULL); + if(verify_area(VERIFY_WRITE, idata+sizeof(long),sizeof(long)))return -EFAULT; + /*put_fs_long(val,idata+sizeof(long));*/ + memcpy_tofs(idata+sizeof(long),&val,sizeof(long)); + return 0; + case DMSDOS_WRITE_DFAT: + if(current->euid!=0)return -EPERM; + if(verify_area(VERIFY_READ, idata, 2*sizeof(long)))return -EFAULT; + /*cluster=get_fs_long(idata);*/ + memcpy_fromfs(&cluster,idata,sizeof(long)); + if(cluster>dblsb->s_max_cluster)return -EINVAL; + /*newval=get_fs_long(idata+sizeof(long));*/ + memcpy_fromfs(&newval,idata+sizeof(long),sizeof(long)); + dbl_fat_nextcluster(sb,cluster,&newval); + return 0; + case DMSDOS_READ_CLUSTER: + if(current->euid!=0)return -EPERM; + if(verify_area(VERIFY_READ, idata, sizeof(long)))return -EFAULT; + /*cluster=get_fs_long(idata);*/ + memcpy_fromfs(&cluster,idata,sizeof(long)); + if(cluster < 0 || cluster>dblsb->s_max_cluster) + return -EINVAL; + membytes=SECTOR_SIZE*dblsb->s_sectperclust; + if(verify_area(VERIFY_WRITE, idata+sizeof(long),membytes))return -EFAULT; + if((clusterd=(unsigned char*)MALLOC(membytes))==NULL) + { printk(KERN_ERR "DMSDOS: ioctl: read_cluster: no memory!\n"); + return -EIO; + } + val=dmsdos_read_cluster(dir->i_sb,clusterd,cluster); + if (val >= 0) + memcpy_tofs(idata+sizeof(long), clusterd, membytes); + FREE(clusterd); + return val; + case DMSDOS_SET_COMP: + if(current->euid!=0)return -EPERM; + if(dblsb->s_comp!=READ_ONLY&&data==READ_ONLY)sync_cluster_cache(0); + dblsb->s_comp=data; + if(data==READ_ONLY)sb->s_flags |= MS_RDONLY; + else sb->s_flags&=~MS_RDONLY; + return 0; + case DMSDOS_SET_CF: + if(current->euid!=0)return -EPERM; + if(data>=12u)return -EINVAL; + dblsb->s_cfaktor=data; + return 0; + case DMSDOS_SIMPLE_CHECK: + if(verify_area(VERIFY_READ, idata, sizeof(long)))return -EFAULT; + memcpy_fromfs(&lval,idata,sizeof(long)); + val=simple_check(dir->i_sb,lval); + if(verify_area(VERIFY_WRITE, idata, sizeof(long)))return -EFAULT; + /*put_fs_long(val,idata);*/ + memcpy_tofs(idata,&val,sizeof(long)); + return 0; + case DMSDOS_DUMPCACHE: + dumpcache(); + dump_ccache(); + return 0; + case DMSDOS_D_ASK: + #ifdef INTERNAL_DAEMON + return -EINVAL; + #else + if(current->euid!=0)return -EPERM; + /* dmsdosd says it is present and ready */ + if(current->pid!=data) + { printk(KERN_ERR "DMSDOS: daemon is lying about its pid\n"); + return -EINVAL; + } + daemon_present=1; + daemon_pid=current->pid; + LOG_DAEMON("DMSDOS: D_ASK\n"); + return 0; + #endif + case DMSDOS_D_READ: + #ifdef INTERNAL_DAEMON + return -EINVAL; + #else + if(current->euid!=0)return -EPERM; + lock_listaccess(); + /*search next valid entry*/ + for(i=LISTSIZE;i>0;--i) + { if(rwlist[rlist].flag==D_VALID) + { /* check in mdfat that cluster is actually used */ + dbl_mdfat_value(rwlist[rlist].sb,rwlist[rlist].clusternr, + NULL,&mde); + if((mde.flags&3)==3)goto vr_found; /* used and uncompressed */ + rwlist[rlist].flag=D_EMPTY; /* remove - it's garbage */ + --listcount; + LOG_DAEMON("DMSDOS: D_READ: removing garbage entry cluster=%d\n", + rwlist[rlist].clusternr); + } + /*rlist=(rlist+1)&(LISTSIZE-1);*/ + rlist++;if(rlist>=LISTSIZE)rlist=0; + } + unlock_listaccess(); + return 0; + vr_found: + cluster=rwlist[rlist].clusternr; + /* yes we change sb here */ + sb=rwlist[rlist].sb; + dblsb=MSDOS_SB(sb)->private_data; + length=rwlist[rlist].length; + clusterd=MALLOC(dblsb->s_sectperclust*SECTOR_SIZE); + if(clusterd==NULL) + { printk(KERN_ERR "DMSDOS: ioctl: D_READ: no memory!\n"); + unlock_listaccess(); + return 0; + } + if((i=dmsdos_read_cluster(sb,clusterd,cluster))<0) + { printk(KERN_ERR "DMSDOS: ioctl: D_READ: read_cluster failed!\n"); + rwlist[rlist].flag=D_EMPTY; + --listcount; + unlock_listaccess(); + FREE(clusterd); + return 0; + } + if(length<0)length=i; /* if invalid length, use the read value */ + rwlist[rlist].flag=D_IN_D_ACTION; + if(verify_area(VERIFY_WRITE, idata, 3*sizeof(long)+length)) + { unlock_listaccess(); + FREE(clusterd); + return -EFAULT; + } + /*put_fs_long(rlist,idata);*/ + memcpy_tofs(idata,&rlist,sizeof(long)); + /*put_fs_long(length,idata+sizeof(long));*/ + memcpy_tofs(idata+sizeof(long),&length,sizeof(long)); + /*put_fs_long(rwlist[rlist].method,idata+2*sizeof(long));*/ + memcpy_tofs(idata+2*sizeof(long),&(rwlist[rlist].method),sizeof(long)); + memcpy_tofs(idata+3*sizeof(long),clusterd,length); + unlock_listaccess(); + FREE(clusterd); + return 1; +#endif + case DMSDOS_D_WRITE: +#ifdef INTERNAL_DAEMON + return -EINVAL; +#else + if(current->euid!=0)return -EPERM; + if(verify_area(VERIFY_READ,idata,3*sizeof(long)))return -EFAULT; + lock_listaccess(); + /*plist=get_fs_long(idata);*/ + memcpy_fromfs(&plist,idata,sizeof(long)); + if(rwlist[plist].flag==D_OVERWRITTEN){rwlist[plist].flag=D_EMPTY;--listcount;} + if(rwlist[plist].flag!=D_IN_D_ACTION) + { LOG_DAEMON("DMSDOS: D_WRITE: Entry not in action, flag=%d cluster=%d\n", + rwlist[plist].flag,rwlist[plist].clusternr); + unlock_listaccess(); + return 0; + } + + /* will be freed in any case later, so: */ + --listcount; + + /*rawlength=get_fs_long(idata+sizeof(long));*/ + memcpy_fromfs(&rawlength,idata+sizeof(long),sizeof(long)); + if(rawlength==0) + { /* data were uncompressible */ + rwlist[plist].flag=D_EMPTY; + unlock_listaccess(); + return 0; + } + /* check that cluster is used */ + dbl_mdfat_value(rwlist[plist].sb,rwlist[plist].clusternr, + NULL,&mde); + if((mde.flags&3)!=3) + { rwlist[plist].flag=D_EMPTY; /* remove - it's garbage */ + LOG_DAEMON("DMSDOS: D_WRITE: removing garbage entry cluster=%d\n", + rwlist[plist].clusternr); + unlock_listaccess(); + return 0; + } + if(verify_area(VERIFY_READ,idata+3*sizeof(long),rawlength)) + { rwlist[plist].flag=D_EMPTY; + unlock_listaccess(); + return -EFAULT; + } + clusterd=MALLOC(rawlength); + if(clusterd==NULL) + { printk(KERN_ERR "DMSDOS: ioctl: D_WRITE: no memory!\n"); + rwlist[plist].flag=D_EMPTY; + unlock_listaccess(); + return 0; + } + length=rwlist[plist].length; + cluster=rwlist[plist].clusternr; + sb=rwlist[plist].sb; + memcpy_fromfs(clusterd,idata+3*sizeof(long),rawlength); + rwlist[plist].flag=D_EMPTY; + unlock_listaccess(); + /* this may call try_daemon via ccache code (freeing a ccache slot) */ + daemon_write_cluster(sb,clusterd,length, + cluster, + rawlength); + FREE(clusterd); + return 0; +#endif + case DMSDOS_D_EXIT: +#ifdef INTERNAL_DAEMON + return -EINVAL; +#else + if(current->euid!=0)return -EPERM; + /* dmsdosd is saying good-bye */ + daemon_present=0; + LOG_DAEMON("DMSDOS: D_EXIT\n"); + return 0; +#endif + case DMSDOS_MOVEBACK: + printk(KERN_WARNING "DMSDOS: MOVEBACK ioctl has gone\n"); + return -EINVAL; + case DMSDOS_SET_MAXCLUSTER: + /*if(current->euid!=0)return -EPERM; + return set_maxcluster(dir->i_sb,data);*/ + printk(KERN_WARNING "DMSDOS: SETMAXCLUSTER ioctl has gone.\n"); + return -EINVAL; + case DMSDOS_FREE_IDLE_CACHE: + if(current->euid!=0)return -EPERM; + free_idle_cache(); + return 0; + case DMSDOS_SET_LOGLEVEL: + if(current->euid!=0)return -EPERM; + loglevel=data; + printk(KERN_INFO "DMSDOS: ioctl: loglevel set to 0x%lx.\n",loglevel); + return 0; + case DMSDOS_SET_SPEEDUP: + if(current->euid!=0)return -EPERM; + dmsdos_speedup=data; + printk(KERN_INFO "DMSDOS: ioctl: speedup set to 0x%lx.\n",dmsdos_speedup); + return 0; + case DMSDOS_SYNC_CCACHE: + sync_cluster_cache(data); + return 0; + case DMSDOS_LOG_STATISTICS: + if(current->euid!=0)return -EPERM; + log_statistics(); + return 0; + case DMSDOS_RECOMPRESS: + printk(KERN_WARNING "DMSDOS: RECOMPRESS ioctl has gone\n"); + return -EINVAL; + case DMSDOS_REPORT_MEMORY: + { Memuse memuse; + if(verify_area(VERIFY_WRITE,idata,sizeof(Memuse)))return -EFAULT; + get_memory_usage_acache(&(memuse.acachebytes),&(memuse.max_acachebytes)); + get_memory_usage_ccache(&(memuse.ccachebytes),&(memuse.max_ccachebytes)); + memcpy_tofs(idata,&memuse,sizeof(Memuse)); + return 0; + } + default: + return -EINVAL; + } + +} + +void remove_from_daemon_list(struct super_block*sb,int clusternr) +{ int i; + + if(must_maintain_list==0)return; + + lock_listaccess(); + + /* check list for existing entry and mark it as overwritten */ + for(i=0;i<LISTSIZE;++i) + { if(rwlist[i].flag!=D_EMPTY) + if(rwlist[i].clusternr==clusternr&&rwlist[i].sb->s_dev==sb->s_dev) + { + if(rwlist[i].flag==D_IN_D_ACTION){rwlist[i].flag=D_OVERWRITTEN;break;} + if(rwlist[i].flag==D_VALID){rwlist[i].flag=D_EMPTY;--listcount;break;} + } + } + + if(daemon_present==0) + { if(listcount==0)must_maintain_list=0; + } + + unlock_listaccess(); +} + +int lastawake=0; +int try_daemon(struct super_block*sb,int clusternr, int length, int method) +{ int i; + + if(daemon_present==0&&must_maintain_list==0)return 0; + + lock_listaccess(); + + must_maintain_list=1; + + /* check list for existing entry and mark it as overwritten */ +/* no longer necessary here...... + for(i=0;i<LISTSIZE;++i) + { if(rwlist[i].clusternr==clusternr&&rwlist[i].sb->s_dev==sb->s_dev) + { + if(rwlist[i].flag==D_IN_D_ACTION){rwlist[i].flag=D_OVERWRITTEN;break;} + if(rwlist[i].flag==D_VALID){rwlist[i].flag=D_EMPTY;--listcount;break;} + } + } +*/ + + if(daemon_present==0||listcount==LISTSIZE) + { + if(listcount==0)must_maintain_list=0; + unlock_listaccess(); + return 0; + } + + /* find empty slot in list */ + for(i=LISTSIZE;i>0;--i) + { if(rwlist[wlist].flag==D_EMPTY) goto w_found; + /*wlist=(wlist+1)&(LISTSIZE-1);*/ + wlist++;if(wlist>=LISTSIZE)wlist=0; + } + /*this shouldn't happen - otherwise there's a count error */ + printk(KERN_WARNING "DMSDOS: try_daemon: no empty slot found, listcount corrected.\n"); + listcount=LISTSIZE; + unlock_listaccess(); + return 0; + + w_found: + ++listcount; + rwlist[wlist].clusternr=clusternr; + rwlist[wlist].sb=sb; + rwlist[wlist].length=length; + rwlist[wlist].method=method; + rwlist[wlist].flag=D_VALID; + unlock_listaccess(); + + /* check whether or not to awake the daemon - + strategy is this: + * don't awake it in periods below 5 secs + * don't awake it for just a little data + */ + if(lastawake+5>CURRENT_TIME||listcount<LISTSIZE/2)return 1; + lastawake=CURRENT_TIME; +#ifdef INTERNAL_DAEMON + wake_up(&daemon_wait); +#else + i=kill_proc(daemon_pid,SIGUSR1,1); + if(i<0) + { printk(KERN_WARNING "DMSDOS: try_daemon: kill_proc daemon_pid=%d failed with error code %d, assuming daemon has died\n", + daemon_pid,-i); + daemon_present=0; + } +#endif + return 1; +} + +void clear_list_dev(struct super_block*sb) +{ int i; + + lock_listaccess(); + for(i=0;i<LISTSIZE;++i) + { if(rwlist[i].flag!=D_EMPTY) + { if(rwlist[i].sb)printk(KERN_ERR "DMSDOS: clear_list_dev: Uhh, sb==NULL ...\n"); + else + if(rwlist[i].sb->s_dev==sb->s_dev) + { rwlist[i].flag=D_EMPTY; + --listcount; + } + } + } + unlock_listaccess(); +} + +void init_daemon(void) +{ int i; + + if(daemon_present) + { printk(KERN_INFO "DMSDOS: init_daemon: daemon already present\n"); +#ifdef INTERNAL_DAEMON + ++internal_daemon_counter; +#endif + return; + } + lock_listaccess(); + LOG_REST("DMSDOS: clearing rwlist...\n"); + for(i=0;i<LISTSIZE;++i)rwlist[i].flag=D_EMPTY; + listcount=0; + unlock_listaccess(); + +#ifdef INTERNAL_DAEMON + /*daemon_present=1...this is maintained by idmsdosd itself*/; + internal_daemon_counter=1; + /* fire up internal daemon */ + printk(KERN_NOTICE "DMSDOS: starting internal daemon...\n"); + daemon_go_home=0; + kernel_thread(idmsdosd,NULL,0); +#endif +} + +void log_list_statistics() +{ int j; + int empty; + int valid; + int in_action; + int overwritten; + + lock_listaccess(); + + printk(KERN_INFO "DMSDOS: list statistics:\n"); + printk(KERN_INFO "daemon_present=%d must_maintain_list=%d listcount=%d\n", + daemon_present,must_maintain_list,listcount); + empty=0; + valid=0; + in_action=0; + overwritten=0; + + for(j=0;j<LISTSIZE;++j) + { switch(rwlist[j].flag) + { case D_EMPTY: ++empty; break; + case D_VALID: ++valid; break; + case D_IN_D_ACTION: ++in_action; break; + case D_OVERWRITTEN: ++overwritten; break; + default: printk(KERN_ERR "DMSDOS: log_list_statistics: cannot happen.\n"); + } + } + printk(KERN_INFO "sum: empty=%d valid=%d in_action=%d overwritten=%d\n", + empty,valid,in_action,overwritten); + + unlock_listaccess(); +} + +#ifdef INTERNAL_DAEMON + +int internal_d_read(int*val1, int*val2, int*val3, + unsigned char*clusterd) +{ int i; + int cluster; + Mdfat_entry mde; + int length; + int method; + struct super_block*sb=NULL; + + lock_listaccess(); + /*search next valid entry*/ + for(i=LISTSIZE;i>0;--i) + { if(rwlist[rlist].flag==D_VALID) + { /* check in mdfat that cluster is actually used */ + sb=rwlist[rlist].sb; + if(sb) + { dbl_mdfat_value(sb,rwlist[rlist].clusternr, + NULL,&mde); + if((mde.flags&3)==3)goto vr_found; /* used and uncompressed */ + } + rwlist[rlist].flag=D_EMPTY; /* remove - it's garbage */ + --listcount; + LOG_DAEMON("DMSDOS: D_READ: removing garbage entry cluster=%d\n", + rwlist[rlist].clusternr); + } + /*rlist=(rlist+1)&(LISTSIZE-1);*/ + rlist++;if(rlist>=LISTSIZE)rlist=0; + } + unlock_listaccess(); + return 0; + vr_found: + cluster=rwlist[rlist].clusternr; + sb=rwlist[rlist].sb; + length=rwlist[rlist].length; + method=rwlist[rlist].method; + if((i=dmsdos_read_cluster(sb,clusterd,cluster))<0) + { printk(KERN_ERR "DMSDOS: ioctl: D_READ: read_cluster failed!\n"); + rwlist[rlist].flag=D_EMPTY; + --listcount; + unlock_listaccess(); + return 0; + } + if(length<0)length=i; /* if invalid length, use read value */ + rwlist[rlist].flag=D_IN_D_ACTION; + *val1=rlist; /*put_fs_long(rlist,idata);*/ + *val2=length; /*put_fs_long(length,idata+sizeof(long));*/ + *val3=method; /*put_fs_long(rwlist[rlist].method,idata+2*sizeof(long));*/ + unlock_listaccess(); + return 1; +} + +int internal_d_write(int plist, int rawlength, unsigned char*clusterd) +{ Mdfat_entry mde; + int length; + int cluster; + struct super_block*sb=NULL; + + lock_listaccess(); + if(rwlist[plist].flag==D_OVERWRITTEN){rwlist[plist].flag=D_EMPTY;--listcount;} + if(rwlist[plist].flag!=D_IN_D_ACTION) + { LOG_DAEMON("DMSDOS: D_WRITE: Entry not in action, flag=%d cluster=%d\n", + rwlist[plist].flag,rwlist[plist].clusternr); + unlock_listaccess(); + return 0; + } + + /* will be freed in any case later, so: */ + --listcount; + + if(rawlength==0) + { /* data were uncompressible */ + rwlist[plist].flag=D_EMPTY; + unlock_listaccess(); + return 0; + } + /* check that cluster is used */ + sb=rwlist[plist].sb; + if(sb==NULL)goto shitt; + dbl_mdfat_value(sb,rwlist[plist].clusternr, + NULL,&mde); + if((mde.flags&3)!=3) + { shitt: + rwlist[plist].flag=D_EMPTY; /* remove - it's garbage */ + LOG_DAEMON("DMSDOS: D_WRITE: removing garbage entry cluster=%d\n", + rwlist[plist].clusternr); + unlock_listaccess(); + return 0; + } + length=rwlist[plist].length; + cluster=rwlist[plist].clusternr; + rwlist[plist].flag=D_EMPTY; + unlock_listaccess(); + /* this may call try_daemon via ccache code (freeing a ccache slot) */ + daemon_write_cluster(sb,clusterd,length,cluster, + rawlength); + return 0; +} + +typedef struct +{ long val1; + long val2; + long val3; + unsigned char data[32*1024]; +} Cdata; + +/* we need the memory always - there's only one process using it - idmsdosd */ +Cdata cdata; +Cdata ckdata; + +int get_and_compress_one(void) +{ int ret; + int handle; + int length; + int size; + int method; + + /* get cluster to compress */ + LOG_DAEMON("idmsdosd: Trying to read...\n"); + ret=internal_d_read(&handle,&length,&method,cdata.data); + if(ret!=1) + { LOG_DAEMON("idmsdosd: nothing there - D_READ ioctl returned %d\n",ret); + return ret; + } + + size=(length-1)/512+1; + LOG_DAEMON("idmsdosd: compressing...\n"); + ret= +#ifdef DMSDOS_CONFIG_STAC + (method==SD_3||method==SD_4) ? + stac_compress(cdata.data,length,ckdata.data, + sizeof(ckdata.data),method,11) : +#endif + dbl_compress(ckdata.data,cdata.data,size,method,11)*512; + LOG_DAEMON("idmsdosd: compress %X from %d returned %d\n", + method,length,ret); + if(ret<0)ret=0; /* compression failed */ + LOG_DAEMON("idmsdosd: writing...\n"); + internal_d_write(handle,ret,ckdata.data); + + return 1; /* one cluster compressed */ +} + +struct timer_list idmsdosd_timer; + +static void idmsdosd_timer_function(unsigned long data) +{ + /* do something */ + /*printk(KERN_DEBUG "DMSDOS: idmsdosd_timer_function: doing something :)\n");*/ + + /* wake up daemon */ + wake_up(&daemon_wait); + + del_timer(&idmsdosd_timer); + idmsdosd_timer.expires=jiffies + (IDMSDOSD_TIME * HZ); + add_timer(&idmsdosd_timer); +} + +int idmsdosd(void*dummy) +{ + /* throw away some things from the calling process */ + /* otherwise the root fs cannot be unmounted on reboot ... urgh*/ + exit_files(current); + exit_fs(current); + exit_sighand(current); + exit_mm(current); + + /* + * We have a bare-bones task_struct, and really should fill + * in a few more things so "top" and /proc/2/{exe,root,cwd} + * display semi-sane things. Not real crucial though... + */ + current->session = 1; + current->pgrp = 1; + sprintf(current->comm, "dmsdosd"); + +#undef NEED_LOCK_KERNEL + /* do we really need this ??? The code was copied from kflushd. */ +#ifdef NEED_LOCK_KERNEL + /* + * As a kernel thread we want to tamper with system buffers + * and other internals and thus be subject to the SMP locking + * rules. (On a uniprocessor box this does nothing). + */ +#ifdef __SMP__ + lock_kernel(); + syscall_count++; +#endif +#endif + + daemon_present=1; + + init_timer(&idmsdosd_timer); + idmsdosd_timer.function=idmsdosd_timer_function; + idmsdosd_timer.expires=jiffies + (IDMSDOSD_TIME * HZ); + add_timer(&idmsdosd_timer); + + for(;;) + { while(get_and_compress_one()==1); + /* don't kill the system performance when nothing to compress */ + { LOG_DAEMON("idmsdosd: sleeping...\n"); + interruptible_sleep_on(&daemon_wait); + if(daemon_go_home)break; + /* throw away long idle mdfat/dfat/bitfat sectors and clusters */ + free_idle_cache(); + } + } + + del_timer(&idmsdosd_timer); + daemon_present=0; + + LOG_DAEMON("idmsdosd: exiting...\n"); + wake_up(&daemon_exit_wait); + return 0; +} + +void remove_internal_daemon(void) +{ if(daemon_present) + { printk(KERN_NOTICE "DMSDOS: killing internal daemon...\n"); + daemon_go_home=1; + wake_up(&daemon_wait); + interruptible_sleep_on(&daemon_exit_wait); + /* this seems to work - don't ask me why :) */ + } +} + +#endif + +void exit_daemon(void) +{ +#ifdef INTERNAL_DAEMON + --internal_daemon_counter; + if(internal_daemon_counter<0) + { printk(KERN_WARNING "DMSDOS: exit_daemon: counter<0 ???\n"); + internal_daemon_counter=0; + } + if(internal_daemon_counter==0)remove_internal_daemon(); +#endif +} + +void force_exit_daemon(void) +{ +#ifdef INTERNAL_DAEMON + internal_daemon_counter=0; + remove_internal_daemon(); +#endif +} |