-
Notifications
You must be signed in to change notification settings - Fork 2
/
cmsfs24x.c
1542 lines (1322 loc) · 47.3 KB
/
cmsfs24x.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
*
* Name: cmsfsvfs.c (C program source)
* CMS FS VFS interface routines (Linux fs driver code)
* Date: 2000-Sep-14 (Thu)
*
* THIS IS FOR THE 2.4 KERNEL
*
* See also: cmsfsany.c (common) and cmsfsusa.c (utility)
*
* This source contains the routines and structures
* required when CMS FS is built as a driver.
* It interfaces between CMS FS' own structures,
* which read the CMS EDF format, and Linux VFS.
*
* Objectives: Mimic ISO, which is also read-only media
* Mimic MS-DOS, which has similar short names (8x3)
* and may require content conversion.
*
*/
#define __KERNEL__
#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fs.h>
#define CMSFS_NEED_TM
#include "cmsfs.h"
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/mm.h>
/* The following gives us lock_super() and unlock_super(). */
#include <linux/locks.h>
#include <linux/blkdev.h>
/* This gives us "user space" access, like copy_to_user(). */
#include <asm/uaccess.h>
/* #include <linux/mm.h> */
/* #include <linux/init.h> */
/* --------------------------------------------------------- CMSFS_ERROR
* Generally a printk() operation, not really perror() function.
*/
void cmsfs_error(unsigned char * string)
{
(void) printk("CMSFS: %s\n",string);
return;
}
/* --------------------------------------------------------- CMSFS_BREAD
* The "b" here means "block", not "buffer". Do not confuse this with
* Linux VFS bread() function. This is CMS FS "block read" function.
*/
int cmsfs_bread(struct CMSSUPER *vol,void *buf,int block,int blocksize)
{
struct buffer_head * bh;
struct super_block * sb;
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,"cmsfs_bread(0x%08X,0x%08X,%d,%d)",
vol,buf,block,blocksize);
cmsfs_error(cmsfs_ermsg);
#endif
/* for the moment, we only deal with physical blocks */
if (blocksize != vol->pbksz)
{
(void) sprintf(cmsfs_ermsg,
"cmsfs_bread(): logical bksize %d does not match physical bksize %d",
blocksize,vol->pbksz);
cmsfs_error(cmsfs_ermsg);
return -1;
}
/* We could maybe handle that case by breaking-up this call into
multiple bread() calls, but that'll be a later driver rev. */
/* ratio = vol->pbksz / blocksize; */
sb = (struct super_block *) vol->vfssuper;
/* announce and call the system-level bread() */
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,"cmsfs_bread(): system bread('%s',%d,%d)",
kdevname(sb->s_dev),block,blocksize);
cmsfs_error(cmsfs_ermsg);
#endif
bh = bread(sb->s_dev,block,blocksize);
/* bh = bread(sb->s_dev,block/ratio,vol->pbksz); */
if (bh == NULL)
{
cmsfs_error("cmsfs_bread(): system bread() failed");
return -1;
}
/* copy the data part, then release the VFS buffer */
(void) memmove(buf,bh->b_data,blocksize);
(void) brelse(bh);
return blocksize;
}
/* -------------------------------------------------------- CMSFS_MALLOC
* Wrapper around kmalloc() for the driver.
* There is a similar wrapper around user-mode malloc() for the util.
*/
void * cmsfs_malloc(int size)
{
return (void *) kmalloc(size, GFP_KERNEL);
}
/* ---------------------------------------------------------- CMSFS_FREE
* Wrapper around kfree() for the driver.
* There is a similar wrapper around user-mode free() for the util.
*/
void cmsfs_free(void * buffer)
{
kfree(buffer);
return;
}
/* -------------------------------------------------------- CMSFS_MKTIME
* It would be much MUCH better to use the mktime() function
* found in GLIBC, but I had trouble compiling in a way that would
* let me use it with kernel code. If someone knows how to use
* GLIBC's version of mktime() with kernel code, PLEASE TELL ME.
*/
time_t cmsfs_mktime(struct cmsfs_tm * source)
{
time_t result;
int year, mon, yoff;
/* start with nothing */
result = 0;
/* add days for each year */
yoff = source->tm_year + 1900;
for (year = 1970 ; year < yoff ; year++)
{
if ((year % 400) == 0) result += 366;
else if ((year % 100) == 0) result += 365;
else if ((year % 4) == 0) result += 366;
else result += 365;
}
/* add days for each month */
switch (source->tm_mon)
{
case 12: result += 31; /* never executed */
case 11: result += 30;
case 10: result += 31;
case 9: result += 30;
case 8: result += 31;
case 7: result += 31;
case 6: result += 30;
case 5: result += 31;
case 4: result += 30;
case 3: result += 31;
case 2: /* how many days in Feb for this year? */
if ((source->tm_year % 400) == 0) result += 29;
else if ((source->tm_year % 100) == 0) result += 28;
else if ((source->tm_year % 4) == 0) result += 29;
else result += 28;
case 1: result += 31;
}
/* add days for this month */
result += source->tm_mday - 1;
/* make days into hours, then add hours */
result = (result * 24) + source->tm_hour;
/* make hours into minutes, then add minutes */
result = (result * 60) + source->tm_min;
/* make minutes into seconds, then add seconds */
result = (result * 60) + source->tm_sec;
return result;
}
/* ================================================================== */
/* include the common code here */
#define isupper(c) (c >= 'A' && c <= 'Z')
#define tolower(c) (c + ('a' - 'A'))
#include "cmsfsany.c"
#ifdef CMSFS_HOST_ASCII
#include "aecs.c"
#endif
/* filesystem driver stuff follows ... */
/* ================================================================== */
/* I learned of this requirement from Neale's "cpint" code. */
char kernel_version [] = UTS_RELEASE;
static unsigned char cmsfsflb[4096];
/* ---------------------------------------------------- CMSFS_FILE_LSEEK
* CMS FS "lseek" function for VFS file. NEED TO IMPLEMENT.
*/
loff_t cmsfs_file_lseek(struct file * file, loff_t offset, int whence)
{
cmsfs_error("cmsfs_file_lseek() -- N/A");
return -1;
}
/* ----------------------------------------------------- CMSFS_FILE_READ
* CMS FS "read" function for VFS file.
* We prefer to work with inodes, so extract the inode
* from the file pointer, formally file->f_dentry->d_inode.
*/
ssize_t cmsfs_file_read(struct file * file,
char * buffer, size_t length, loff_t * offset)
{
struct CMSINODE * ci;
int rc;
/* what's happening here with f_pos?? */
/*
{ int q; q = file->f_pos; (void) sprintf(cmsfs_ermsg,
"cmsfs_file_read(): VFS ->f_pos %lu",q); }
cmsfs_error(cmsfs_ermsg);
{ int q; q = *offset; (void) sprintf(cmsfs_ermsg,
"cmsfs_file_read(): offset %lu",q); }
cmsfs_error(cmsfs_ermsg);
*/
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,"cmsfs_file_read(,,%lu,)",length);
cmsfs_error(cmsfs_ermsg);
#endif
/* dereference CMS inode pointer */
ci = file->f_dentry->d_inode->u.generic_ip;
if (ci->vfsinode != file->f_dentry->d_inode)
{
(void) sprintf(cmsfs_ermsg,
"cmsfs_file_read(): CMS struct for inode %lu is corrupted",
file->f_dentry->d_inode->i_ino);
cmsfs_error(cmsfs_ermsg);
return -1;
}
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,
"cmsfs_file_read(): inode %lu, file '%s'",
file->f_dentry->d_inode->i_ino,ci->name);
cmsfs_error(cmsfs_ermsg);
#endif
/* if translation hasn't been determined, figure it out */
cmsfs_map_EXT(ci);
/* default to text files for the time being */
if (ci->flags == 0x0000) ci->flags = CMSFSTXT;
/* allocate a record buffer, if needed */
if (ci->rdbuf2 == NULL)
ci->rdbuf2 = cmsfs_malloc(ci->lrecl+2);
if (ci->rdbuf2 == NULL)
ci->rdbuf2 = cmsfs_malloc(ci->lrecl+2);
if (ci->rdbuf2 == NULL)
{ cmsfs_error("cmsfs_file_read(): cannot allocate record buffer");
return -1; }
/* try reading the file */
rc = cmsfs_read(ci,ci->rdbuf2,length);
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,
"cmsfs_file_read(): cmsfs_read() returned %d for %d",rc,length);
cmsfs_error(cmsfs_ermsg);
#endif
if (rc < 0) return rc;
/* copy from kernel storage to user storage */
if (rc > 0) (void) copy_to_user(buffer,ci->rdbuf2,rc);
/* if (rc > 0) (void) memmove(buffer,ci->rdbuf2,rc); */
/* annoying inconsistency! not for inodes, but yes content? */
/* update file pointers */
*offset = *offset + rc;
/* one or the other, but not both! */
/* file->f_pos += rc; */
return rc; /* report how many bytes were read */
}
/* -------------------------------------------------- CMSFS_FILE_READDIR
* CMS FS "readdir" function for VFS directory.
* It took me a long time to figure out to code the right datatype
* for the fourth argument to filldir(). [sigh]
*/
int cmsfs_file_readdir(struct file * file,
void * dirent, filldir_t myfd)
{
struct CMSINODE *dirinode, *tmpinode;
int rc, i, j, k;
if (file->f_pos != 0) return 0;
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,
"cmsfs_file_readdir(0x%08X,0x%08X,0x%08X)",file,dirent,myfd);
cmsfs_error(cmsfs_ermsg);
#endif
tmpinode = cmsfs_malloc(sizeof(struct CMSINODE));
/* we should check for errors here! */
dirinode = file->f_dentry->d_inode->u.generic_ip;
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,
"cmsfs_file_readdir(): inode %lu %d files",
file->f_dentry->d_inode->i_ino,dirinode->items);
cmsfs_error(cmsfs_ermsg);
#endif
dirinode->rdpnt = 0;
file->f_pos = dirinode->rdpnt * dirinode->lrecl;
rc = myfd(dirent,".",1,file->f_pos,0,0);
/* (void) sprintf(cmsfs_ermsg,
"cmsfs_file_readdir(): filldir(,'.',,,0) returned %d",rc);
cmsfs_error(cmsfs_ermsg); */
dirinode->rdpnt += 1;
file->f_pos = dirinode->rdpnt * dirinode->lrecl;
rc = myfd(dirent,"..",2,file->f_pos,
file->f_dentry->d_parent->d_inode->i_ino,0);
/* (void) sprintf(cmsfs_ermsg,
"cmsfs_file_readdir(): filldir(,'..',,,1) returned %d",rc);
cmsfs_error(cmsfs_ermsg);
(void) sprintf(cmsfs_ermsg,
" filldir(,'..',,,%d) returned %d",
file->f_dentry->d_parent->d_inode->i_ino,rc);
cmsfs_error(cmsfs_ermsg); */
dirinode->rdpnt += 1;
file->f_pos = dirinode->rdpnt * dirinode->lrecl;
/* prime the loop with the first block of the directory */
/* starting at 128 gives the effect of skipping two FSTs */
j = 128; k = 0;
rc = cmsfsrd2(dirinode,cmsfsflb,k);
/* skipping .DIRECTOR and .ALLOCMAP, fill VFS dir with files */
for (i = 2 ; i < dirinode->items ; i++)
{
(void) cmsfs_map_FST(tmpinode,
(struct CMSFSFST *)&cmsfsflb[j]);
rc = myfd(dirent,tmpinode->name,
strlen(tmpinode->name),file->f_pos,i,0);
/* (void) sprintf(cmsfs_ermsg,
"cmsfs_file_readdir(): filldir(,'%s',,%d,%d) returned %d",
tmpinode->name,i*64,i,rc);
cmsfs_error(cmsfs_ermsg); */
/* if the filldir() call failed, get outta here */
if (rc != 0) break;
j += 64;
if (j >= dirinode->cmssuper->blksz)
{
k++;
rc = cmsfsrd2(dirinode,cmsfsflb,k);
j = 0;
}
dirinode->rdpnt += 1;
file->f_pos = dirinode->rdpnt * dirinode->lrecl;
}
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,
"cmsfs_file_readdir(): CMS rec pos %d",dirinode->rdpnt);
cmsfs_error(cmsfs_ermsg);
/* file->f_pos = dirinode->rdpnt * dirinode->lrecl; */
{ int q; q = file->f_pos; (void) sprintf(cmsfs_ermsg,
"cmsfs_file_readdir(): VFS ->f_pos %lu",q); }
cmsfs_error(cmsfs_ermsg);
(void) sprintf(cmsfs_ermsg,
"cmsfs_file_readdir(): stored %d",i);
cmsfs_error(cmsfs_ermsg);
#endif
cmsfs_free(tmpinode);
/* cmsfs_error("cmsfs_file_readdir(): finis!"); */
/* return i; */
return 0;
}
/* ---------------------------------------------------- CMSFS_FILE_IOCTL
* CMS FS "ioctl" function for VFS file. NEED TO IMPLEMENT.
*/
int cmsfs_file_ioctl(struct inode * inode, struct file * file,
unsigned int command, unsigned long argument)
{
cmsfs_error("cmsfs_file_ioctl() -- N/A");
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,
"cmsfs_file_ioctl(,,%u,%lu)",command,argument);
cmsfs_error(cmsfs_ermsg);
#endif
return -1;
}
/* ----------------------------------------------------- CMSFS_FILE_OPEN
* CMS FS "open" function for VFS file.
* This is just a check in this implementation.
*/
ssize_t cmsfs_file_open(struct inode * in, struct file * file)
{
struct CMSINODE * ci;
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,
"cmsfs_file_open(0x%08X,0x%08X)",in,file);
cmsfs_error(cmsfs_ermsg);
#endif
/* dereference CMS inode pointer and check cross-link */
ci = in->u.generic_ip;
if (ci == NULL)
{
(void) sprintf(cmsfs_ermsg,
"cmsfs_open(): NULL CMS struct pointer for inode %lu",
in->i_ino);
cmsfs_error(cmsfs_ermsg);
}
if (ci->vfsinode != in)
{
(void) sprintf(cmsfs_ermsg,
"cmsfs_open(): corrupted CMS struct for inode %lu",
in->i_ino);
cmsfs_error(cmsfs_ermsg);
return -1;
}
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,
"cmsfs_file_open(): opening file '%s' inode %lu",
ci->name,in->i_ino);
cmsfs_error(cmsfs_ermsg);
#endif
/* reset CMS and VFS pointers */
ci->rdpnt = ci->rdblk = ci->rdoff = 0;
file->f_pos = 0;
return 0;
}
/* ------------------------------------------------------------------ */
static
struct file_operations cmsfs_file_operations = {
llseek: cmsfs_file_lseek, /* N/A */
read: cmsfs_file_read,
readdir: cmsfs_file_readdir,
/* write: cmsfs_file_write, ** N/A */
ioctl: cmsfs_file_ioctl, /* N/A */
/* mmap: generic_file_mmap, ** N/A */
open: cmsfs_file_open,
/* release: cmsfs_release_file, ** N/A */
/* fsync: cmsfs_sync_file, ** N/A */
};
/* -------------------------------------------------- CMSFS_INODE_LOOKUP
* Search for the file in the CMS directory.
* Calls: cmsfs_lookup() to find the file,
* iget() to get a VFS inode for the file, if found,
* d_add() to add that inode to the VFS directory.
*/
struct dentry *cmsfs_inode_lookup(
struct inode * in, struct dentry *de)
{
struct CMSINODE * cmsinode;
struct inode * inode;
int n;
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,"cmsfs_inode_lookup(0x%08X,0x%08X)",in,de);
cmsfs_error(cmsfs_ermsg);
(void) sprintf(cmsfs_ermsg,
"cmsfs_inode_lookup(): dir inode, %lu filename '%s'",
de->d_inode,de->d_name.name);
cmsfs_error(cmsfs_ermsg);
#endif
/*
* On CMS minidisks, the directory entries (FST) serve as inodes.
* Here we allocate one in doing the search, and then free it.
* Not elegant, but works, and interfaces properly with VFS.
*/
cmsinode = cmsfs_lookup((CMSINODE*) in->u.generic_ip,
(unsigned char *) de->d_name.name);
if (cmsinode == NULL) return NULL;
/* it would be nice to be able to hand-off the CMS inode struct *
* rather than going through another allocation from iget(). */
n = cmsinode->index;
cmsinode->cmssuper->inuse -= 1;
cmsfs_free(cmsinode);
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,
"cmsfs_inode_lookup(): found inode %d",n);
cmsfs_error(cmsfs_ermsg);
#endif
/* iget() will allocate a VFS inode. *
* it will also call cmsfs_read_inode(), *
* thus re-allocating the CMS inode struct. */
inode = iget(in->i_sb,n);
if (inode == NULL) return NULL;
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,
"cmsfs_inode_lookup(): iget() supplied inode 0x%08X",inode);
cmsfs_error(cmsfs_ermsg);
#endif
d_add(de,inode);
/* cmsfs_error("cmsfs_inode_lookup(): finis!"); */
return NULL;
}
/* ---------------------------------------------- CMSFS_INODE_PERMISSION
* CMS FS "permission" function for VFS inode.
* This is really only useful for filesystems with ACL support.
* Return non-zero if you want access to be denied to this inode.
*/
int cmsfs_inode_permission(struct inode * in, int mask)
{
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,
"cmsfs_inode_permission(0x%08X,0%05o)",in,mask);
cmsfs_error(cmsfs_ermsg);
(void) sprintf(cmsfs_ermsg,
"cmsfs_inode_permission(): inode %lu mode 0%05o",
in->i_ino,in->i_mode);
cmsfs_error(cmsfs_ermsg);
#endif
return 0;
}
/* ------------------------------------------------------------------ */
static
struct inode_operations cmsfs_inode_operations = {
lookup: cmsfs_inode_lookup,
};
/* ------------------------------------------------------ CMSFS_READPAGE
* CMS FS "readpage" function for VFS file.
* We need readpage() so we can put embed other FS on a CMS disk.
* That is, we need this function so that we can hold an EXT2 FS
* in CMS space and mount that with "-o loop".
*
* I looked at the sources to other FS drivers until I was cross-eyed.
* The I got the following contribution from Leland Lucius.
* The following function is entirely his logic. There may be
* minor code chages on my part for obscure reasons. Thanks, Leland!
*/
static
int cmsfs_readpage(struct file *fi, struct page *pg)
{
struct CMSINODE *ci;
unsigned long offset;
unsigned long needlen;
unsigned long blksz;
unsigned long rdblk;
unsigned long len;
void *buf;
char *ptr;
int result = -EIO;
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,
"cmsfs_readpage(0x%08X,0x%08X)",fi,pg);
cmsfs_error(cmsfs_ermsg);
#endif
ci = fi->f_dentry->d_inode->u.generic_ip;
if( ci->vfsinode != fi->f_dentry->d_inode )
{
sprintf( cmsfs_ermsg,
"cmsfs_readpage(): CMS struct for inode %lu is corrupted",
fi->f_dentry->d_inode->i_ino );
cmsfs_error( cmsfs_ermsg );
return result;
}
if( ci->recfm[ 0 ] != 'F' )
{
sprintf( cmsfs_ermsg,
"cmsfs_readpage(): Record format not fixed" );
cmsfs_error( cmsfs_ermsg );
return result;
}
if( ci->rdbuf == NULL )
{
ci->rdbuf = cmsfs_malloc( ci->cmssuper->blksz );
if( ci->rdbuf == NULL )
{
cmsfs_error( "cmsfs_readpage(): unable to allocate a work buffer");
return result;
}
}
#if CMSFS_DEBUG
sprintf( cmsfs_ermsg,
"cmsfs_readpage(): inode %lu, file '%s'",
fi->f_dentry->d_inode->i_ino,ci->name );
cmsfs_error( cmsfs_ermsg );
#endif
page_cache_get( pg );
buf = kmap( pg );
if( buf )
{
offset = pg->index << PAGE_CACHE_SHIFT;
if( offset < ci->bytes )
{
blksz = ci->cmssuper->blksz;
rdblk = offset / blksz;
ptr = buf;
needlen = PAGE_SIZE;
while( needlen > 0 )
{
if( cmsfsrd2( ci, ci->rdbuf, rdblk ) != blksz )
{
cmsfs_error( "cmsfs_read(): could not read block" );
break;
}
len = min_t( unsigned long, needlen, blksz );
memcpy( ptr, ci->rdbuf, len );
ptr += len;
needlen -= len;
rdblk++;
}
if( needlen == 0 )
{
SetPageUptodate( pg );
result = 0;
}
}
if( result )
{
memset( buf, 0, PAGE_SIZE );
SetPageError( pg );
}
flush_dcache_page( pg );
UnlockPage( pg );
kunmap( pg );
}
page_cache_release( pg );
return result;
}
/* ------------------------------------------------------------------ */
static
struct address_space_operations cmsfs_as_operations = {
readpage: cmsfs_readpage,
/* bmap: cmsfs_as_bmap,
direct_IO: cmsfs_as_direct_IO, */
/* a possible simplification trick
readpage: blkdev_readpage,
*/
};
/* ---------------------------------------------------- CMSFS_READ_INODE
* CMS FS inode numbers are base-zero index into the CMS directory.
* CMS FS (EDF) is flat, no sub-directories, so there is only
* one such directory into which we index, always the "root".
* If the inode we are reading is zero, we mark it as the directory.
* The CMS superblock struct must have already been allocated,
* although CMS inode structs will usually be allocated here.
*/
void cmsfs_read_inode(struct inode * in)
{
struct CMSINODE *cmsinode;
struct CMSSUPER *cmssuper;
int rc, ct;
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,"cmsfs_read_inode(0x%08X)",in);
cmsfs_error(cmsfs_ermsg);
(void) sprintf(cmsfs_ermsg,
"cmsfs_read_inode(): reading inode %lu from dev '%s' sb 0x%08X",
in->i_ino,kdevname(in->i_dev),in->i_sb);
cmsfs_error(cmsfs_ermsg);
#endif
/* dummy values in case any of this fails */
in->i_uid = 0; in->i_gid = 0;
in->i_mode = 0; in->i_nlink = 0; in->i_size = 0;
in->i_atime = in->i_mtime = in->i_ctime = 0;
in->i_blksize = 0;
/* dereference pointer to CMS superblock from VFS superblock */
cmssuper = (CMSSUPER *) in->i_sb->u.generic_sbp;
/* and check it ... */
if (cmssuper == NULL)
{ cmsfs_error("cmsfs_read_inode(): no CMS superblock");
return; }
if (cmssuper->vfssuper != in->i_sb)
{ cmsfs_error("cmsfs_read_inode(): corrupted CMS superblock");
return; }
/* allocate a CMS inode struct */
if (in->u.generic_ip == NULL)
{
if (in->i_ino == 0 && cmssuper->cmsrooti != NULL)
{
#ifdef CMSFS_DEBUG
cmsfs_error(
"cmsfs_read_inode(): using CMS directory inode (prev alloc)");
#endif
cmsinode = cmssuper->cmsrooti;
/* and check it */
if (cmsinode->cmssuper != cmssuper) { cmsfs_error(
"cmsfs_read_inode(): corrupted CMS directory inode");
return; }
ct = 0;
}
else
{
#ifdef CMSFS_DEBUG
cmsfs_error(
"cmsfs_read_inode(): allocating a CMS inode struct");
#endif
cmsinode = cmsfs_malloc(sizeof(struct CMSINODE));
if (cmsinode != NULL) cmsinode->cmssuper = NULL;
ct = 1;
}
}
if (cmsinode == NULL)
{
cmsfs_error(
"cmsfs_read_inode(): error allocating CMS inode structure");
return;
}
/* cross-link CMS and VFS inode structures */
cmsinode->vfsinode = in;
in->u.generic_ip = cmsinode;
#ifdef CMSFS_DEBUG
cmsfs_error(
"cmsfs_read_inode(): VFS and CMS inodes allocated and linked");
#endif
/* Non-NULL CMS superblock pointer implies that we have *
* already mapped the CMS inode. A CMS superblock is *
* required for the cmsfs_map_FST() call to work. */
if (cmsinode->cmssuper == NULL)
{
cmsinode->cmssuper = cmssuper;
/* read the CMS "inode" (FST entry) indexed by in->i_ino , *
* map it to the newly allocated CMS inode struct, *
* and copy relevent content to the supplied VFS inode struct */
/* RECHECK THIS LOGIC for block calc against different blocksizes */
/*
(void) sprintf(cmsfs_ermsg,"... reading block %d",
((in->i_ino)*64)/(in->i_sb->s_blocksize));
cmsfs_error(cmsfs_ermsg);
*/
rc = cmsfsrd2(cmssuper->cmsrooti,cmsfsflb,
((in->i_ino)*64)/(in->i_sb->s_blocksize));
/*
(void) sprintf(cmsfs_ermsg,
"cmsfs_read_inode(): cmsfsrd2() returned %d",rc);
cmsfs_error(cmsfs_ermsg);
(void) sprintf(cmsfs_ermsg,"... FST offset %d",
(in->i_ino%(in->i_sb->s_blocksize/64))*64);
cmsfs_error(cmsfs_ermsg);
*/
(void) cmsfs_map_FST(cmsinode,(struct CMSFSFST *)
&cmsfsflb[(in->i_ino%(in->i_sb->s_blocksize/64))*64]);
}
/* create VFS inode from CMS inode */
in->i_mode = S_IRUGO; /* set "r--r--r--" perms */
in->i_nlink = 1;
in->i_uid = 0; in->i_gid = 0;
/* let the inode inherit some things from the superblock */
in->i_rdev = in->i_dev;
/* because i_dev gets set by new_inode() */
/* how big is this file? */
in->i_size = cmsfs_bytes(cmsinode);
/* CMS files have only one time stamp */
in->i_atime = in->i_mtime = in->i_ctime = cmsinode->ctime;
/* what about i_blkbits? that gets set by new_inode() */
/* CMS file blocksize is by definition filesystem blocksize */
in->i_blksize = cmsinode->cmssuper->blksz;
/* may not be accurate for total */
in->i_blocks = cmsinode->bloks;
in->i_version = 0; /* not sure about this */
in->i_attr_flags = 0;
in->i_state = 0;
in->i_flags = 0;
in->i_generation = 0;
/* in->i_writecount = 0; */
/* now point to our custom inode_operations struct */
in->i_op = &cmsfs_inode_operations;
/* CMS FS uses the same i_op struct for files and the directory */
/* now point to our custom file_operations struct */
in->i_fop = &cmsfs_file_operations;
/* CMS FS uses same i_fop struct for files and the directory */
/* is this a directory?? */
if (in->i_ino == 0)
{
in->i_mode |= S_IFDIR; /* mark it as a directory */
/* CMS directory was created when the filesystem was made */
in->i_ctime = cmssuper->ctime;
#ifdef CMSFS_DEBUG
cmsfs_error(
"cmsfs_read_inode(): inode zero (root) marked as directory");
#endif
in->i_nlink += 1;
in->i_mode |= S_IXUGO; /* add "--x--x--x" perms */
}
/* we know that inode zero is the CMS directory */
else in->i_mode |= S_IFREG; /* mark it as a regular file */
/* Address Space operations (to support loopback ioctl) */
in->i_data.a_ops = &cmsfs_as_operations;
/* increment the "in use" counter */
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,
"cmsfs_read_inode(): CMS superblock usage was %d",
cmssuper->inuse);
cmsfs_error(cmsfs_ermsg);
#endif
cmssuper->inuse += ct;
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,
"cmsfs_read_inode(): CMS superblock usage now %d",
cmssuper->inuse);
cmsfs_error(cmsfs_ermsg);
#endif
return;
}
/* --------------------------------------------------- CMSFS_CLEAR_SUPER
* Clears the cross-links and frees the CMS superblock struct.
* Cannot lock/unlock the superblock at this stage of the game.
*/
void cmsfs_clear_super(struct super_block * sb)
{
CMSSUPER *cmssuper;
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,"cmsfs_clear_super(0x%08X)",sb);
cmsfs_error(cmsfs_ermsg);
#endif
/* dereference the CMS superblock pointer and check */
cmssuper = sb->u.generic_sbp;
/* if we've already been here, then silently return */
if (cmssuper == NULL) return;
/* sanity check, cross-reference CMS and VFS superblocks */
if (cmssuper->vfssuper != sb)
{
(void) sprintf(cmsfs_ermsg,
"cmsfs_clear_super(): CMS superblock at 0x%08X is corrupted",
cmssuper);
cmsfs_error(cmsfs_ermsg);
return;
}
/* if superblock is still busy, then bail */
if (cmssuper->inuse != 0)
{
(void) sprintf(cmsfs_ermsg,
"cmsfs_clear_super(): CMS superblock at 0x%08X is busy",
cmssuper);
cmsfs_error(cmsfs_ermsg);
return;
}
/* free the CMSSUPER struct and mark it freed */
/* lock_super(sb); */
cmssuper->vfssuper = NULL;
cmsfs_free(cmssuper); /* deref'd from sb->u.generic_sbp */
sb->u.generic_sbp = NULL;
/* unlock_super(sb); */
/* one less instance of this driver */
MOD_DEC_USE_COUNT;
/* don't do this until all storage is freed */
return;
}
/* --------------------------------------------------- CMSFS_CLEAR_INODE
* Cleanly deallocate the CMS inode linked to this VFS inode.
* Because of the order in which VFS objects are released at umount(),
* this function must also clear the CMS superblock
* if the inode being cleared is the CMS directory.
*/
void cmsfs_clear_inode(struct inode * in)
{
struct CMSINODE * ck;
struct CMSSUPER * cs;
struct super_block * sb;
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,"cmsfs_clear_inode(0x%08X)",in);
cmsfs_error(cmsfs_ermsg);
(void) sprintf(cmsfs_ermsg,
"cmsfs_clear_inode(): clearing inode number %lu",in->i_ino);
cmsfs_error(cmsfs_ermsg);
#endif
/* dereference the generic pointer to a CMS struct */
ck = in->u.generic_ip;
/* if no CMS inode to free, then silently return */
if (ck == NULL) return;
/* if ->vfsinode doesn't point back to VFS inode, then error */
if (ck->vfsinode != in)
{
cmsfs_error("cmsfs_clear_inode(): error in CMS inode ref");
(void) sprintf(cmsfs_ermsg,
"cmsfs_clear_inode(): CMS links to 0x%08X",ck->vfsinode);
cmsfs_error(cmsfs_ermsg);
return;
}
/* dereference VFS and CMS superblock pointers for shorthand */
sb = in->i_sb; cs = ck->cmssuper;
/* sanity check those, expecting them to be cross-linked */
if (sb->u.generic_sbp != cs)
{ cmsfs_error(
"cmsfs_clear_inode(): VFS SB ref to CMS SB is corrupted");
return; }
if (cs->vfssuper != sb)
{ cmsfs_error(
"cmsfs_clear_inode(): CMS SB ref to VFS SB is corrupted");
return; }
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,
"cmsfs_clear_inode(): CMS superblock usage was %d",cs->inuse);
cmsfs_error(cmsfs_ermsg);
#endif
/* decrement the "in use" counter */
cs->inuse -= 1;
#ifdef CMSFS_DEBUG
(void) sprintf(cmsfs_ermsg,
"cmsfs_clear_inode(): CMS superblock usage now %d",cs->inuse);
cmsfs_error(cmsfs_ermsg);
#endif
if (ck->rdbuf != NULL)
{
#ifdef CMSFS_DEBUG
cmsfs_error("cmsfs_clear_inode(): freeing read buffer");