Subversion Repositories HelenOS

Rev

Rev 2404 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 2404 Rev 2435
1
/*
1
/*
2
 * Copyright (c) 1987,1997, Prentice Hall
2
 * Copyright (c) 1987,1997, Prentice Hall
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use of the MINIX operating system in source and
5
 * Redistribution and use of the MINIX operating system in source and
6
 * binary forms, with or without modification, are permitted provided
6
 * binary forms, with or without modification, are permitted provided
7
 * that the following conditions are met:
7
 * that the following conditions are met:
8
 
8
 
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 
11
 
12
 * - Redistributions in binary form must reproduce the above
12
 * - Redistributions in binary form must reproduce the above
13
 *   copyright notice, this list of conditions and the following
13
 *   copyright notice, this list of conditions and the following
14
 *   disclaimer in the documentation and/or other materials provided
14
 *   disclaimer in the documentation and/or other materials provided
15
 *   with the distribution.
15
 *   with the distribution.
16
 
16
 
17
 * - Neither the name of Prentice Hall nor the names of the software
17
 * - Neither the name of Prentice Hall nor the names of the software
18
 *   authors or contributors may be used to endorse or promote
18
 *   authors or contributors may be used to endorse or promote
19
 *   products derived from this software without specific prior
19
 *   products derived from this software without specific prior
20
 *   written permission.
20
 *   written permission.
21
 
21
 
22
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
22
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
23
 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23
 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26
 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
26
 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
27
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
31
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
32
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
32
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
33
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
 */
34
 */
35
 
35
 
-
 
36
/** @addtogroup FileSystemImpl
36
 
37
* @{
37
/* This file contains the heart of the mechanism used to read files.
-
 
38
 * Read requests are split up into chunks that do not cross block
-
 
39
 * boundaries. Each chunk is then processed in turn.
-
 
40
 */
38
*/
41
 
39
 
-
 
40
/**
42
/* Methods:
41
 * @file    read.c
43
 * do_read:    perform the READ system call
42
 * @brief   This file contains the heart of the mechanism used to read files.
44
 * read_map:   given an inode and file position, look up its zone number
43
 *        Read requests are split up into chunks that do not cross block
45
 * rd_indir:   read an entry in an indirect block
44
 *        boundaries. Each chunk is then processed in turn.
46
 */
45
 */
47
 
46
 
48
#include <stdio.h>
47
#include <stdio.h>
49
#include "fs.h"
48
#include "fs.h"
50
#include "block.h"
49
#include "block.h"
51
#include "file.h"
50
#include "file.h"
52
#include "fproc.h"
51
#include "fproc.h"
53
#include "inode.h"
52
#include "inode.h"
54
#include "super.h"
53
#include "super.h"
55
#include "param.h"
54
#include "param.h"
56
 
55
 
57
 
56
 
58
static int read_chunk(inode_t *rip, offset_t position,
57
static int read_chunk(inode_t *rip, offset_t position,
59
        unsigned off, int chunk, char *buff);
58
        unsigned off, int chunk, char *buff);
60
 
59
 
-
 
60
/**
-
 
61
 * Perform the READ system call
-
 
62
 */
