00001 #include "devices/block.h"
00002
00003 #include <list.h>
00004 #include <string.h>
00005 #include <stdio.h>
00006 #include "devices/ide.h"
00007 #include "threads/malloc.h"
00008 #include "threads/synch.h"
00009
00010
00011 struct block
00012 {
00013 struct list_elem list_elem;
00014
00015 char name[16];
00016 enum block_type type;
00017 block_sector_t size;
00018
00019 const struct block_operations *ops;
00020 void *aux;
00021
00022 struct lock lock;
00023 unsigned long long read_cnt;
00024 unsigned long long write_cnt;
00025 };
00026
00027
00028 static struct list all_blocks = LIST_INITIALIZER (all_blocks);
00029
00030
00031 static struct block *block_by_role[BLOCK_ROLE_CNT];
00032
00033 static struct block *list_elem_to_block (struct list_elem *);
00034
00035
00036
00037 const char *
00038 block_type_name (enum block_type type)
00039 {
00040 static const char *block_type_names[BLOCK_CNT] =
00041 {
00042 "kernel",
00043 "filesys",
00044 "scratch",
00045 "swap",
00046 "raw",
00047 "foreign",
00048 };
00049
00050 ASSERT (type < BLOCK_CNT);
00051 return block_type_names[type];
00052 }
00053
00054
00055
00056 struct block *
00057 block_get_role (enum block_type role)
00058 {
00059 ASSERT (role < BLOCK_ROLE_CNT);
00060 return block_by_role[role];
00061 }
00062
00063
00064 void
00065 block_set_role (enum block_type role, struct block *block)
00066 {
00067 ASSERT (role < BLOCK_ROLE_CNT);
00068 block_by_role[role] = block;
00069 }
00070
00071
00072
00073 struct block *
00074 block_first (void)
00075 {
00076 return list_elem_to_block (list_begin (&all_blocks));
00077 }
00078
00079
00080
00081 struct block *
00082 block_next (struct block *block)
00083 {
00084 return list_elem_to_block (list_next (&block->list_elem));
00085 }
00086
00087
00088
00089 struct block *
00090 block_get_by_name (const char *name)
00091 {
00092 struct list_elem *e;
00093
00094 for (e = list_begin (&all_blocks); e != list_end (&all_blocks);
00095 e = list_next (e))
00096 {
00097 struct block *block = list_entry (e, struct block, list_elem);
00098 if (!strcmp (name, block->name))
00099 return block;
00100 }
00101
00102 return NULL;
00103 }
00104
00105
00106
00107 static void
00108 check_sector (struct block *block, block_sector_t sector)
00109 {
00110 if (sector >= block->size)
00111 {
00112
00113
00114 PANIC ("Access past end of device %s (sector=%"PRDSNu", "
00115 "size=%"PRDSNu")\n", block_name (block), sector, block->size);
00116 }
00117 }
00118
00119
00120
00121
00122
00123 void
00124 block_read (struct block *block, block_sector_t sector, void *buffer)
00125 {
00126 check_sector (block, sector);
00127 block->ops->read (block->aux, sector, buffer);
00128 lock_acquire (&block->lock);
00129 block->read_cnt++;
00130 lock_release (&block->lock);
00131 }
00132
00133
00134
00135
00136
00137
00138 void
00139 block_write (struct block *block, block_sector_t sector, const void *buffer)
00140 {
00141 check_sector (block, sector);
00142 ASSERT (block->type != BLOCK_FOREIGN);
00143 block->ops->write (block->aux, sector, buffer);
00144 lock_acquire (&block->lock);
00145 block->write_cnt++;
00146 lock_release (&block->lock);
00147 }
00148
00149
00150 block_sector_t
00151 block_size (struct block *block)
00152 {
00153 return block->size;
00154 }
00155
00156
00157 const char *
00158 block_name (struct block *block)
00159 {
00160 return block->name;
00161 }
00162
00163
00164 enum block_type
00165 block_type (struct block *block)
00166 {
00167 return block->type;
00168 }
00169
00170
00171 void
00172 block_print_stats (void)
00173 {
00174 int i;
00175
00176 for (i = 0; i < BLOCK_CNT; i++)
00177 {
00178 struct block *block = block_by_role[i];
00179 if (block != NULL)
00180 {
00181 lock_acquire (&block->lock);
00182 printf ("%s (%s): %llu reads, %llu writes\n",
00183 block->name, block_type_name (block->type),
00184 block->read_cnt, block->write_cnt);
00185 lock_release (&block->lock);
00186 }
00187 }
00188 }
00189
00190
00191
00192
00193
00194
00195 struct block *
00196 block_register (const char *name, enum block_type type,
00197 const char *extra_info, block_sector_t size,
00198 const struct block_operations *ops, void *aux)
00199 {
00200 struct block *block = malloc (sizeof *block);
00201 if (block == NULL)
00202 PANIC ("Failed to allocate memory for block device descriptor");
00203
00204 list_push_back (&all_blocks, &block->list_elem);
00205 strlcpy (block->name, name, sizeof block->name);
00206 block->type = type;
00207 block->size = size;
00208 block->ops = ops;
00209 block->aux = aux;
00210 block->read_cnt = 0;
00211 block->write_cnt = 0;
00212 lock_init (&block->lock);
00213
00214 printf ("%s: %'"PRDSNu" sectors (", block->name, block->size);
00215 print_human_readable_size ((uint64_t) block->size * BLOCK_SECTOR_SIZE);
00216 printf (")");
00217 if (extra_info != NULL)
00218 printf (", %s", extra_info);
00219 printf ("\n");
00220
00221 return block;
00222 }
00223
00224
00225
00226 static struct block *
00227 list_elem_to_block (struct list_elem *list_elem)
00228 {
00229 return (list_elem != list_end (&all_blocks)
00230 ? list_entry (list_elem, struct block, list_elem)
00231 : NULL);
00232 }
00233