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 <minix/u64.h>
00020 #include <string.h>
00021 #include "buf.h"
00022 #include "super.h"
00023 #include "inode.h"
00024
00025 FORWARD _PROTOTYPE( void rm_lru, (struct buf *bp) );
00026 FORWARD _PROTOTYPE( int rw_block, (struct buf *, int) );
00027
00028
00029
00030
00031 PUBLIC struct buf *get_block(dev, block, only_search)
00032 register dev_t dev;
00033 register block_t block;
00034 int only_search;
00035 {
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 int b;
00052 static struct buf *bp, *prev_ptr;
00053
00054 ASSERT(fs_block_size > 0);
00055
00056
00057
00058
00059
00060
00061 if (dev != NO_DEV) {
00062 b = BUFHASH(block);
00063 bp = buf_hash[b];
00064 while (bp != NIL_BUF) {
00065 if (bp->b_blocknr == block && bp->b_dev == dev) {
00066
00067 if (bp->b_count == 0) rm_lru(bp);
00068 bp->b_count++;
00069 ASSERT(bp->b_bytes == fs_block_size);
00070 ASSERT(bp->b_dev == dev);
00071 ASSERT(bp->b_dev != NO_DEV);
00072 ASSERT(bp->bp);
00073 return(bp);
00074 } else {
00075
00076 bp = bp->b_hash;
00077 }
00078 }
00079 }
00080
00081
00082 if ((bp = front) == NIL_BUF) panic(__FILE__,"all buffers in use", NR_BUFS);
00083
00084 if(bp->b_bytes < fs_block_size) {
00085 ASSERT(!bp->bp);
00086 ASSERT(bp->b_bytes == 0);
00087 if(!(bp->bp = alloc_contig(fs_block_size, 0, NULL))) {
00088 printf("MFS: couldn't allocate a new block.\n");
00089 for(bp = front;
00090 bp && bp->b_bytes < fs_block_size; bp = bp->b_next)
00091 ;
00092 if(!bp) {
00093 panic("MFS", "no buffer available", NO_NUM);
00094 }
00095 } else {
00096 bp->b_bytes = fs_block_size;
00097 }
00098 }
00099
00100 ASSERT(bp);
00101 ASSERT(bp->bp);
00102 ASSERT(bp->b_bytes == fs_block_size);
00103 ASSERT(bp->b_count == 0);
00104
00105 rm_lru(bp);
00106
00107
00108 b = BUFHASH(bp->b_blocknr);
00109 prev_ptr = buf_hash[b];
00110 if (prev_ptr == bp) {
00111 buf_hash[b] = bp->b_hash;
00112 } else {
00113
00114 while (prev_ptr->b_hash != NIL_BUF)
00115 if (prev_ptr->b_hash == bp) {
00116 prev_ptr->b_hash = bp->b_hash;
00117 break;
00118 } else {
00119 prev_ptr = prev_ptr->b_hash;
00120 }
00121 }
00122
00123
00124
00125
00126 if (bp->b_dev != NO_DEV) {
00127 if (bp->b_dirt == DIRTY) flushall(bp->b_dev);
00128 }
00129
00130
00131 bp->b_dev = dev;
00132 bp->b_blocknr = block;
00133 bp->b_count++;
00134 b = BUFHASH(bp->b_blocknr);
00135 bp->b_hash = buf_hash[b];
00136
00137 buf_hash[b] = bp;
00138
00139
00140 if (dev != NO_DEV) {
00141 if (only_search == PREFETCH) bp->b_dev = NO_DEV;
00142 else
00143 if (only_search == NORMAL) {
00144 rw_block(bp, READING);
00145 }
00146 }
00147
00148 ASSERT(bp->bp);
00149
00150 return(bp);
00151 }
00152
00153
00154
00155
00156 PUBLIC void put_block(bp, block_type)
00157 register struct buf *bp;
00158 int block_type;
00159 {
00160
00161
00162
00163
00164
00165
00166
00167
00168 if (bp == NIL_BUF) return;
00169
00170 bp->b_count--;
00171 if (bp->b_count != 0) return;
00172
00173 bufs_in_use--;
00174
00175
00176
00177
00178
00179
00180 if (bp->b_dev == DEV_RAM || (block_type & ONE_SHOT)) {
00181
00182
00183
00184 bp->b_prev = NIL_BUF;
00185 bp->b_next = front;
00186 if (front == NIL_BUF)
00187 rear = bp;
00188 else
00189 front->b_prev = bp;
00190 front = bp;
00191 }
00192 else {
00193
00194
00195
00196 bp->b_prev = rear;
00197 bp->b_next = NIL_BUF;
00198 if (rear == NIL_BUF)
00199 front = bp;
00200 else
00201 rear->b_next = bp;
00202 rear = bp;
00203 }
00204
00205
00206
00207
00208
00209 if ((block_type & WRITE_IMMED) && bp->b_dirt==DIRTY && bp->b_dev != NO_DEV) {
00210 rw_block(bp, WRITING);
00211 }
00212 }
00213
00214
00215
00216
00217 PUBLIC zone_t alloc_zone(dev, z)
00218 dev_t dev;
00219 zone_t z;
00220 {
00221
00222
00223 int major, minor;
00224 bit_t b, bit;
00225 struct super_block *sp;
00226
00227
00228
00229
00230
00231
00232
00233
00234 sp = get_super(dev);
00235
00236
00237 if (z == sp->s_firstdatazone) {
00238 bit = sp->s_zsearch;
00239 } else {
00240 bit = (bit_t) z - (sp->s_firstdatazone - 1);
00241 }
00242 b = alloc_bit(sp, ZMAP, bit);
00243 if (b == NO_BIT) {
00244 err_code = ENOSPC;
00245 major = (int) (sp->s_dev >> MAJOR) & BYTE;
00246 minor = (int) (sp->s_dev >> MINOR) & BYTE;
00247 printf("No space on device %d/%d\n", major, minor);
00248 return(NO_ZONE);
00249 }
00250 if (z == sp->s_firstdatazone) sp->s_zsearch = b;
00251 return(sp->s_firstdatazone - 1 + (zone_t) b);
00252 }
00253
00254
00255
00256
00257 PUBLIC void free_zone(dev, numb)
00258 dev_t dev;
00259 zone_t numb;
00260 {
00261
00262
00263 register struct super_block *sp;
00264 bit_t bit;
00265
00266
00267 sp = get_super(dev);
00268 if (numb < sp->s_firstdatazone || numb >= sp->s_zones) return;
00269 bit = (bit_t) (numb - (sp->s_firstdatazone - 1));
00270 free_bit(sp, ZMAP, bit);
00271 if (bit < sp->s_zsearch) sp->s_zsearch = bit;
00272 }
00273
00274
00275
00276
00277 PRIVATE int rw_block(bp, rw_flag)
00278 register struct buf *bp;
00279 int rw_flag;
00280 {
00281
00282
00283
00284
00285
00286 int r, op;
00287 u64_t pos;
00288 dev_t dev;
00289
00290 if ( (dev = bp->b_dev) != NO_DEV) {
00291 pos = mul64u(bp->b_blocknr, fs_block_size);
00292 op = (rw_flag == READING ? MFS_DEV_READ : MFS_DEV_WRITE);
00293 r = block_dev_io(op, dev, SELF_E, bp->b_data, pos, fs_block_size, 0);
00294 if (r != fs_block_size) {
00295 if (r >= 0) r = END_OF_FILE;
00296 if (r != END_OF_FILE)
00297 printf("MFS(%d) I/O error on device %d/%d, block %ld\n",
00298 SELF_E, (dev>>MAJOR)&BYTE, (dev>>MINOR)&BYTE,
00299 bp->b_blocknr);
00300
00301 bp->b_dev = NO_DEV;
00302
00303
00304 if (rw_flag == READING) rdwt_err = r;
00305 }
00306 }
00307
00308 bp->b_dirt = CLEAN;
00309
00310 return OK;
00311 }
00312
00313
00314
00315
00316 PUBLIC void invalidate(device)
00317 dev_t device;
00318 {
00319
00320
00321 register struct buf *bp;
00322
00323 for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++)
00324 if (bp->b_dev == device) bp->b_dev = NO_DEV;
00325 }
00326
00327
00328
00329
00330 PUBLIC void flushall(dev)
00331 dev_t dev;
00332 {
00333
00334
00335 register struct buf *bp;
00336 static struct buf **dirty;
00337 int ndirty;
00338
00339 STATICINIT(dirty, NR_BUFS);
00340
00341 for (bp = &buf[0], ndirty = 0; bp < &buf[NR_BUFS]; bp++)
00342 if (bp->b_dirt == DIRTY && bp->b_dev == dev) dirty[ndirty++] = bp;
00343 rw_scattered(dev, dirty, ndirty, WRITING);
00344 }
00345
00346
00347
00348
00349 PUBLIC void rw_scattered(dev, bufq, bufqsize, rw_flag)
00350 dev_t dev;
00351 struct buf **bufq;
00352 int bufqsize;
00353 int rw_flag;
00354 {
00355
00356
00357 register struct buf *bp;
00358 int gap;
00359 register int i;
00360 register iovec_t *iop;
00361 static iovec_t *iovec = NULL;
00362 int j, r;
00363
00364 STATICINIT(iovec, NR_IOREQS);
00365
00366
00367 gap = 1;
00368 do
00369 gap = 3 * gap + 1;
00370 while (gap <= bufqsize);
00371 while (gap != 1) {
00372 gap /= 3;
00373 for (j = gap; j < bufqsize; j++) {
00374 for (i = j - gap;
00375 i >= 0 && bufq[i]->b_blocknr > bufq[i + gap]->b_blocknr;
00376 i -= gap) {
00377 bp = bufq[i];
00378 bufq[i] = bufq[i + gap];
00379 bufq[i + gap] = bp;
00380 }
00381 }
00382 }
00383
00384
00385
00386
00387 while (bufqsize > 0) {
00388 for (j = 0, iop = iovec; j < NR_IOREQS && j < bufqsize; j++, iop++) {
00389 bp = bufq[j];
00390 if (bp->b_blocknr != bufq[0]->b_blocknr + j) break;
00391 iop->iov_addr = (vir_bytes) bp->b_data;
00392 iop->iov_size = fs_block_size;
00393 }
00394 r = block_dev_io(rw_flag == WRITING ? MFS_DEV_SCATTER : MFS_DEV_GATHER,
00395 dev, SELF_E, iovec,
00396 mul64u(bufq[0]->b_blocknr, fs_block_size), j, 0);
00397
00398
00399
00400
00401 for (i = 0, iop = iovec; i < j; i++, iop++) {
00402 bp = bufq[i];
00403 if (iop->iov_size != 0) {
00404
00405 if (r != OK && i == 0) {
00406 printf(
00407 "fs: I/O error on device %d/%d, block %lu\n",
00408 (dev>>MAJOR)&BYTE, (dev>>MINOR)&BYTE,
00409 bp->b_blocknr);
00410 bp->b_dev = NO_DEV;
00411 }
00412 break;
00413 }
00414 if (rw_flag == READING) {
00415 bp->b_dev = dev;
00416 put_block(bp, PARTIAL_DATA_BLOCK);
00417 } else {
00418 bp->b_dirt = CLEAN;
00419 }
00420 }
00421 bufq += i;
00422 bufqsize -= i;
00423 if (rw_flag == READING) {
00424
00425
00426
00427 while (bufqsize > 0) {
00428 put_block(*bufq++, PARTIAL_DATA_BLOCK);
00429 bufqsize--;
00430 }
00431 }
00432 if (rw_flag == WRITING && i == 0) {
00433
00434
00435
00436
00437
00438 break;
00439 }
00440 }
00441 }
00442
00443
00444
00445
00446 PRIVATE void rm_lru(bp)
00447 struct buf *bp;
00448 {
00449
00450 struct buf *next_ptr, *prev_ptr;
00451
00452 bufs_in_use++;
00453 next_ptr = bp->b_next;
00454 prev_ptr = bp->b_prev;
00455 if (prev_ptr != NIL_BUF)
00456 prev_ptr->b_next = next_ptr;
00457 else
00458 front = next_ptr;
00459
00460 if (next_ptr != NIL_BUF)
00461 next_ptr->b_prev = prev_ptr;
00462 else
00463 rear = prev_ptr;
00464 }
00465
00466
00467
00468
00469 PUBLIC void set_blocksize(int blocksize)
00470 {
00471 struct buf *bp;
00472 struct inode *rip;
00473
00474 ASSERT(blocksize > 0);
00475
00476 for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++)
00477 if(bp->b_count != 0)
00478 panic("MFS", "change blocksize with buffer in use",
00479 NO_NUM);
00480
00481 for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++)
00482 if (rip->i_count > 0)
00483 panic("MFS", "change blocksize with inode in use",
00484 NO_NUM);
00485
00486 fs_sync();
00487
00488 buf_pool();
00489 fs_block_size = blocksize;
00490 }
00491
00492
00493
00494
00495 PUBLIC void buf_pool(void)
00496 {
00497
00498 register struct buf *bp;
00499
00500 bufs_in_use = 0;
00501 front = &buf[0];
00502 rear = &buf[NR_BUFS - 1];
00503
00504 for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) {
00505 bp->b_blocknr = NO_BLOCK;
00506 bp->b_dev = NO_DEV;
00507 bp->b_next = bp + 1;
00508 bp->b_prev = bp - 1;
00509 bp->bp = NULL;
00510 bp->b_bytes = 0;
00511 }
00512 buf[0].b_prev = NIL_BUF;
00513 buf[NR_BUFS - 1].b_next = NIL_BUF;
00514
00515 for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) bp->b_hash = bp->b_next;
00516 buf_hash[0] = front;
00517
00518 }
00519