61
int do_read()
63
int do_read()
62
{
64
{
63
   
65
   
64
    /* Perform read(fd, buffer, nbytes) call. */
66
    /* Perform read(fd, buffer, nbytes) call. */
65
   
67
   
66
    register inode_t *rip;
68
    register inode_t *rip;
67
    register filp_t *f;
69
    register filp_t *f;
68
    offset_t bytes_left, f_size, position;
70
    offset_t bytes_left, f_size, position;
69
    unsigned int off, cum_io;
71
    unsigned int off, cum_io;
70
    int oflags, r, chunk;
72
    int oflags, r, chunk;
71
    int regular;
73
    int regular;
72
    mode_t mode_word;
74
    mode_t mode_word;
73
    void *old_addr;
75
    void *old_addr;
74
   
76
   
75
 
77
 
76
    /* If the file descriptor is valid, get the inode, size and mode. */
78
    /* If the file descriptor is valid, get the inode, size and mode. */
77
    if (nbytes < 0)
79
    if (nbytes < 0)
78
        return FS_EINVAL;
80
        return FS_EINVAL;
79
 
81
 
80
    if ((f = get_filp(fd)) == NIL_FILP)
82
    if ((f = get_filp(fd)) == NIL_FILP)
81
        return err_code;
83
        return err_code;
82
 
84
 
83
    if (f->filp_mode == FILP_CLOSED)
85
    if (f->filp_mode == FILP_CLOSED)
84
        return FS_EIO;
86
        return FS_EIO;
85
     
87
     
86
    if (nbytes == 0)
88
    if (nbytes == 0)
87
        return 0;    
89
        return 0;    
88
     
90
     
89
    position = f->filp_pos;
91
    position = f->filp_pos;
90
    if (position > MAX_FILE_POS)
92
    if (position > MAX_FILE_POS)
91
        return FS_EINVAL;
93
        return FS_EINVAL;
92
 
94
 
93
    if (position + nbytes < position)
95
    if (position + nbytes < position)
94
        return FS_EINVAL;   /* unsigned overflow */
96
        return FS_EINVAL;   /* unsigned overflow */
95
     
97
     
96
    oflags = f->filp_flags;
98
    oflags = f->filp_flags;
97
    rip = f->filp_ino;
99
    rip = f->filp_ino;
98
    f_size = rip->i_size;
100
    f_size = rip->i_size;
99
    r = OK;  
101
    r = OK;  
100
    cum_io = 0;
102
    cum_io = 0;
101
    mode_word = rip->i_mode & I_TYPE;
103
    mode_word = rip->i_mode & I_TYPE;
102
    regular = (mode_word == I_REGULAR);
104
    regular = (mode_word == I_REGULAR);
103
    status = OK;                /* set to EIO if disk error occurs */
105
    status = OK;                /* set to EIO if disk error occurs */
104
   
106
   
105
    old_addr = fp->buffer; 
107
    old_addr = fp->buffer; 
106
   
108
   
107
    /* Split the transfer into chunks that don't span two blocks. */
109
    /* Split the transfer into chunks that don't span two blocks. */
108
    while (nbytes != 0) {
110
    while (nbytes != 0) {
109
        off = (unsigned int)(position % BLOCK_SIZE); /* offset in blk*/
111
        off = (unsigned int)(position % BLOCK_SIZE); /* offset in blk*/
110
        chunk = MIN(nbytes, BLOCK_SIZE - off);
112
        chunk = MIN(nbytes, BLOCK_SIZE - off);
111
        if (chunk < 0) {
113
        if (chunk < 0) {
112
            chunk = BLOCK_SIZE - off;
114
            chunk = BLOCK_SIZE - off;
113
        }
115
        }
114
       
116
       
115
        bytes_left = f_size - position;
117
        bytes_left = f_size - position;
116
 
118
 
117
        if (position >= f_size) {
119
        if (position >= f_size) {
118
            break;          /* we are beyond EOF */
120
            break;          /* we are beyond EOF */
119
        }
121
        }
120
        if (chunk > bytes_left)
122
        if (chunk > bytes_left)
121
            chunk = (int)bytes_left;
123
            chunk = (int)bytes_left;
122
       
124
       
123
 
125
 
124
        /* Read 'chunk' bytes. */
126
        /* Read 'chunk' bytes. */
125
        r = read_chunk(rip, position, off, chunk, fp->buffer);
127
        r = read_chunk(rip, position, off, chunk, fp->buffer);
126
   
128
   
127
        if (status < 0)
129
        if (status < 0)
128
            break;
130
            break;
129
   
131
   
130
        /* Update counters and pointers. */
132
        /* Update counters and pointers. */
131
        fp->buffer += chunk * sizeof(char);         /* user buffer address */
133
        fp->buffer += chunk * sizeof(char);         /* user buffer address */
132
           
134
           
133
        nbytes -= chunk;        /* bytes yet to be read */
135
        nbytes -= chunk;        /* bytes yet to be read */
134
        cum_io += chunk;        /* bytes read so far */
136
        cum_io += chunk;        /* bytes read so far */
135
            position += chunk;      /* position within the file */
137
            position += chunk;      /* position within the file */
136
       
138
       
137
    }
139
    }
138
   
140
   
139
    if (bytes_left <= 0 || nbytes == 0)
141
    if (bytes_left <= 0 || nbytes == 0)
140
        status = END_OF_FILE;
142
        status = END_OF_FILE;
141
 
143
 
142
    fp->buffer = old_addr;
144
    fp->buffer = old_addr;
143
   
145
   
144
    f->filp_pos = position;
146
    f->filp_pos = position;
145
    rip->i_seek = NO_SEEK;
147
    rip->i_seek = NO_SEEK;
146
   
148
   
147
    if (status != OK) {
149
    if (status != OK) {
148
        r = status;     /* check for disk error */
150
        r = status;     /* check for disk error */
149
    }
151
    }
150
    if (status == END_OF_FILE) {
152
    if (status == END_OF_FILE) {
151
        r = OK;
153
        r = OK;
152
    }
154
    }
153
    if (r == OK) {
155
    if (r == OK) {
154
        fp->fp_cum_io_partial = 0;
156
        fp->fp_cum_io_partial = 0;
155
        print_console("File was successfully read into buffer\n");
157
        print_console("File was successfully read into buffer\n");
156
 
158
 
157
            return cum_io;
159
            return cum_io;
158
    }
160
    }
159
    else {
161
    else {
160
        print_console("Some error occured during reading the file\n");
162
        print_console("Some error occured during reading the file\n");
161
        return r;
163
        return r;
162
    }
164
    }
163
}
165
}
164
   
