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