|
|
1.1 root 1: /*
2: dblspace_fileops.c-2.1.80
3:
4: DMSDOS CVF-FAT module: file operation routines (for kernel>=2.1.80).
5:
6: ******************************************************************************
7: DMSDOS (compressed MSDOS filesystem support) for Linux
8: written 1995-1998 by Frank Gockel and Pavel Pisa
9:
10: (C) Copyright 1995-1998 by Frank Gockel
11: (C) Copyright 1996-1998 by Pavel Pisa
12:
13: Some code of dmsdos has been copied from the msdos filesystem
14: so there are the following additional copyrights:
15:
16: (C) Copyright 1992,1993 by Werner Almesberger (msdos filesystem)
17: (C) Copyright 1994,1995 by Jacques Gelinas (mmap code)
18: (C) Copyright 1992-1995 by Linus Torvalds
19:
20: DMSDOS was inspired by the THS filesystem (a simple doublespace
21: DS-0-2 compressed read-only filesystem) written 1994 by Thomas Scheuermann.
22:
23: The DMSDOS code is distributed under the Gnu General Public Licence.
24: See file COPYING for details.
25: ******************************************************************************
26:
27: */
28:
29: #include <linux/sched.h>
30: #include <linux/ctype.h>
31: #include <linux/major.h>
32: #include <linux/blkdev.h>
33: #include <linux/fs.h>
34: #include <linux/stat.h>
35: #include <linux/locks.h>
36: #include <asm/segment.h>
37: #include <linux/mm.h>
38: #include <linux/malloc.h>
39: #include <linux/string.h>
40: #include <linux/msdos_fs.h>
41: #include <linux/errno.h>
42: #include <linux/kernel.h>
43: #include <linux/shm.h>
44: #include <linux/mman.h>
45: #include <asm/system.h>
46: #include "dmsdos.h"
47:
48: extern unsigned long dmsdos_speedup;
49:
50: #define MIN(x,y) ( ( (x)<(y) ) ? (x) : (y) )
51:
52: void do_cluster_reada(struct super_block*sb,int clusternr)
53: { /* read one cluster ahead without waiting for the data */
54: int nextclust;
55:
56: nextclust=dbl_fat_nextcluster(sb,clusternr,NULL);
57: if(nextclust>0)
58: { /* no need to read-ahead if it is in cache */
59: /* for a simple search for existence we needn't lock the cache */
60: if(find_in_ccache(sb,nextclust,NULL,NULL)==NULL)
61: dmsdos_read_cluster(sb,NULL,nextclust);
62: }
63: }
64:
65: int dblspace_file_read(
66: struct file *filp,
67: char *buf,
68: size_t count,
69: loff_t *ppos)
70: {
71: int clusternr;
72: /*unsigned char*clusterd;*/
73: int offset;
74: int bytes_read;
75: int membytes;
76: int membytes_bits;
77: int ret;
78: char * b;
79: int toread;
80: Cluster_head*ch;
81: struct inode *inode;
82: struct super_block*sb;
83: Dblsb*dblsb;
84:
85: LOG_FS("DMSDOS: file_read start...\n");
86:
87: inode = filp->f_dentry->d_inode;
88: LOG_FS("DMSDOS: file_read: got inode\n");
89: sb=inode->i_sb;
90: LOG_FS("DMSDOS: file_read: got sb\n");
91: dblsb=MSDOS_SB(sb)->private_data;
92: LOG_FS("DMSDOS: file_read: got dblsb\n");
93:
94: if (!inode) {
95: printk(KERN_ERR "DMSDOS: file_read: inode = NULL, rejected.\n");
96: return -EINVAL;
97: }
98: /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
99: if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
100: printk(KERN_ERR "DMSDOS: file_read: mode = %07o, rejected.\n",inode->i_mode);
101: return -EINVAL;
102: }
103:
104: LOG_FS("DMSDOS: file_read init complete...\n");
105:
106: if(count<=0)return 0;
107:
108: if(*ppos>=inode->i_size)return 0;
109:
110: if(*ppos+count>inode->i_size)count=inode->i_size-*ppos;
111:
112: ret=verify_area(VERIFY_WRITE, buf, count);
113: if(ret<0)return ret;
114: ret=0;
115:
116: membytes=SECTOR_SIZE*dblsb->s_sectperclust;
117: membytes_bits=SECTOR_BITS+dblsb->s_spc_bits;
118:
119: /* calculate clusternr for cluster to read */
120: offset=*ppos&(membytes-1);
121: LOG_CLUST("DMSDOS: file_read: get_cluster...\n");
122: clusternr=get_cluster(inode,*ppos>>membytes_bits);
123: if(clusternr<=0)
124: { printk(KERN_ERR "DMSDOS: file_readx: FAT mismatches file size for ino=%ld\n",
125: inode->i_ino);
126: return 0;
127: }
128:
129: bytes_read=0;
130: b=buf;
131:
132: do
133: { LOG_CLUST("DMSDOS: file_read: calling ch_read...\n");
134: ch=ch_read(sb,clusternr,0);
135: LOG_CLUST("DMSDOS: file_read: after ch_read\n");
136: ret=(ch==NULL)?-EIO:0;
137: if(ret>=0)
138: { if(count>READA_THRESHOLD&&(dmsdos_speedup&SP_USE_READ_AHEAD)!=0)
139: do_cluster_reada(inode->i_sb,clusternr);
140: toread=(membytes-offset>count) ? count : membytes-offset;
141: /*printk("DMSDOS file_readx: memcpy_tofs(0x%08x,0x%08x,0x%08x)\n",
142: b,clusterd+offset,toread);*/
143: memcpy_tofs(b,ch->c_data+offset,toread);
144: bytes_read+=toread;
145: *ppos+=toread;
146: count-=toread;
147: ch_free(ch);
148: if(count>0)
149: { b+=toread;
150: offset=0;
151: LOG_CLUST("DMSDOS: file_read: get_cluster...\n");
152: clusternr=get_cluster(inode,*ppos>>membytes_bits);
153: if(*ppos&(membytes-1))
154: panic("DMSDOS: read_file bug: f_pos not cluster-aligned");
155: if(clusternr<=0)
156: { ret=-EIO;
157: printk(KERN_ERR "DMSDOS: file_readx: FAT mismatches file size for ino=%ld\n",
158: inode->i_ino);
159: }
160: }
161: }
162: }
163: while(count>0&&ret>=0);
164:
165: return (bytes_read==0&&ret<0)?ret:bytes_read;
166: }
167:
168: int dblspace_file_write(
169: struct file *filp,
170: const char *buf,
171: size_t count,
172: loff_t *ppos)
173: {
174: int cluster;
175: int ret=0;
176: unsigned int offset;
177: const unsigned char *b;
178: int canwrite;
179: int written;
180: int clustersize;
181: int clustersize_bits;
182: int uc;
183: Cluster_head*ch;
184: struct inode *inode = filp->f_dentry->d_inode;
185: struct super_block*sb=inode->i_sb;
186: Dblsb*dblsb=MSDOS_SB(sb)->private_data;
187:
188: if (!inode) {
189: printk(KERN_ERR "dmsdos_file_write: inode = NULL\n");
190: return -EINVAL;
191: }
192: /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
193: if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
194: printk(KERN_ERR "dmsdos_file_write: mode = %07o\n",inode->i_mode);
195: return -EINVAL;
196: }
197: /*
198: * ok, append may not work when many processes are writing at the same time
199: * but so what. That way leads to madness anyway.
200: */
201: if(sb->s_flags&MS_RDONLY)
202: { printk(KERN_ERR "DMSDOS: file_write: READ-ONLY filesystem\n");
203: return -EROFS;
204: }
205:
206: if(dblsb->s_comp==READ_ONLY)return -EPERM;
207:
208: if (filp->f_flags & O_APPEND) *ppos = inode->i_size;
209: if (count <= 0) return 0;
210:
211: ret=verify_area(VERIFY_READ, buf, count);
212: if(ret<0)return ret;
213: ret=0;
214:
215: clustersize=dblsb->s_sectperclust*SECTOR_SIZE;
216: clustersize_bits=dblsb->s_spc_bits+SECTOR_BITS;
217:
218: uc=0;
219: /* no longer working in 2.3.99...
220: if(dmsdos_speedup&SP_NO_EMD_COMPR)
221: uc=(MSDOS_I(inode)->i_binary>1)?1:0; / uncompressed forced /
222: */
223:
224: offset=*ppos&(clustersize-1);
225: do
226: { cluster=get_cluster(inode,*ppos>>clustersize_bits);
227: if(cluster>0)break;
228: if(dblsb->s_full==2)
229: { printk(KERN_ERR "DMSDOS: write_file: CVF full (full flag set)\n");
230: return -ENOSPC;
231: }
232: if(dblsb->s_free_sectors<MIN_FREE_SECTORS)
233: { printk(KERN_ERR "DMSDOS: write_file: CVF full (free sector count too low)\n");
234: return -ENOSPC;
235: }
236: if(fat_add_cluster(inode)<0)
237: { printk(KERN_ERR "DMSDOS: write_file: fat_add_cluster failed\n");
238: return -ENOSPC;
239: }
240: }
241: while(cluster<=0);
242:
243: LOG_CLUST("DMSDOS: file_write: beginning with cluster %d\n",
244: cluster);
245:
246: b=buf;
247: written=0;
248:
249: while(count>0)
250: {
251: if(offset>0||count<clustersize)
252: { /* cluster must be read because it will only partially overwritten */
253: LOG_CLUST("DMSDOS: write_file: reading cluster %d...\n",cluster);
254: ch=ch_read(sb,cluster,C_KEEP_LOCK);
255: if(ch==NULL)
256: { printk(KERN_ERR "DMSDOS: write_file: read_cluster failed!\n");
257: ret=-EIO;
258: break;
259: }
260: /*lock_ch(ch); we call with KEEP_LOCK above */
261: }
262: else
263: { /* cluster will be fully overwritten, don't read it */
264: ch=ch_read(sb,cluster,C_KEEP_LOCK|C_NO_READ);
265: if(ch==NULL)
266: { printk(KERN_ERR "DMSDOS: write_file: ch_noread failed!\n");
267: ret=-EIO;
268: break;
269: }
270: /*lock_ch(ch); we call with KEEP_LOCK above */
271: ch->c_length= (count+offset<clustersize) ?
272: count+offset : clustersize;
273: }
274: canwrite=MIN(clustersize-offset,count);
275: memcpy_fromfs(&(ch->c_data[offset]),b,canwrite);
276:
277: /* did cluster grow ? */
278: if(canwrite+offset>ch->c_length)
279: { /*printk(KERN_ERR "DMSDOS: write_file: write beyond logical cluster end, appending.\n");
280: */
281: ch->c_length=canwrite+offset;
282: }
283: if(ch->c_length>clustersize)
284: { printk(KERN_ERR "DMSDOS: write_file: length>clustersize ??? bug !!!\n");
285: ch->c_length=clustersize;
286: }
287:
288: /*unlock_ch(ch); no not here*/
289:
290: LOG_CLUST("DMSDOS: write_file: writing cluster %d...\n",cluster);
291:
292: /* ch_dirty_locked unlocks the cluster */
293: if(ch_dirty_locked(ch,0,uc)<0)
294: { printk(KERN_ERR "DMSDOS: write_file: ch_dirty failed!\n");
295: ch_free(ch);
296: ch=NULL;
297: ret=-EIO;
298: break;
299: }
300: ch_free(ch);
301: ch=NULL;
302:
303: offset=0;
304: b+=canwrite;
305: *ppos+=canwrite;
306: written+=canwrite;
307: count-=canwrite;
308:
309: if(count==0)break; /* braucht keinen neuen cluster mehr*/
310:
311: /* next cluster ? */
312: cluster=get_cluster(inode,*ppos>>clustersize_bits);
313: if(cluster<=0)
314: { LOG_CLUST("DMSDOS: write_file: write_loop: allocating new cluster\n");
315: if(dblsb->s_full==2)
316: { printk(KERN_ERR "DMSDOS: write_file: CVF full (full flag set)\n");
317: ret=-ENOSPC;
318: break;
319: }
320: if(dblsb->s_free_sectors<MIN_FREE_SECTORS)
321: { printk(KERN_ERR "DMSDOS: write_file: CVF full (free sector count too low)\n");
322: ret=-ENOSPC;
323: break;
324: }
325: if(fat_add_cluster(inode)<0)
326: { printk(KERN_ERR "DMSDOS: write_file: fat_add_cluster failed\n");
327: ret=-ENOSPC;
328: break;
329: }
330: cluster=get_cluster(inode,*ppos>>clustersize_bits);
331: if(cluster<=0)
332: { printk(KERN_ERR "DMSDOS: write_file: something's wrong, cannot happen\n");
333: ret=-EIO;
334: break;
335: }
336: }
337: }
338:
339: if(*ppos>inode->i_size)
340: { inode->i_size=*ppos;
341: /*inode->i_dirt=1; .... HMMM .... */
342: mark_inode_dirty(inode);
343: }
344:
345: return (written==0)?ret:written;
346: }
347:
348:
349: /* Grmpf.... partially untested code. Don't know an application that does
350: writable mmaps, but it would be needed for testing this piece of code */
351:
352: /* idea: kernel does buffer reads with bmap calculated buffers - impossible
353: for dmsdos. (see kernel mmap code).
354: kernel emulates writable mmap by calling file_write when no buffers
355: are present - should work for dmsdos.
356: so we do file_read-emulated readable mmaps here though the
357: generic_mmap function is used.
358: */
359:
360: #ifdef DMSDOS_USE_READPAGE
361:
362: #ifdef __FOR_KERNEL_2_3_99
363: #error kernels >= 2.3.99 need mmap interface
364: #endif
365:
366: int read_the_page(unsigned long address, unsigned long pos,
367: struct inode*inode)
368: {
369: unsigned int clear;
370: long gap; /* distance from eof to pos */
371:
372: LOG_FS("DMSDOS: read_the_page\n");
373:
374: address &= PAGE_MASK;
375:
376: clear = 0;
377: gap = inode->i_size - pos;
378: if (gap <= 0){
379: /* mmaping beyond end of file */
380: clear = PAGE_SIZE;
381: }else{
382: int cur_read;
383: int need_read;
384: struct file filp;
385: if (gap < PAGE_SIZE){
386: clear = PAGE_SIZE - gap;
387: }
388: filp.f_reada = 0;
389: filp.f_pos = pos;
390: need_read = PAGE_SIZE - clear;
391: { mm_segment_t cur_fs = get_fs();
392: filp.f_dentry=kmalloc(sizeof(struct dentry),GFP_KERNEL);
393: if(filp.f_dentry==NULL)
394: { printk(KERN_ERR "DMSDOS: read_the_page: no memory!\n");
395: return -1;
396: }
397: filp.f_dentry->d_inode=inode;
398:
399: set_fs (KERNEL_DS);
400: LOG_FS("DMSDOS: read_the_page: calling file_read...\n");
401: cur_read = dblspace_file_read (&filp,
402: (char*)address,
403: need_read,
404: &(filp.f_pos));
405: set_fs (cur_fs);
406: kfree(filp.f_dentry);
407: }
408: if (cur_read != need_read){
409: printk ("DMSDOS: Error while reading an mmap file %d <> %d\n"
410: ,cur_read,need_read);
411: return -1;
412: }
413: }
414: if (clear > 0){
415: memset ((char*)address+PAGE_SIZE-clear,0,clear);
416: }
417: return 0;
418: }
419:
420: #ifdef READPAGE_DENTRY
421: int dblspace_readpage(struct dentry*dentry, struct page *page)
422: { unsigned long address;
423: int error = -1;
424: struct inode*inode=dentry->d_inode;
425: #else
426: int dblspace_readpage(struct inode *inode, struct page *page)
427: { unsigned long address;
428: int error = -1;
429: #endif
430: LOG_FS("DMSDOS: readpage %08lx\n", page_address(page));
431:
432: address = page_address(page);
433: atomic_inc(&page->count);
434: set_bit(PG_locked, &page->flags);
435:
436: /* now read the data */
437: error=read_the_page(address,page->offset,inode);
438:
439: LOG_FS("DMSDOS: readpage: read_the_page returned %d\n",error);
440:
441: if(error==0)set_bit(PG_uptodate, &page->flags);
442:
443: clear_bit(PG_locked, &page->flags);
444: wake_up(&page->wait);
445:
446: free_page(address);
447: return error;
448: }
449:
450: #else /* from: ifdef DMSDOS_USE_READPAGE */
451:
452: /* this is supposed to be obsolete stuff for older kernels... */
453:
454: /* we reactivate it for 2.3.99 kernel */
455:
456: /*
457: * Fill in the supplied page for mmap
458: */
459: struct page* dblspace_file_mmap_nopage(
460: struct vm_area_struct * area,
461: unsigned long address,
462: int write_access)
463: {
464: struct inode * inode = area->vm_file->f_dentry->d_inode;
465: struct page* page;
466: unsigned int clear;
467: int pos;
468: long gap; /* distance from eof to pos */
469:
470: LOG_FS("DMSDOS: file_mmap_nopage\n");
471: /*page = __get_free_page(GFP_KERNEL);*/
472: page=alloc_pages(GFP_KERNEL,0);
473: if (!page)return NULL;
474: LOG_FS("DMSDOS: file_mmap_nopage: got page\n");
475:
476: address &= PAGE_MASK;
477: pos = address - area->vm_start + area->vm_pgoff*PAGE_SIZE;
478:
479: clear = 0;
480: gap = inode->i_size - pos;
481: if (gap <= 0){
482: /* mmaping beyond end of file */
483: clear = PAGE_SIZE;
484: }else{
485: int cur_read;
486: int need_read;
487: struct file filp;
488: if (gap < PAGE_SIZE){
489: clear = PAGE_SIZE - gap;
490: }
491: filp.f_reada = 0;
492: filp.f_pos = pos;
493: need_read = PAGE_SIZE - clear;
494: { mm_segment_t cur_fs = get_fs();
495: filp.f_dentry=kmalloc(sizeof(struct dentry),GFP_KERNEL);
496: if(filp.f_dentry==NULL)
497: { printk(KERN_ERR "DMSDOS: file_mmap_nopage: no memory!\n");
498: return NULL;
499: }
500: filp.f_dentry->d_inode=inode;
501:
502: set_fs (KERNEL_DS);
503: LOG_FS("DMSDOS: file_mmap_nopage: calling file_read...\n");
504: cur_read = dblspace_file_read(&filp,
505: (char*)page_address(page),
506: need_read,&filp.f_pos);
507: LOG_FS("DMSDOS: file_mmap_nopage: file_read returned\n");
508: set_fs (cur_fs);
509: kfree(filp.f_dentry);
510: }
511: if (cur_read != need_read){
512: printk ("DMSDOS: Error while reading an mmap file %d <> %d\n"
513: ,cur_read,need_read);
514: }
515: }
516: if (clear > 0){
517: memset ((char*)page+PAGE_SIZE-clear,0,clear);
518: }
519: LOG_FS("DMSDOS: file_mmap_nopage: end\n");
520: return page;
521: }
522:
523: struct vm_operations_struct dblspace_file_mmap = {
524: NULL, /* open */
525: NULL, /* close */
526: NULL, /* unmap */
527: NULL, /* protect */
528: NULL, /* sync */
529: dblspace_file_mmap_nopage, /* nopage */
530: NULL, /* wppage */
531: NULL, /* swapout */
532: };
533:
534: /*
535: * This is used for a general mmap of a dmsdos file
536: * Returns 0 if ok, or a negative error code if not.
537: */
538: int dblspace_mmap(struct file*file,struct vm_area_struct*vma)
539: { struct inode *inode = file->f_dentry->d_inode;
540: LOG_FS("DMSDOS: mmap ino=%ld\n",inode->i_ino);
541: if (vma->vm_flags & VM_SHARED) /* only PAGE_COW or read-only supported now */
542: return -EINVAL;
543: /*
544: if (vma->vm_offset & (inode->i_sb->s_blocksize - 1))
545: return -EINVAL;
546: */
547: if (!inode->i_sb || !S_ISREG(inode->i_mode))
548: return -EACCES;
549: if (!IS_RDONLY(inode)) {
550: inode->i_atime = CURRENT_TIME;
551: /*inode->i_dirt = 1;*/
552: mark_inode_dirty(inode);
553: }
554:
555: vma->vm_file = file;
556: vma->vm_ops = &dblspace_file_mmap;
557: return 0;
558: }
559:
560: #endif /* from: else / ifdef DMSDOS_USE_READPAGE */
561:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.