summaryrefslogtreecommitdiffstats
path: root/pintos-progos/devices/block.c
diff options
context:
space:
mode:
Diffstat (limited to 'pintos-progos/devices/block.c')
-rw-r--r--pintos-progos/devices/block.c223
1 files changed, 223 insertions, 0 deletions
diff --git a/pintos-progos/devices/block.c b/pintos-progos/devices/block.c
new file mode 100644
index 0000000..a3acec1
--- /dev/null
+++ b/pintos-progos/devices/block.c
@@ -0,0 +1,223 @@
1#include "devices/block.h"
2#include <list.h>
3#include <string.h>
4#include <stdio.h>
5#include "devices/ide.h"
6#include "threads/malloc.h"
7
8/* A block device. */
9struct block
10 {
11 struct list_elem list_elem; /* Element in all_blocks. */
12
13 char name[16]; /* Block device name. */
14 enum block_type type; /* Type of block device. */
15 block_sector_t size; /* Size in sectors. */
16
17 const struct block_operations *ops; /* Driver operations. */
18 void *aux; /* Extra data owned by driver. */
19
20 unsigned long long read_cnt; /* Number of sectors read. */
21 unsigned long long write_cnt; /* Number of sectors written. */
22 };
23
24/* List of all block devices. */
25static struct list all_blocks = LIST_INITIALIZER (all_blocks);
26
27/* The block block assigned to each Pintos role. */
28static struct block *block_by_role[BLOCK_ROLE_CNT];
29
30static struct block *list_elem_to_block (struct list_elem *);
31
32/* Returns a human-readable name for the given block device
33 TYPE. */
34const char *
35block_type_name (enum block_type type)
36{
37 static const char *block_type_names[BLOCK_CNT] =
38 {
39 "kernel",
40 "filesys",
41 "scratch",
42 "swap",
43 "raw",
44 "foreign",
45 };
46
47 ASSERT (type < BLOCK_CNT);
48 return block_type_names[type];
49}
50
51/* Returns the block device fulfilling the given ROLE, or a null
52 pointer if no block device has been assigned that role. */
53struct block *
54block_get_role (enum block_type role)
55{
56 ASSERT (role < BLOCK_ROLE_CNT);
57 return block_by_role[role];
58}
59
60/* Assigns BLOCK the given ROLE. */
61void
62block_set_role (enum block_type role, struct block *block)
63{
64 ASSERT (role < BLOCK_ROLE_CNT);
65 block_by_role[role] = block;
66}
67
68/* Returns the first block device in kernel probe order, or a
69 null pointer if no block devices are registered. */
70struct block *
71block_first (void)
72{
73 return list_elem_to_block (list_begin (&all_blocks));
74}
75
76/* Returns the block device following BLOCK in kernel probe
77 order, or a null pointer if BLOCK is the last block device. */
78struct block *
79block_next (struct block *block)
80{
81 return list_elem_to_block (list_next (&block->list_elem));
82}
83
84/* Returns the block device with the given NAME, or a null
85 pointer if no block device has that name. */
86struct block *
87block_get_by_name (const char *name)
88{
89 struct list_elem *e;
90
91 for (e = list_begin (&all_blocks); e != list_end (&all_blocks);
92 e = list_next (e))
93 {
94 struct block *block = list_entry (e, struct block, list_elem);
95 if (!strcmp (name, block->name))
96 return block;
97 }
98
99 return NULL;
100}
101
102/* Verifies that SECTOR is a valid offset within BLOCK.
103 Panics if not. */
104static void
105check_sector (struct block *block, block_sector_t sector)
106{
107 if (sector >= block->size)
108 {
109 /* We do not use ASSERT because we want to panic here
110 regardless of whether NDEBUG is defined. */
111 PANIC ("Access past end of device %s (sector=%"PRDSNu", "
112 "size=%"PRDSNu")\n", block_name (block), sector, block->size);
113 }
114}
115
116/* Reads sector SECTOR from BLOCK into BUFFER, which must
117 have room for BLOCK_SECTOR_SIZE bytes.
118 Internally synchronizes accesses to block devices, so external
119 per-block device locking is unneeded. */
120void
121block_read (struct block *block, block_sector_t sector, void *buffer)
122{
123 check_sector (block, sector);
124 block->ops->read (block->aux, sector, buffer);
125 block->read_cnt++;
126}
127
128/* Write sector SECTOR to BLOCK from BUFFER, which must contain
129 BLOCK_SECTOR_SIZE bytes. Returns after the block device has
130 acknowledged receiving the data.
131 Internally synchronizes accesses to block devices, so external
132 per-block device locking is unneeded. */
133void
134block_write (struct block *block, block_sector_t sector, const void *buffer)
135{
136 check_sector (block, sector);
137 ASSERT (block->type != BLOCK_FOREIGN);
138 block->ops->write (block->aux, sector, buffer);
139 block->write_cnt++;
140}
141
142/* Returns the number of sectors in BLOCK. */
143block_sector_t
144block_size (struct block *block)
145{
146 return block->size;
147}
148
149/* Returns BLOCK's name (e.g. "hda"). */
150const char *
151block_name (struct block *block)
152{
153 return block->name;
154}
155
156/* Returns BLOCK's type. */
157enum block_type
158block_type (struct block *block)
159{
160 return block->type;
161}
162
163/* Prints statistics for each block device used for a Pintos role. */
164void
165block_print_stats (void)
166{
167 int i;
168
169 for (i = 0; i < BLOCK_ROLE_CNT; i++)
170 {
171 struct block *block = block_by_role[i];
172 if (block != NULL)
173 {
174 printf ("%s (%s): %llu reads, %llu writes\n",
175 block->name, block_type_name (block->type),
176 block->read_cnt, block->write_cnt);
177 }
178 }
179}
180
181/* Registers a new block device with the given NAME. If
182 EXTRA_INFO is non-null, it is printed as part of a user
183 message. The block device's SIZE in sectors and its TYPE must
184 be provided, as well as the it operation functions OPS, which
185 will be passed AUX in each function call. */
186struct block *
187block_register (const char *name, enum block_type type,
188 const char *extra_info, block_sector_t size,
189 const struct block_operations *ops, void *aux)
190{
191 struct block *block = malloc (sizeof *block);
192 if (block == NULL)
193 PANIC ("Failed to allocate memory for block device descriptor");
194
195 list_push_back (&all_blocks, &block->list_elem);
196 strlcpy (block->name, name, sizeof block->name);
197 block->type = type;
198 block->size = size;
199 block->ops = ops;
200 block->aux = aux;
201 block->read_cnt = 0;
202 block->write_cnt = 0;
203
204 printf ("%s: %'"PRDSNu" sectors (", block->name, block->size);
205 print_human_readable_size ((uint64_t) block->size * BLOCK_SECTOR_SIZE);
206 printf (")");
207 if (extra_info != NULL)
208 printf (", %s", extra_info);
209 printf ("\n");
210
211 return block;
212}
213
214/* Returns the block device corresponding to LIST_ELEM, or a null
215 pointer if LIST_ELEM is the list end of all_blocks. */
216static struct block *
217list_elem_to_block (struct list_elem *list_elem)
218{
219 return (list_elem != list_end (&all_blocks)
220 ? list_entry (list_elem, struct block, list_elem)
221 : NULL);
222}
223