summaryrefslogtreecommitdiff
path: root/minix/fs/mfs/cache.c
blob: 4b3fcc2234c6f02d8672d3591db221c6275e11ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/* The file system maintains a buffer cache to reduce the number of disk
 * accesses needed.  Whenever a read or write to the disk is done, a check is
 * first made to see if the block is in the cache.  This file contains some
 * related routines, but the cache is now in libminixfs.
 */

#include "fs.h"
#include <minix/u64.h>
#include <minix/bdev.h>
#include <sys/param.h>
#include <stdlib.h>
#include <assert.h>
#include <minix/libminixfs.h>
#include <math.h>
#include "buf.h"
#include "super.h"
#include "inode.h"

/*===========================================================================*
 *				get_block				     *
 *===========================================================================*/
struct buf *get_block(dev_t dev, block_t block, int how)
{
/* Wrapper routine for lmfs_get_block(). This MFS implementation does not deal
 * well with block read errors pretty much anywhere. To prevent corruption due
 * to unchecked error conditions, we panic upon an I/O failure here.
 */
  struct buf *bp;
  int r;

  if ((r = lmfs_get_block(&bp, dev, block, how)) != OK && r != ENOENT)
	panic("MFS: error getting block (%llu,%u): %d", dev, block, r);

  assert(r == OK || how == PEEK);

  return (r == OK) ? bp : NULL;
}

/*===========================================================================*
 *				alloc_zone				     *
 *===========================================================================*/
zone_t alloc_zone(
  dev_t dev,			/* device where zone wanted */
  zone_t z			/* try to allocate new zone near this one */
)
{
/* Allocate a new zone on the indicated device and return its number. */

  bit_t b, bit;
  struct super_block *sp;
  static int print_oos_msg = 1;

  /* Note that the routine alloc_bit() returns 1 for the lowest possible
   * zone, which corresponds to sp->s_firstdatazone.  To convert a value
   * between the bit number, 'b', used by alloc_bit() and the zone number, 'z',
   * stored in the inode, use the formula:
   *     z = b + sp->s_firstdatazone - 1
   * Alloc_bit() never returns 0, since this is used for NO_BIT (failure).
   */
  sp = &superblock;

  /* If z is 0, skip initial part of the map known to be fully in use. */
  if (z == sp->s_firstdatazone) {
	bit = sp->s_zsearch;
  } else {
	bit = (bit_t) (z - (sp->s_firstdatazone - 1));
  }
  b = alloc_bit(sp, ZMAP, bit);
  if (b == NO_BIT) {
	err_code = ENOSPC;
	if (print_oos_msg)
		printf("No space on device %d/%d\n", major(sp->s_dev),
			minor(sp->s_dev));
	print_oos_msg = 0;	/* Don't repeat message */
	return(NO_ZONE);
  }
  print_oos_msg = 1;
  if (z == sp->s_firstdatazone) sp->s_zsearch = b;	/* for next time */
  return( (zone_t) (sp->s_firstdatazone - 1) + (zone_t) b);
}

/*===========================================================================*
 *				free_zone				     *
 *===========================================================================*/
void free_zone(
  dev_t dev,				/* device where zone located */
  zone_t numb				/* zone to be returned */
)
{
/* Return a zone. */

  register struct super_block *sp;
  bit_t bit;

  /* Locate the appropriate super_block and return bit. */
  sp = &superblock;
  if (numb < sp->s_firstdatazone || numb >= sp->s_zones) return;
  bit = (bit_t) (numb - (zone_t) (sp->s_firstdatazone - 1));
  free_bit(sp, ZMAP, bit);
  if (bit < sp->s_zsearch) sp->s_zsearch = bit;

  /* Also tell libminixfs, so that 1) if it has a block for this bit, it can
   * mark it as clean, thus reducing useless writes, and 2) it can tell VM that
   * any previous inode association is to be broken for this block, so that the
   * block will not be mapped in erroneously later on.
   */
  assert(sp->s_log_zone_size == 0); /* otherwise we need a loop here.. */
  lmfs_free_block(dev, (block_t)numb);
}