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