166
 
-
 
167
/**
-
 
168
 * Given an inode and file position, look up its zone number
-
 
169
 */
165
static int read_chunk(register inode_t *rip, offset_t position, unsigned off,
170
static int read_chunk(register inode_t *rip, offset_t position, unsigned off,
166
    int chunk, char *buff)
171
    int chunk, char *buff)
167
{
172
{
168
   
173
   
169
    /*
174
    /*
170
     * rip: pointer to inode for file to be read
175
     * rip: pointer to inode for file to be read
171
     * position:    position within file to read or write
176
     * position:    position within file to read or write
172
     * off:     off within the current block
177
     * off:     off within the current block
173
     * chunk:   number of bytes to read or write
178
     * chunk:   number of bytes to read or write
174
     * buff:    virtual address of the user buffer
179
     * buff:    virtual address of the user buffer
175
     */
180
     */
176
 
181
 
177
    /* Read (part of) a block. */
182
    /* Read (part of) a block. */
178
   
183
   
179
    register block_t *bp;
184
    register block_t *bp;
180
    block_num_t b;
185
    block_num_t b;
181
   
186
   
182
    b = read_map(rip, position);
187
    b = read_map(rip, position);
183
     
188
     
184
    /* Reading from a nonexistent block.  Must read as all zeros.*/
189
    /* Reading from a nonexistent block.  Must read as all zeros.*/
185
    if (b == NO_BLOCK) {
190
    if (b == NO_BLOCK) {
186
         bp = get_zero_block();    /* get a zero block */  
191
         bp = get_zero_block();    /* get a zero block */  
187
    }
192
    }
188
    else {
193
    else {
189
        bp = get_block(b);
194
        bp = get_block(b);
190
    }
195
    }
191
 
196
 
192
    /* Copy a chunk from the block buffer to user space. */
197
    /* Copy a chunk from the block buffer to user space. */
193
    memcpy((void *)buff, (void *)(bp->b.b__data+off), chunk);
198
    memcpy((void *)buff, (void *)(bp->b.b__data+off), chunk);
194
     
199
     
195
    return OK;
200
    return OK;
196
}
201
}
197
   
