1 #include "devices/block.h"
5 #include "devices/ide.h"
6 #include "threads/malloc.h"
11 struct list_elem list_elem; /* Element in all_blocks. */
13 char name[16]; /* Block device name. */
14 enum block_type type; /* Type of block device. */
15 block_sector_t size; /* Size in sectors. */
17 const struct block_operations *ops; /* Driver operations. */
18 void *aux; /* Extra data owned by driver. */
20 unsigned long long read_cnt; /* Number of sectors read. */
21 unsigned long long write_cnt; /* Number of sectors written. */
24 /* List of all block devices. */
25 static struct list all_blocks = LIST_INITIALIZER (all_blocks);
27 /* The block block assigned to each Pintos role. */
28 static struct block *block_by_role[BLOCK_ROLE_CNT];
30 static struct block *list_elem_to_block (struct list_elem *);
32 /* Returns a human-readable name for the given block device
35 block_type_name (enum block_type type)
37 static const char *block_type_names[BLOCK_CNT] =
47 ASSERT (type < BLOCK_CNT);
48 return block_type_names[type];
51 /* Returns the block device fulfilling the given ROLE, or a null
52 pointer if no block device has been assigned that role. */
54 block_get_role (enum block_type role)
56 ASSERT (role < BLOCK_ROLE_CNT);
57 return block_by_role[role];
60 /* Assigns BLOCK the given ROLE. */
62 block_set_role (enum block_type role, struct block *block)
64 ASSERT (role < BLOCK_ROLE_CNT);
65 block_by_role[role] = block;
68 /* Returns the first block device in kernel probe order, or a
69 null pointer if no block devices are registered. */
73 return list_elem_to_block (list_begin (&all_blocks));
76 /* Returns the block device following BLOCK in kernel probe
77 order, or a null pointer if BLOCK is the last block device. */
79 block_next (struct block *block)
81 return list_elem_to_block (list_next (&block->list_elem));
84 /* Returns the block device with the given NAME, or a null
85 pointer if no block device has that name. */
87 block_get_by_name (const char *name)
91 for (e = list_begin (&all_blocks); e != list_end (&all_blocks);
94 struct block *block = list_entry (e, struct block, list_elem);
95 if (!strcmp (name, block->name))
102 /* Verifies that SECTOR is a valid offset within BLOCK.
105 check_sector (struct block *block, block_sector_t sector)
107 if (sector >= block->size)
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);
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. */
121 block_read (struct block *block, block_sector_t sector, void *buffer)
123 check_sector (block, sector);
124 block->ops->read (block->aux, sector, buffer);
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. */
134 block_write (struct block *block, block_sector_t sector, const void *buffer)
136 check_sector (block, sector);
137 ASSERT (block->type != BLOCK_FOREIGN);
138 block->ops->write (block->aux, sector, buffer);
142 /* Returns the number of sectors in BLOCK. */
144 block_size (struct block *block)
149 /* Returns BLOCK's name (e.g. "hda"). */
151 block_name (struct block *block)
156 /* Returns BLOCK's type. */
158 block_type (struct block *block)
163 /* Prints statistics for each block device used for a Pintos role. */
165 block_print_stats (void)
169 for (i = 0; i < BLOCK_ROLE_CNT; i++)
171 struct block *block = block_by_role[i];
174 printf ("%s (%s): %llu reads, %llu writes\n",
175 block->name, block_type_name (block->type),
176 block->read_cnt, block->write_cnt);
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. */
187 block_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)
191 struct block *block = malloc (sizeof *block);
193 PANIC ("Failed to allocate memory for block device descriptor");
195 list_push_back (&all_blocks, &block->list_elem);
196 strlcpy (block->name, name, sizeof block->name);
202 block->write_cnt = 0;
204 printf ("%s: %'"PRDSNu" sectors (", block->name, block->size);
205 print_human_readable_size ((uint64_t) block->size * BLOCK_SECTOR_SIZE);
207 if (extra_info != NULL)
208 printf (", %s", extra_info);
214 /* Returns the block device corresponding to LIST_ELEM, or a null
215 pointer if LIST_ELEM is the list end of all_blocks. */
216 static struct block *
217 list_elem_to_block (struct list_elem *list_elem)
219 return (list_elem != list_end (&all_blocks)
220 ? list_entry (list_elem, struct block, list_elem)