00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "fs.h"
00018 #include <minix/com.h>
00019 #include "buf.h"
00020 #include "file.h"
00021 #include "fproc.h"
00022 #include "super.h"
00023
00024 FORWARD _PROTOTYPE( void rm_lru, (struct buf *bp) );
00025 FORWARD _PROTOTYPE( int rw_block, (struct buf *, int) );
00026
00027
00028
00029
00030 PUBLIC struct buf *get_block(dev, block, only_search)
00031 register dev_t dev;
00032 register block_t block;
00033 int only_search;
00034 {
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 int b;
00051 register struct buf *bp, *prev_ptr;
00052
00053
00054
00055
00056
00057
00058 if (dev != NO_DEV) {
00059 b = (int) block & HASH_MASK;
00060 bp = buf_hash[b];
00061 while (bp != NIL_BUF) {
00062 if (bp->b_blocknr == block && bp->b_dev == dev) {
00063
00064 if (bp->b_count == 0) rm_lru(bp);
00065 bp->b_count++;
00066
00067 return(bp);
00068 } else {
00069
00070 bp = bp->b_hash;
00071 }
00072 }
00073 }
00074
00075
00076 if ((bp = front) == NIL_BUF) panic(__FILE__,"all buffers in use", NR_BUFS);
00077 rm_lru(bp);
00078
00079
00080 b = (int) bp->b_blocknr & HASH_MASK;
00081 prev_ptr = buf_hash[b];
00082 if (prev_ptr == bp) {
00083 buf_hash[b] = bp->b_hash;
00084 } else {
00085
00086 while (prev_ptr->b_hash != NIL_BUF)
00087 if (prev_ptr->b_hash == bp) {
00088 prev_ptr->b_hash = bp->b_hash;
00089 break;
00090 } else {
00091 prev_ptr = prev_ptr->b_hash;
00092 }
00093 }
00094
00095
00096
00097
00098 if (bp->b_dev != NO_DEV) {
00099 if (bp->b_dirt == DIRTY) flushall(bp->b_dev);
00100 #if ENABLE_CACHE2
00101 put_block2(bp);
00102 #endif
00103 }
00104
00105
00106 bp->b_dev = dev;
00107 bp->b_blocknr = block;
00108 bp->b_count++;
00109 b = (int) bp->b_blocknr & HASH_MASK;
00110 bp->b_hash = buf_hash[b];
00111 buf_hash[b] = bp;
00112
00113
00114 if (dev != NO_DEV) {
00115 #if ENABLE_CACHE2
00116 if (get_block2(bp, only_search)) ;
00117 else
00118 #endif
00119 if (only_search == PREFETCH) bp->b_dev = NO_DEV;
00120 else
00121 if (only_search == NORMAL) {
00122 rw_block(bp, READING);
00123 }
00124 }
00125 return(bp);
00126 }
00127
00128
00129
00130
00131 PUBLIC void put_block(bp, block_type)
00132 register struct buf *bp;
00133 int block_type;
00134 {
00135
00136
00137
00138
00139
00140
00141
00142
00143 if (bp == NIL_BUF) return;
00144
00145 bp->b_count--;
00146 if (bp->b_count != 0) return;
00147
00148 bufs_in_use--;
00149
00150
00151
00152
00153
00154
00155 if (bp->b_dev == DEV_RAM || (block_type & ONE_SHOT)) {
00156
00157
00158
00159 bp->b_prev = NIL_BUF;
00160 bp->b_next = front;
00161 if (front == NIL_BUF)
00162 rear = bp;
00163 else
00164 front->b_prev = bp;
00165 front = bp;
00166 } else {
00167
00168
00169
00170 bp->b_prev = rear;
00171 bp->b_next = NIL_BUF;
00172 if (rear == NIL_BUF)
00173 front = bp;
00174 else
00175 rear->b_next = bp;
00176 rear = bp;
00177 }
00178
00179
00180
00181
00182
00183 if ((block_type & WRITE_IMMED) && bp->b_dirt==DIRTY && bp->b_dev != NO_DEV) {
00184 rw_block(bp, WRITING);
00185 }
00186 }
00187
00188
00189
00190
00191 PUBLIC zone_t alloc_zone(dev, z)
00192 dev_t dev;
00193 zone_t z;
00194 {
00195
00196
00197 int major, minor;
00198 bit_t b, bit;
00199 struct super_block *sp;
00200
00201
00202
00203
00204
00205
00206
00207
00208 sp = get_super(dev);
00209
00210
00211 if (z == sp->s_firstdatazone) {
00212 bit = sp->s_zsearch;
00213 } else {
00214 bit = (bit_t) z - (sp->s_firstdatazone - 1);
00215 }
00216 b = alloc_bit(sp, ZMAP, bit);
00217 if (b == NO_BIT) {
00218 err_code = ENOSPC;
00219 major = (int) (sp->s_dev >> MAJOR) & BYTE;
00220 minor = (int) (sp->s_dev >> MINOR) & BYTE;
00221 printf("No space on %sdevice %d/%d\n",
00222 sp->s_dev == root_dev ? "root " : "", major, minor);
00223 return(NO_ZONE);
00224 }
00225 if (z == sp->s_firstdatazone) sp->s_zsearch = b;
00226 return(sp->s_firstdatazone - 1 + (zone_t) b);
00227 }
00228
00229
00230
00231
00232 PUBLIC void free_zone(dev, numb)
00233 dev_t dev;
00234 zone_t numb;
00235 {
00236
00237
00238 register struct super_block *sp;
00239 bit_t bit;
00240
00241
00242 sp = get_super(dev);
00243 if (numb < sp->s_firstdatazone || numb >= sp->s_zones) return;
00244 bit = (bit_t) (numb - (sp->s_firstdatazone - 1));
00245 free_bit(sp, ZMAP, bit);
00246 if (bit < sp->s_zsearch) sp->s_zsearch = bit;
00247 }
00248
00249
00250
00251
00252 PRIVATE int rw_block(bp, rw_flag)
00253 register struct buf *bp;
00254 int rw_flag;
00255 {
00256
00257
00258
00259
00260
00261
00262 int r, op;
00263 off_t pos;
00264 dev_t dev;
00265 int block_size;
00266
00267 block_size = get_block_size(bp->b_dev);
00268
00269 if ( (dev = bp->b_dev) != NO_DEV) {
00270 pos = (off_t) bp->b_blocknr * block_size;
00271 op = (rw_flag == READING ? DEV_READ : DEV_WRITE);
00272 r = dev_io(op, dev, FS_PROC_NR, bp->b_data, pos, block_size, 0);
00273 if (r != block_size) {
00274 if (r >= 0) r = END_OF_FILE;
00275 if (r != END_OF_FILE)
00276 printf("Unrecoverable disk error on device %d/%d, block %ld\n",
00277 (dev>>MAJOR)&BYTE, (dev>>MINOR)&BYTE, bp->b_blocknr);
00278 bp->b_dev = NO_DEV;
00279
00280
00281 if (rw_flag == READING) rdwt_err = r;
00282 }
00283 }
00284
00285 bp->b_dirt = CLEAN;
00286
00287 return OK;
00288 }
00289
00290
00291
00292
00293 PUBLIC void invalidate(device)
00294 dev_t device;
00295 {
00296
00297
00298 register struct buf *bp;
00299
00300 for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++)
00301 if (bp->b_dev == device) bp->b_dev = NO_DEV;
00302
00303 #if ENABLE_CACHE2
00304 invalidate2(device);
00305 #endif
00306 }
00307
00308
00309
00310
00311 PUBLIC void flushall(dev)
00312 dev_t dev;
00313 {
00314
00315
00316 register struct buf *bp;
00317 static struct buf *dirty[NR_BUFS];
00318 int ndirty;
00319
00320 for (bp = &buf[0], ndirty = 0; bp < &buf[NR_BUFS]; bp++)
00321 if (bp->b_dirt == DIRTY && bp->b_dev == dev) dirty[ndirty++] = bp;
00322 rw_scattered(dev, dirty, ndirty, WRITING);
00323 }
00324
00325
00326
00327
00328 PUBLIC void rw_scattered(dev, bufq, bufqsize, rw_flag)
00329 dev_t dev;
00330 struct buf **bufq;
00331 int bufqsize;
00332 int rw_flag;
00333 {
00334
00335
00336 register struct buf *bp;
00337 int gap;
00338 register int i;
00339 register iovec_t *iop;
00340 static iovec_t iovec[NR_IOREQS];
00341 int j, r;
00342 int block_size;
00343
00344 block_size = get_block_size(dev);
00345
00346
00347 gap = 1;
00348 do
00349 gap = 3 * gap + 1;
00350 while (gap <= bufqsize);
00351 while (gap != 1) {
00352 gap /= 3;
00353 for (j = gap; j < bufqsize; j++) {
00354 for (i = j - gap;
00355 i >= 0 && bufq[i]->b_blocknr > bufq[i + gap]->b_blocknr;
00356 i -= gap) {
00357 bp = bufq[i];
00358 bufq[i] = bufq[i + gap];
00359 bufq[i + gap] = bp;
00360 }
00361 }
00362 }
00363
00364
00365
00366
00367 while (bufqsize > 0) {
00368 for (j = 0, iop = iovec; j < NR_IOREQS && j < bufqsize; j++, iop++) {
00369 bp = bufq[j];
00370 if (bp->b_blocknr != bufq[0]->b_blocknr + j) break;
00371 iop->iov_addr = (vir_bytes) bp->b_data;
00372 iop->iov_size = block_size;
00373 }
00374 r = dev_io(rw_flag == WRITING ? DEV_SCATTER : DEV_GATHER,
00375 dev, FS_PROC_NR, iovec,
00376 (off_t) bufq[0]->b_blocknr * block_size, j, 0);
00377
00378
00379
00380
00381 for (i = 0, iop = iovec; i < j; i++, iop++) {
00382 bp = bufq[i];
00383 if (iop->iov_size != 0) {
00384
00385 if (r != OK && i == 0) {
00386 printf(
00387 "fs: I/O error on device %d/%d, block %lu\n",
00388 (dev>>MAJOR)&BYTE, (dev>>MINOR)&BYTE,
00389 bp->b_blocknr);
00390 bp->b_dev = NO_DEV;
00391 }
00392 break;
00393 }
00394 if (rw_flag == READING) {
00395 bp->b_dev = dev;
00396 put_block(bp, PARTIAL_DATA_BLOCK);
00397 } else {
00398 bp->b_dirt = CLEAN;
00399 }
00400 }
00401 bufq += i;
00402 bufqsize -= i;
00403 if (rw_flag == READING) {
00404
00405
00406
00407 while (bufqsize > 0) {
00408 put_block(*bufq++, PARTIAL_DATA_BLOCK);
00409 bufqsize--;
00410 }
00411 }
00412 if (rw_flag == WRITING && i == 0) {
00413
00414
00415
00416
00417
00418 break;
00419 }
00420 }
00421 }
00422
00423
00424
00425
00426 PRIVATE void rm_lru(bp)
00427 struct buf *bp;
00428 {
00429
00430 struct buf *next_ptr, *prev_ptr;
00431
00432 bufs_in_use++;
00433 next_ptr = bp->b_next;
00434 prev_ptr = bp->b_prev;
00435 if (prev_ptr != NIL_BUF)
00436 prev_ptr->b_next = next_ptr;
00437 else
00438 front = next_ptr;
00439
00440 if (next_ptr != NIL_BUF)
00441 next_ptr->b_prev = prev_ptr;
00442 else
00443 rear = prev_ptr;
00444 }