OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [before_ORP/] [uclinux/] [uClinux-2.0.x/] [fs/] [sysv/] [file.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
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
#include <linux/kernel.h>
17
#include <linux/fs.h>
18
#include <linux/sysv_fs.h>
19
#include <linux/errno.h>
20
#include <linux/fcntl.h>
21
#include <linux/stat.h>
22
#include <linux/string.h>
23
#include <linux/locks.h>
24
#include <linux/pagemap.h>
25
 
26
#include <asm/segment.h>
27
 
28
#define NBUF    32
29
 
30
#define MIN(a,b) (((a)<(b))?(a):(b))
31
#define MAX(a,b) (((a)>(b))?(a):(b))
32
 
33
#include <linux/fs.h>
34
#include <linux/sysv_fs.h>
35
 
36
static int sysv_file_write(struct inode *, struct file *, const char *, int);
37
 
38
/*
39
 * We have mostly NULL's here: the current defaults are ok for
40
 * the coh filesystem.
41
 */
42
static struct file_operations sysv_file_operations = {
43
        NULL,                   /* lseek - default */
44
        sysv_file_read,         /* read */
45
        sysv_file_write,        /* write */
46
        NULL,                   /* readdir - bad */
47
        NULL,                   /* select - default */
48
        NULL,                   /* ioctl - default */
49
        generic_file_mmap,      /* mmap */
50
        NULL,                   /* no special open is needed */
51
        NULL,                   /* release */
52
        sysv_sync_file          /* fsync */
53
};
54
 
55
struct inode_operations sysv_file_inode_operations = {
56
        &sysv_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
        generic_readpage,       /* readpage */
69
        NULL,                   /* writepage */
70
        sysv_bmap,              /* bmap */
71
        sysv_truncate,          /* truncate */
72
        NULL                    /* permission */
73
};
74
 
75
int sysv_file_read(struct inode * inode, struct file * filp, char * buf, int count)
76
{
77
        struct super_block * sb = inode->i_sb;
78
        int read,left,chars;
79
        unsigned int block;
80
        int blocks, offset;
81
        int bhrequest, uptodate;
82
        struct buffer_head ** bhb, ** bhe;
83
        struct buffer_head * bhreq[NBUF];
84
        struct buffer_head * buflist[NBUF];
85
        unsigned int size;
86
 
87
        if (!inode) {
88
                printk("sysv_file_read: inode = NULL\n");
89
                return -EINVAL;
90
        }
91
        if (!S_ISREG(inode->i_mode)) {
92
                printk("sysv_file_read: mode = %07o\n",inode->i_mode);
93
                return -EINVAL;
94
        }
95
        offset = filp->f_pos;
96
        size = inode->i_size;
97
        if (offset > size)
98
                left = 0;
99
        else
100
                left = size - offset;
101
        if (left > count)
102
                left = count;
103
        if (left <= 0)
104
                return 0;
105
        read = 0;
106
        block = offset >> sb->sv_block_size_bits;
107
        offset &= sb->sv_block_size_1;
108
        size = (size + sb->sv_block_size_1) >> sb->sv_block_size_bits;
109
        blocks = (left + offset + sb->sv_block_size_1) >> sb->sv_block_size_bits;
110
        bhb = bhe = buflist;
111
        if (filp->f_reada) {
112
                blocks += read_ahead[MAJOR(inode->i_dev)] >> (sb->sv_block_size_bits - 9);
113
                if (block + blocks > size)
114
                        blocks = size - block;
115
        }
116
 
117
        /* We do this in a two stage process.  We first try to request
118
           as many blocks as we can, then we wait for the first one to
119
           complete, and then we try to wrap up as many as are actually
120
           done.  This routine is rather generic, in that it can be used
121
           in a filesystem by substituting the appropriate function in
122
           for getblk.
123
 
124
           This routine is optimized to make maximum use of the various
125
           buffers and caches.
126
         */
127
 
128
        do {
129
                bhrequest = 0;
130
                uptodate = 1;
131
                while (blocks) {
132
                        --blocks;
133
                        *bhb = sysv_getblk(inode, block++, 0);
134
                        if (*bhb && !buffer_uptodate(*bhb)) {
135
                                uptodate = 0;
136
                                bhreq[bhrequest++] = *bhb;
137
                        }
138
 
139
                        if (++bhb == &buflist[NBUF])
140
                                bhb = buflist;
141
 
142
                        /* If the block we have on hand is uptodate, go ahead
143
                           and complete processing. */
144
                        if (uptodate)
145
                                break;
146
                        if (bhb == bhe)
147
                                break;
148
                }
149
 
150
                /* Now request them all */
151
                if (bhrequest)
152
                        ll_rw_block(READ, bhrequest, bhreq);
153
 
154
                do { /* Finish off all I/O that has actually completed */
155
                        if (*bhe) {
156
                                wait_on_buffer(*bhe);
157
                                if (!buffer_uptodate(*bhe)) {   /* read error? */
158
                                        brelse(*bhe);
159
                                        if (++bhe == &buflist[NBUF])
160
                                                bhe = buflist;
161
                                        left = 0;
162
                                        break;
163
                                }
164
                        }
165
                        if (left < sb->sv_block_size - offset)
166
                                chars = left;
167
                        else
168
                                chars = sb->sv_block_size - offset;
169
                        filp->f_pos += chars;
170
                        left -= chars;
171
                        read += chars;
172
                        if (*bhe) {
173
                                memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
174
                                brelse(*bhe);
175
                                buf += chars;
176
                        } else {
177
                                while (chars-- > 0)
178
                                        put_user(0,buf++);
179
                        }
180
                        offset = 0;
181
                        if (++bhe == &buflist[NBUF])
182
                                bhe = buflist;
183
                } while (left > 0 && bhe != bhb && (!*bhe || !buffer_locked(*bhe)));
184
        } while (left > 0);
185
 
186
/* Release the read-ahead blocks */
187
        while (bhe != bhb) {
188
                brelse(*bhe);
189
                if (++bhe == &buflist[NBUF])
190
                        bhe = buflist;
191
        };
192
        if (!read)
193
                return -EIO;
194
        filp->f_reada = 1;
195
        if (!IS_RDONLY(inode)) {
196
                inode->i_atime = CURRENT_TIME;
197
                inode->i_dirt = 1;
198
        }
199
        return read;
200
}
201
 
202
static int sysv_file_write(struct inode * inode, struct file * filp, const char * buf, int count)
203
{
204
        struct super_block * sb = inode->i_sb;
205
        off_t pos;
206
        int written,c;
207
        struct buffer_head * bh;
208
        char * p;
209
 
210
        if (!inode) {
211
                printk("sysv_file_write: inode = NULL\n");
212
                return -EINVAL;
213
        }
214
        if (!S_ISREG(inode->i_mode)) {
215
                printk("sysv_file_write: mode = %07o\n",inode->i_mode);
216
                return -EINVAL;
217
        }
218
/*
219
 * ok, append may not work when many processes are writing at the same time
220
 * but so what. That way leads to madness anyway.
221
 * But we need to protect against simultaneous truncate as we may end up
222
 * writing our data into blocks that have meanwhile been incorporated into
223
 * the freelist, thereby trashing the freelist.
224
 */
225
        if (filp->f_flags & O_APPEND)
226
                pos = inode->i_size;
227
        else
228
                pos = filp->f_pos;
229
        written = 0;
230
        while (written<count) {
231
                bh = sysv_getblk (inode, pos >> sb->sv_block_size_bits, 1);
232
                if (!bh) {
233
                        if (!written)
234
                                written = -ENOSPC;
235
                        break;
236
                }
237
                c = sb->sv_block_size - (pos & sb->sv_block_size_1);
238
                if (c > count-written)
239
                        c = count-written;
240
                if (c != sb->sv_block_size && !buffer_uptodate(bh)) {
241
                        ll_rw_block(READ, 1, &bh);
242
                        wait_on_buffer(bh);
243
                        if (!buffer_uptodate(bh)) {
244
                                brelse(bh);
245
                                if (!written)
246
                                        written = -EIO;
247
                                break;
248
                        }
249
                }
250
                /* now either c==sb->sv_block_size or buffer_uptodate(bh) */
251
                p = (pos & sb->sv_block_size_1) + bh->b_data;
252
                memcpy_fromfs(p, buf, c);
253
                update_vm_cache(inode, pos, p, c);
254
                pos += c;
255
                if (pos > inode->i_size) {
256
                        inode->i_size = pos;
257
                        inode->i_dirt = 1;
258
                }
259
                written += c;
260
                buf += c;
261
                mark_buffer_uptodate(bh, 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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.