1 /*
2  * CVF extensions for fat-based filesystems
3  *
4  * written 1997,1998 by Frank Gockel <gockel@sent13.uni-duisburg.de>
5  *
6  * please do not remove the next line, dmsdos needs it for verifying patches
7  * CVF-FAT-VERSION-ID: 1.2.0
8  *
9  */
10 
11 #include<linux/sched.h>
12 #include<linux/fs.h>
13 #include<linux/msdos_fs.h>
14 #include<linux/msdos_fs_sb.h>
15 #include<linux/string.h>
16 #include<linux/fat_cvf.h>
17 #include<linux/config.h>
18 #ifdef CONFIG_KMOD
19 #include<linux/kmod.h>
20 #endif
21 
22 #define MAX_CVF_FORMATS 3
23 
24 struct buffer_head *default_fat_bread(struct super_block *,int);
25 struct buffer_head *default_fat_getblk(struct super_block *, int);
26 void default_fat_brelse(struct super_block *, struct buffer_head *);
27 void default_fat_mark_buffer_dirty (struct super_block *, struct buffer_head *);
28 void default_fat_set_uptodate (struct super_block *, struct buffer_head *,int);
29 int default_fat_is_uptodate(struct super_block *, struct buffer_head *);
30 int default_fat_access(struct super_block *sb,int nr,int new_value);
31 void default_fat_ll_rw_block (struct super_block *sb, int opr, int nbreq,
32 			      struct buffer_head *bh[32]);
33 int default_fat_bmap(struct inode *inode,int block);
34 ssize_t default_fat_file_write(struct file *filp, const char *buf,
35 			       size_t count, loff_t *ppos);
36 
37 struct cvf_format default_cvf = {
38 	cvf_version: 		0,	/* version - who cares? */
39 	cvf_version_text: 	"plain",
40 	flags:			0,	/* flags - who cares? */
41 	cvf_bread:		default_fat_bread,
42 	cvf_getblk:		default_fat_getblk,
43 	cvf_brelse:		default_fat_brelse,
44 	cvf_mark_buffer_dirty:	default_fat_mark_buffer_dirty,
45 	cvf_set_uptodate:	default_fat_set_uptodate,
46 	cvf_is_uptodate:	default_fat_is_uptodate,
47 	cvf_ll_rw_block:	default_fat_ll_rw_block,
48 	fat_access:		default_fat_access,
49 	cvf_bmap:		default_fat_bmap,
50 	cvf_file_read:		generic_file_read,
51 	cvf_file_write:		default_fat_file_write,
52 };
53 
54 struct cvf_format *cvf_formats[MAX_CVF_FORMATS];
55 int cvf_format_use_count[MAX_CVF_FORMATS];
56 
register_cvf_format(struct cvf_format * cvf_format)57 int register_cvf_format(struct cvf_format*cvf_format)
58 { int i,j;
59 
60   for(i=0;i<MAX_CVF_FORMATS;++i)
61   { if(cvf_formats[i]==NULL)
62     { /* free slot found, now check version */
63       for(j=0;j<MAX_CVF_FORMATS;++j)
64       { if(cvf_formats[j])
65         { if(cvf_formats[j]->cvf_version==cvf_format->cvf_version)
66           { printk("register_cvf_format: version %d already registered\n",
67                    cvf_format->cvf_version);
68             return -1;
69           }
70         }
71       }
72       cvf_formats[i]=cvf_format;
73       cvf_format_use_count[i]=0;
74       printk("CVF format %s (version id %d) successfully registered.\n",
75              cvf_format->cvf_version_text,cvf_format->cvf_version);
76       return 0;
77     }
78   }
79 
80   printk("register_cvf_format: too many formats\n");
81   return -1;
82 }
83 
unregister_cvf_format(struct cvf_format * cvf_format)84 int unregister_cvf_format(struct cvf_format*cvf_format)
85 { int i;
86 
87   for(i=0;i<MAX_CVF_FORMATS;++i)
88   { if(cvf_formats[i])
89     { if(cvf_formats[i]->cvf_version==cvf_format->cvf_version)
90       { if(cvf_format_use_count[i])
91         { printk("unregister_cvf_format: format %d in use, cannot remove!\n",
92           cvf_formats[i]->cvf_version);
93           return -1;
94         }
95 
96         printk("CVF format %s (version id %d) successfully unregistered.\n",
97         cvf_formats[i]->cvf_version_text,cvf_formats[i]->cvf_version);
98         cvf_formats[i]=NULL;
99         return 0;
100       }
101     }
102   }
103 
104   printk("unregister_cvf_format: format %d is not registered\n",
105          cvf_format->cvf_version);
106   return -1;
107 }
108 
dec_cvf_format_use_count_by_version(int version)109 void dec_cvf_format_use_count_by_version(int version)
110 { int i;
111 
112   for(i=0;i<MAX_CVF_FORMATS;++i)
113   { if(cvf_formats[i])
114     { if(cvf_formats[i]->cvf_version==version)
115       { --cvf_format_use_count[i];
116         if(cvf_format_use_count[i]<0)
117         { cvf_format_use_count[i]=0;
118           printk(KERN_EMERG "FAT FS/CVF: This is a bug in cvf_version_use_count\n");
119         }
120         return;
121       }
122     }
123   }
124 
125   printk("dec_cvf_format_use_count_by_version: version %d not found ???\n",
126          version);
127 }
128 
detect_cvf(struct super_block * sb,char * force)129 int detect_cvf(struct super_block*sb,char*force)
130 { int i;
131   int found=0;
132   int found_i=-1;
133 
134   if(force)
135     if(strcmp(force,"autoload")==0)
136     {
137 #ifdef CONFIG_KMOD
138       request_module("cvf_autoload");
139       force=NULL;
140 #else
141       printk("cannot autoload CVF modules: kmod support is not compiled into kernel\n");
142       return -1;
143 #endif
144     }
145 
146 #ifdef CONFIG_KMOD
147   if(force)
148     if(*force)
149       request_module(force);
150 #endif
151 
152   if(force)
153   { if(*force)
154     { for(i=0;i<MAX_CVF_FORMATS;++i)
155       { if(cvf_formats[i])
156         { if(!strcmp(cvf_formats[i]->cvf_version_text,force))
157             return i;
158         }
159       }
160       printk("CVF format %s unknown (module not loaded?)\n",force);
161       return -1;
162     }
163   }
164 
165   for(i=0;i<MAX_CVF_FORMATS;++i)
166   { if(cvf_formats[i])
167     { if(cvf_formats[i]->detect_cvf(sb))
168       { ++found;
169         found_i=i;
170       }
171     }
172   }
173 
174   if(found==1)return found_i;
175   if(found>1)printk("CVF detection ambiguous, please use cvf_format=xxx option\n");
176   return -1;
177 }
178