Import 2.1.81
[davej-history.git] / fs / fat / buffer.c
blob86b3a2f5a6df173e83b2c0580c37124b416b971b
1 /*
2 * linux/fs/fat/buffer.c
5 */
7 #include <linux/mm.h>
8 #include <linux/malloc.h>
9 #include <linux/string.h>
10 #include <linux/fs.h>
11 #include <linux/msdos_fs.h>
12 #include <linux/fat_cvf.h>
14 #if 0
15 # define PRINTK(x) printk x
16 #else
17 # define PRINTK(x)
18 #endif
20 struct buffer_head *fat_bread (
21 struct super_block *sb,
22 int block)
24 struct buffer_head *ret = NULL;
26 PRINTK(("fat_bread: block=0x%x\n", block));
28 * Note that the blocksize is 512, 1024 or 2048, but the first read
29 * is always of size 1024 (or 2048). Doing readahead may be
30 * counterproductive or just plain wrong.
33 if(MSDOS_SB(sb)->cvf_format &&
34 MSDOS_SB(sb)->cvf_format->cvf_bread)
35 return MSDOS_SB(sb)->cvf_format->cvf_bread(sb,block);
37 if (sb->s_blocksize == 512) {
38 ret = bread (sb->s_dev,block,512);
39 } else {
40 struct buffer_head *real;
41 if (sb->s_blocksize == 1024){
42 real = bread (sb->s_dev,block>>1,1024);
43 } else {
44 real = bread (sb->s_dev,block>>2,2048);
47 if (real != NULL){
48 ret = (struct buffer_head *)
49 kmalloc (sizeof(struct buffer_head), GFP_KERNEL);
50 if (ret != NULL) {
51 /* #Specification: msdos / strategy / special device / dummy blocks
52 * Many special device (Scsi optical disk for one) use
53 * larger hardware sector size. This allows for higher
54 * capacity.
56 * Most of the time, the MsDOS file system that sit
57 * on this device is totally unaligned. It use logically
58 * 512 bytes sector size, with logical sector starting
59 * in the middle of a hardware block. The bad news is
60 * that a hardware sector may hold data own by two
61 * different files. This means that the hardware sector
62 * must be read, patch and written almost all the time.
64 * Needless to say that it kills write performance
65 * on all OS.
67 * Internally the linux msdos fs is using 512 bytes
68 * logical sector. When accessing such a device, we
69 * allocate dummy buffer cache blocks, that we stuff
70 * with the information of a real one (1k large).
72 * This strategy is used to hide this difference to
73 * the core of the msdos fs. The slowdown is not
74 * hidden though!
77 * The memset is there only to catch errors. The msdos
78 * fs is only using b_data
80 memset (ret,0,sizeof(*ret));
81 ret->b_data = real->b_data;
82 if (sb->s_blocksize == 2048) {
83 if (block & 3) ret->b_data += (block & 3) << 9;
84 }else{
85 if (block & 1) ret->b_data += 512;
87 ret->b_next = real;
88 }else{
89 brelse (real);
93 return ret;
96 struct buffer_head *fat_getblk(struct super_block *sb, int block)
98 struct buffer_head *ret = NULL;
99 PRINTK(("fat_getblk: block=0x%x\n", block));
101 if (MSDOS_SB(sb)->cvf_format &&
102 MSDOS_SB(sb)->cvf_format->cvf_getblk)
103 return MSDOS_SB(sb)->cvf_format->cvf_getblk(sb,block);
105 if (sb->s_blocksize == 512){
106 ret = getblk (sb->s_dev,block,512);
107 } else {
109 * #Specification: msdos / special device / writing
110 * A write is always preceded by a read of the complete block
111 * (large hardware sector size). This defeat write performance.
112 * There is a possibility to optimize this when writing large
113 * chunk by making sure we are filling large block. Volunteer ?
115 ret = fat_bread (sb,block);
117 return ret;
120 void fat_brelse (
121 struct super_block *sb,
122 struct buffer_head *bh)
124 if (bh != NULL) {
125 if (MSDOS_SB(sb)->cvf_format &&
126 MSDOS_SB(sb)->cvf_format->cvf_brelse)
127 return MSDOS_SB(sb)->cvf_format->cvf_brelse(sb,bh);
129 if (sb->s_blocksize == 512){
130 brelse (bh);
131 }else{
132 brelse (bh->b_next);
133 /* We can free the dummy because a new one is allocated at
134 each fat_getblk() and fat_bread().
136 kfree (bh);
141 void fat_mark_buffer_dirty (
142 struct super_block *sb,
143 struct buffer_head *bh,
144 int dirty)
146 if (MSDOS_SB(sb)->cvf_format &&
147 MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty) {
148 MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty(sb,bh,dirty);
149 return;
152 if (sb->s_blocksize != 512){
153 bh = bh->b_next;
155 mark_buffer_dirty (bh,dirty);
158 void fat_set_uptodate (
159 struct super_block *sb,
160 struct buffer_head *bh,
161 int val)
163 if (MSDOS_SB(sb)->cvf_format &&
164 MSDOS_SB(sb)->cvf_format->cvf_set_uptodate) {
165 MSDOS_SB(sb)->cvf_format->cvf_set_uptodate(sb,bh,val);
166 return;
169 if (sb->s_blocksize != 512){
170 bh = bh->b_next;
172 mark_buffer_uptodate(bh, val);
174 int fat_is_uptodate (
175 struct super_block *sb,
176 struct buffer_head *bh)
178 if(MSDOS_SB(sb)->cvf_format &&
179 MSDOS_SB(sb)->cvf_format->cvf_is_uptodate)
180 return MSDOS_SB(sb)->cvf_format->cvf_is_uptodate(sb,bh);
182 if (sb->s_blocksize != 512){
183 bh = bh->b_next;
185 return buffer_uptodate(bh);
188 void fat_ll_rw_block (
189 struct super_block *sb,
190 int opr,
191 int nbreq,
192 struct buffer_head *bh[32])
194 if (MSDOS_SB(sb)->cvf_format &&
195 MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block) {
196 MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block(sb,opr,nbreq,bh);
197 return;
200 if (sb->s_blocksize == 512){
201 ll_rw_block(opr,nbreq,bh);
202 }else{
203 struct buffer_head *tmp[32];
204 int i;
205 for (i=0; i<nbreq; i++){
206 tmp[i] = bh[i]->b_next;
208 ll_rw_block(opr,nbreq,tmp);