1 /*
2 * linux/fs/ext/file.c
3 *
4 * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
5 *
6 * from
7 *
8 * linux/fs/minix/file.c
9 *
10 * Copyright (C) 1991, 1992 Linus Torvalds
11 *
12 * ext regular file handling primitives
13 */
14
15 #include <asm/segment.h>
16 #include <asm/system.h>
17
18 #include <linux/sched.h>
19 #include <linux/ext_fs.h>
20 #include <linux/kernel.h>
21 #include <linux/errno.h>
22 #include <linux/fcntl.h>
23 #include <linux/stat.h>
24 #include <linux/locks.h>
25
26 #define NBUF 32
27
28 #define MIN(a,b) (((a)<(b))?(a):(b))
29 #define MAX(a,b) (((a)>(b))?(a):(b))
30
31 #include <linux/fs.h>
32 #include <linux/ext_fs.h>
33
34 static int ext_file_read(struct inode *, struct file *, char *, int);
35 static int ext_file_write(struct inode *, struct file *, char *, int);
36
37 /*
38 * We have mostly NULL's here: the current defaults are ok for
39 * the ext filesystem.
40 */
41 static struct file_operations ext_file_operations = {
42 NULL, /* lseek - default */
43 ext_file_read, /* read */
44 ext_file_write, /* write */
45 NULL, /* readdir - bad */
46 NULL, /* select - default */
47 NULL, /* ioctl - default */
48 generic_mmap, /* mmap */
49 NULL, /* no special open is needed */
50 NULL, /* release */
51 ext_sync_file /* fsync */
52 };
53
54 struct inode_operations ext_file_inode_operations = {
55 &ext_file_operations, /* default file operations */
56 NULL, /* create */
57 NULL, /* lookup */
58 NULL, /* link */
59 NULL, /* unlink */
60 NULL, /* symlink */
61 NULL, /* mkdir */
62 NULL, /* rmdir */
63 NULL, /* mknod */
64 NULL, /* rename */
65 NULL, /* readlink */
66 NULL, /* follow_link */
67 ext_bmap, /* bmap */
68 ext_truncate, /* truncate */
69 NULL /* permission */
70 };
71
72 static int ext_file_read(struct inode * inode, struct file * filp, char * buf, int count)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
73 {
74 int read,left,chars;
75 int block, blocks, offset;
76 int bhrequest, uptodate;
77 struct buffer_head ** bhb, ** bhe;
78 struct buffer_head * bhreq[NBUF];
79 struct buffer_head * buflist[NBUF];
80 unsigned int size;
81
82 if (!inode) {
83 printk("ext_file_read: inode = NULL\n");
84 return -EINVAL;
85 }
86 if (!S_ISREG(inode->i_mode)) {
87 printk("ext_file_read: mode = %07o\n",inode->i_mode);
88 return -EINVAL;
89 }
90 offset = filp->f_pos;
91 size = inode->i_size;
92 if (offset > size)
93 left = 0;
94 else
95 left = size - offset;
96 if (left > count)
97 left = count;
98 if (left <= 0)
99 return 0;
100 read = 0;
101 block = offset >> BLOCK_SIZE_BITS;
102 offset &= BLOCK_SIZE-1;
103 size = (size + (BLOCK_SIZE-1)) >> BLOCK_SIZE_BITS;
104 blocks = (left + offset + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
105 bhb = bhe = buflist;
106 if (filp->f_reada) {
107 blocks += read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
108 if (block + blocks > size)
109 blocks = size - block;
110 }
111
112 /* We do this in a two stage process. We first try and request
113 as many blocks as we can, then we wait for the first one to
114 complete, and then we try and wrap up as many as are actually
115 done. This routine is rather generic, in that it can be used
116 in a filesystem by substituting the appropriate function in
117 for getblk.
118
119 This routine is optimized to make maximum use of the various
120 buffers and caches. */
121
122 do {
123 bhrequest = 0;
124 uptodate = 1;
125 while (blocks) {
126 --blocks;
127 *bhb = ext_getblk(inode, block++, 0);
128 if (*bhb && !(*bhb)->b_uptodate) {
129 uptodate = 0;
130 bhreq[bhrequest++] = *bhb;
131 }
132
133 if (++bhb == &buflist[NBUF])
134 bhb = buflist;
135
136 /* If the block we have on hand is uptodate, go ahead
137 and complete processing. */
138 if (uptodate)
139 break;
140 if (bhb == bhe)
141 break;
142 }
143
144 /* Now request them all */
145 if (bhrequest)
146 ll_rw_block(READ, bhrequest, bhreq);
147
148 do { /* Finish off all I/O that has actually completed */
149 if (*bhe) {
150 wait_on_buffer(*bhe);
151 if (!(*bhe)->b_uptodate) { /* read error? */
152 brelse(*bhe);
153 if (++bhe == &buflist[NBUF])
154 bhe = buflist;
155 left = 0;
156 break;
157 }
158 }
159 if (left < BLOCK_SIZE - offset)
160 chars = left;
161 else
162 chars = BLOCK_SIZE - offset;
163 filp->f_pos += chars;
164 left -= chars;
165 read += chars;
166 if (*bhe) {
167 memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
168 brelse(*bhe);
169 buf += chars;
170 } else {
171 while (chars-->0)
172 put_fs_byte(0,buf++);
173 }
174 offset = 0;
175 if (++bhe == &buflist[NBUF])
176 bhe = buflist;
177 } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
178 } while (left > 0);
179
180 /* Release the read-ahead blocks */
181 while (bhe != bhb) {
182 brelse(*bhe);
183 if (++bhe == &buflist[NBUF])
184 bhe = buflist;
185 };
186 if (!read)
187 return -EIO;
188 filp->f_reada = 1;
189 if (!IS_RDONLY(inode)) {
190 inode->i_atime = CURRENT_TIME;
191 inode->i_dirt = 1;
192 }
193 return read;
194 }
195
196 static int ext_file_write(struct inode * inode, struct file * filp, char * buf, int count)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
197 {
198 off_t pos;
199 int written,c;
200 struct buffer_head * bh;
201 char * p;
202
203 if (!inode) {
204 printk("ext_file_write: inode = NULL\n");
205 return -EINVAL;
206 }
207 if (!S_ISREG(inode->i_mode)) {
208 printk("ext_file_write: mode = %07o\n",inode->i_mode);
209 return -EINVAL;
210 }
211 /*
212 * ok, append may not work when many processes are writing at the same time
213 * but so what. That way leads to madness anyway.
214 */
215 if (filp->f_flags & O_APPEND)
216 pos = inode->i_size;
217 else
218 pos = filp->f_pos;
219 written = 0;
220 while (written<count) {
221 bh = ext_getblk(inode,pos/BLOCK_SIZE,1);
222 if (!bh) {
223 if (!written)
224 written = -ENOSPC;
225 break;
226 }
227 c = BLOCK_SIZE - (pos % BLOCK_SIZE);
228 if (c > count-written)
229 c = count-written;
230 if (c != BLOCK_SIZE && !bh->b_uptodate) {
231 ll_rw_block(READ, 1, &bh);
232 wait_on_buffer(bh);
233 if (!bh->b_uptodate) {
234 brelse(bh);
235 if (!written)
236 written = -EIO;
237 break;
238 }
239 }
240 p = (pos % BLOCK_SIZE) + bh->b_data;
241 pos += c;
242 if (pos > inode->i_size) {
243 inode->i_size = pos;
244 inode->i_dirt = 1;
245 }
246 written += c;
247 memcpy_fromfs(p,buf,c);
248 buf += c;
249 bh->b_uptodate = 1;
250 bh->b_dirt = 1;
251 brelse(bh);
252 }
253 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
254 filp->f_pos = pos;
255 inode->i_dirt = 1;
256 return written;
257 }