CS318 - Pintos
Pintos source browser for JHU CS318 course
block.c
Go to the documentation of this file.
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. */
9 struct 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. */
26 
27 /** The block block assigned to each Pintos role. */
29 
30 static struct block *list_elem_to_block (struct list_elem *);
31 
32 /** Returns a human-readable name for the given block device
33  TYPE. */
34 const char *
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. */
53 struct block *
55 {
56  ASSERT (role < BLOCK_ROLE_CNT);
57  return block_by_role[role];
58 }
59 
60 /** Assigns BLOCK the given ROLE. */
61 void
62 block_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. */
70 struct block *
72 {
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. */
78 struct block *
80 {
82 }
83 
84 /** Returns the block device with the given NAME, or a null
85  pointer if no block device has that name. */
86 struct block *
87 block_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. */
104 static void
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. */
120 void
121 block_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. */
133 void
134 block_write (struct block *block, block_sector_t sector, const void *buffer)
135 {
136  check_sector (block, sector);
138  block->ops->write (block->aux, sector, buffer);
139  block->write_cnt++;
140 }
141 
142 /** Returns the number of sectors in BLOCK. */
145 {
146  return block->size;
147 }
148 
149 /** Returns BLOCK's name (e.g. "hda"). */
150 const char *
152 {
153  return block->name;
154 }
155 
156 /** Returns BLOCK's type. */
157 enum block_type
159 {
160  return block->type;
161 }
162 
163 /** Prints statistics for each block device used for a Pintos role. */
164 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",
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. */
186 struct block *
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)
190 {
191  struct block *block = malloc (sizeof *block);
192  if (block == NULL)
193  PANIC ("Failed to allocate memory for block device descriptor");
194 
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);
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. */
216 static struct block *
218 {
219  return (list_elem != list_end (&all_blocks)
220  ? list_entry (list_elem, struct block, list_elem)
221  : NULL);
222 }
223 
uint64_t
unsigned long long int uint64_t
Definition: stdint.h:29
name
char * name[]
Definition: insult.c:47
malloc
void * malloc(size_t size)
Obtains and returns a new block of at least SIZE bytes.
Definition: malloc.c:90
block.h
list_elem
Doubly linked list.
Definition: list.h:90
list_entry
#define list_entry(LIST_ELEM, STRUCT, MEMBER)
Converts pointer to list element LIST_ELEM into a pointer to the structure that LIST_ELEM is embedded...
Definition: list.h:108
BLOCK_FOREIGN
Owned by non-Pintos operating system.
Definition: block.h:38
NULL
#define NULL
Definition: stddef.h:4
string.h
block_operations
Lower-level interface to block device drivers.
Definition: block.h:64
strcmp
int strcmp(const char *a_, const char *b_)
Finds the first differing characters in strings A and B.
Definition: string.c:73
block_operations::read
void(* read)(void *aux, block_sector_t, void *buffer)
Definition: block.h:66
list_next
struct list_elem * list_next(struct list_elem *elem)
Returns the element after ELEM in its list.
Definition: list.c:82
BLOCK_CNT
Number of Pintos block types.
Definition: block.h:39
block::type
enum block_type type
Type of block device.
Definition: block.c:14
block::size
block_sector_t size
Size in sectors.
Definition: block.c:15
block_get_role
struct block * block_get_role(enum block_type role)
Returns the block device fulfilling the given ROLE, or a null pointer if no block device has been ass...
Definition: block.c:54
block_sector_t
uint32_t block_sector_t
Index of a block device sector.
Definition: block.h:15
block_by_role
static struct block * block_by_role[BLOCK_ROLE_CNT]
The block block assigned to each Pintos role.
Definition: block.c:28
PANIC
#define PANIC(...)
Halts the OS, printing the source file name, line number, and function name, plus a user-specific mes...
Definition: debug.h:14
check_sector
static void check_sector(struct block *block, block_sector_t sector)
Verifies that SECTOR is a valid offset within BLOCK.
Definition: block.c:105
block_type
enum block_type block_type(struct block *block)
Returns BLOCK's type.
Definition: block.c:158
buffer
static struct intq buffer
Stores keys from the keyboard and serial port.
Definition: input.c:7
printf
int printf(const char *format,...)
Writes formatted output to the console.
Definition: stdio.c:79
PRDSNu
#define PRDSNu
Format specifier for printf(), e.g.
Definition: block.h:19
block_name
const char * block_name(struct block *block)
Returns BLOCK's name (e.g.
Definition: block.c:151
BLOCK_ROLE_CNT
Definition: block.h:33
malloc.h
list_end
struct list_elem * list_end(struct list *list)
Returns LIST's tail.
Definition: list.c:94
list_begin
struct list_elem * list_begin(struct list *list)
Returns the beginning of LIST.
Definition: list.c:72
ide.h
ASSERT
#define ASSERT(CONDITION)
This is outside the header guard so that debug.h may be included multiple times with different settin...
Definition: debug.h:31
block_get_by_name
struct block * block_get_by_name(const char *name)
Returns the block device with the given NAME, or a null pointer if no block device has that name.
Definition: block.c:87
block::read_cnt
unsigned long long read_cnt
Number of sectors read.
Definition: block.c:20
block
A block device.
Definition: block.c:9
block_first
struct block * block_first(void)
Returns the first block device in kernel probe order, or a null pointer if no block devices are regis...
Definition: block.c:71
block_next
struct block * block_next(struct block *block)
Returns the block device following BLOCK in kernel probe order, or a null pointer if BLOCK is the las...
Definition: block.c:79
block::name
char name[16]
Block device name.
Definition: block.c:13
LIST_INITIALIZER
#define LIST_INITIALIZER(NAME)
List initialization.
Definition: list.h:122
BLOCK_SECTOR_SIZE
#define BLOCK_SECTOR_SIZE
Size of a block device sector in bytes.
Definition: block.h:11
block_print_stats
void block_print_stats(void)
Prints statistics for each block device used for a Pintos role.
Definition: block.c:165
block_read
void block_read(struct block *block, block_sector_t sector, void *buffer)
Reads sector SECTOR from BLOCK into BUFFER, which must have room for BLOCK_SECTOR_SIZE bytes.
Definition: block.c:121
block::write_cnt
unsigned long long write_cnt
Number of sectors written.
Definition: block.c:21
block_operations::write
void(* write)(void *aux, block_sector_t, const void *buffer)
Definition: block.h:67
block_size
block_sector_t block_size(struct block *block)
Returns the number of sectors in BLOCK.
Definition: block.c:144
block_type_name
const char * block_type_name(enum block_type type)
Returns a human-readable name for the given block device TYPE.
Definition: block.c:35
print_human_readable_size
void print_human_readable_size(uint64_t size)
Prints SIZE, which represents a number of bytes, in a human-readable format, e.g.
Definition: stdio.c:642
block::list_elem
struct list_elem list_elem
Element in all_blocks.
Definition: block.c:11
block_type
block_type
Type of a block device.
Definition: block.h:26
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Copies string SRC to DST.
Definition: string.c:326
list_push_back
void list_push_back(struct list *list, struct list_elem *elem)
Inserts ELEM at the end of LIST, so that it becomes the back in LIST.
Definition: list.c:217
block::aux
void * aux
Extra data owned by driver.
Definition: block.c:18
all_blocks
static struct list all_blocks
List of all block devices.
Definition: block.c:25
list.h
block_set_role
void block_set_role(enum block_type role, struct block *block)
Assigns BLOCK the given ROLE.
Definition: block.c:62
block_write
void block_write(struct block *block, block_sector_t sector, const void *buffer)
Write sector SECTOR to BLOCK from BUFFER, which must contain BLOCK_SECTOR_SIZE bytes.
Definition: block.c:134
list
List.
Definition: list.h:97
block::ops
const struct block_operations * ops
Driver operations.
Definition: block.c:17
block_register
struct block * block_register(const char *name, enum block_type type, const char *extra_info, block_sector_t size, const struct block_operations *ops, void *aux)
Registers a new block device with the given NAME.
Definition: block.c:187
list_elem_to_block
static struct block * list_elem_to_block(struct list_elem *)
Returns the block device corresponding to LIST_ELEM, or a null pointer if LIST_ELEM is the list end o...
Definition: block.c:217