202
 
-
 
203
/**
-
 
204
 * Read an entry in an indirect block
-
 
205
 */
198
block_num_t read_map(register inode_t *rip, offset_t position)
206
block_num_t read_map(register inode_t *rip, offset_t position)
199
{
207
{
200
   
208
   
201
    /* Given an inode and a position within the corresponding file, locate the
209
    /* Given an inode and a position within the corresponding file, locate the
202
     * block (not zone) number in which that position is to be found and return it.
210
     * block (not zone) number in which that position is to be found and return it.
203
     */
211
     */
204
   
212
   
205
    register block_t *bp;
213
    register block_t *bp;
206
    register zone_t z;
214
    register zone_t z;
207
    int scale, boff, dzones, nr_indirects, index, zind, ex;
215
    int scale, boff, dzones, nr_indirects, index, zind, ex;
208
    block_num_t b;
216
    block_num_t b;
209
    long excess, zone, block_pos;
217
    long excess, zone, block_pos;
210
     
218
     
211
    scale = rip->i_sp->s_log_zone_size;   /* for block-zone conversion */
219
    scale = rip->i_sp->s_log_zone_size;   /* for block-zone conversion */
212
    block_pos = position/BLOCK_SIZE;      /* relative blk # in file */
220
    block_pos = position/BLOCK_SIZE;      /* relative blk # in file */
213
    zone = block_pos >> scale;    /* position's zone */
221
    zone = block_pos >> scale;    /* position's zone */
214
    boff = (int) (block_pos - (zone << scale) ); /* relative blk # within zone */
222
    boff = (int) (block_pos - (zone << scale) ); /* relative blk # within zone */
215
    dzones = rip->i_ndzones;
223
    dzones = rip->i_ndzones;
216
    nr_indirects = rip->i_nindirs;
224
    nr_indirects = rip->i_nindirs;
217
   
225
   
218
    /* Is 'position' to be found in the inode itself? */
226
    /* Is 'position' to be found in the inode itself? */
219
    if (zone < dzones) {
227
    if (zone < dzones) {
220
        zind = (int)zone;      /* index should be an int */
228
        zind = (int)zone;      /* index should be an int */
221
        z = rip->i_zone[zind];
229
        z = rip->i_zone[zind];
222
        if (z == NO_ZONE)
230
        if (z == NO_ZONE)
223
           return NO_BLOCK;
231
           return NO_BLOCK;
224
        b = ((block_num_t) z << scale) + boff;
232
        b = ((block_num_t) z << scale) + boff;
225
        return b;
233
        return b;
226
    }
234
    }
227
   
235
   
228
    /* It is not in the inode, so it must be single or double indirect. */
236
    /* It is not in the inode, so it must be single or double indirect. */
229
    excess = zone - dzones;       /* first Vx_NR_DZONES don't count */
237
    excess = zone - dzones;       /* first Vx_NR_DZONES don't count */
230
   
238
   
231
    if (excess < nr_indirects) {
239
    if (excess < nr_indirects) {
232
    /* 'position' can be located via the single indirect block. */
240
    /* 'position' can be located via the single indirect block. */
233
    z = rip->i_zone[dzones];
241
    z = rip->i_zone[dzones];
234
    }
242
    }
235
    else {
243
    else {
236
    /* 'position' can be located via the double indirect block. */
244
    /* 'position' can be located via the double indirect block. */
237
        if ( (z = rip->i_zone[dzones+1]) == NO_ZONE)
245
        if ( (z = rip->i_zone[dzones+1]) == NO_ZONE)
238
            return NO_BLOCK;
246
            return NO_BLOCK;
239
 
247
 
240
        excess -= nr_indirects;         /* single indir doesn't count*/
248
        excess -= nr_indirects;         /* single indir doesn't count*/
241
        b = (block_num_t) z << scale;
249
        b = (block_num_t) z << scale;
242
        bp = get_block(b);              /* get double indirect block */
250
        bp = get_block(b);              /* get double indirect block */
243
        index = (int) (excess/nr_indirects);
251
        index = (int) (excess/nr_indirects);
244
        z = rd_indir(bp, index);        /* z= zone for single*/
252
        z = rd_indir(bp, index);        /* z= zone for single*/
245
        excess = excess % nr_indirects;     /* index into single ind blk */
253
        excess = excess % nr_indirects;     /* index into single ind blk */
246
    }
254
    }
247
   
255
   
248
    /* 'z' is zone num for single indirect block; 'excess' is index into it. */
256
    /* 'z' is zone num for single indirect block; 'excess' is index into it. */
249
    if (z == NO_ZONE)
257
    if (z == NO_ZONE)
250
        return NO_BLOCK;
258
        return NO_BLOCK;
251
 
259
 
252
    b = (block_num_t) z << scale;       /* b is blk # for single ind */
260
    b = (block_num_t) z << scale;       /* b is blk # for single ind */
253
    bp = get_block(b);              /* get single indirect block */
261
    bp = get_block(b);              /* get single indirect block */
254
    ex = (int) excess;          /* need an integer */
262
    ex = (int) excess;          /* need an integer */
255
    z = rd_indir(bp, ex);           /* get block pointed to */
263
    z = rd_indir(bp, ex);           /* get block pointed to */
256
     
264
     
257
    if (z == NO_ZONE)
265
    if (z == NO_ZONE)
258
        return NO_BLOCK;
266
        return NO_BLOCK;
259
 
267
 
260
    b = ((block_num_t) z << scale) + boff;
268
    b = ((block_num_t) z << scale) + boff;
261
 
269
 
262
    return b;
270
    return b;
263
}
271
}
264
   
272
   
-
 
273
/**
-
 
274
 *
-
 
275
 */
265
zone_t rd_indir(block_t *bp, int index)
276
zone_t rd_indir(block_t *bp, int index)
266
{
277
{
267
 
278
 
268
    super_block_t *sp;
279
    super_block_t *sp;
269
    zone_t zone;   
280
    zone_t zone;   
270
   
281
   
271
    sp = get_super();   /* need super block to find file sys type */
282
    sp = get_super();   /* need super block to find file sys type */
272
   
283
   
273
    /* read a zone from an indirect block */
284
    /* read a zone from an indirect block */
274
    if (sp->s_version == V1) {
285
    if (sp->s_version == V1) {
275
        zone = (zone_t)bp->b.b__v1_ind[index];
286
        zone = (zone_t)bp->b.b__v1_ind[index];
276
    }
287
    }
277
    else {
288
    else {
278
        zone = (zone_t)bp->b.b__v2_ind[index];
289
        zone = (zone_t)bp->b.b__v2_ind[index];
279
    }
290
    }
280
    if (zone != NO_ZONE && (zone < (zone_t)sp->s_firstdatazone || zone >= sp->s_zones)) {
291
    if (zone != NO_ZONE && (zone < (zone_t)sp->s_firstdatazone || zone >= sp->s_zones)) {
281
        print_console_int("Illegal zone number %d ", zone);
292
        print_console_int("Illegal zone number %d ", zone);
282
        print_console_int("in indirect block, index %d\n", index);
293
        print_console_int("in indirect block, index %d\n", index);
283
    }
294
    }
284
 
295
 
285
    return zone;
296
    return zone;
286
}
297
}
287
   
298
   
-
 
299
 
-
 
300
/**
-
 
301
 * }
-
 
302
 */
-
 
303
 
288
 
304