inode_create()

Mate, mate y mucha más mate

Un poco de explicación...

Bien, lo primero que debes enfocarte es en la función de inode_create(). En pocas palabras, esta función se llama cuando se quiere crear un nuevo archivo en la partición del File System. Aquí estarás calculando cuántos sectores necesitarás para guardar el archivo, qué fracción del archivo le corresponde un determinado sector y muchas cosas más.

Estarás utilizando exhaustivamente varios buffers temporales para almacenar cierta información. Debes de utilizar las funciones malloc(), realloc() y free() si no, cosas extrañas pasarán en las pruebas.

Lo que harás en esta función es lo siguiente:

  1. Calcular cuántos sectores es requerido para guardar el archivo completo.

  2. Reservar los sectores necesarios e inicializar los bloques bloques directos, el bloque indirecto y/o el bloque doble indirecto (estructurar el Inode).

  3. Guardar en cada sector el pedazo de archivo que corresponde.

  4. Escribir un EOF.

El paso número 2 es el más tedioso de toda esta función, porque constantemente dudarás de tus cálculos matemáticos, dudarás de tu código por la incertidumbre de cómo funciona PintOS y/o porque dudas de C. Entenderás este párrafo conforme avances.

Existe la idea de ir guardando los contenidos del archivo durante el proceso de estructuración del inode. No te recomendamos ese approach, puede ser que por el cansancio te confundas mucho o la implementación puede resultarte complicada. Es mejor ir despacio pero con buena letra.

Implementación

Primera Parte: Estructurar el Inode

Como mencionamos, creemos que es mejor crear y estructurar el Inode y luego escribir los contenidos del archivo a realizar las dos tareas simultáneamente para evitar complicarnos la existencia y el código.

Te dejo un poco de código solo porque me caes bien:

bool inode_create (block_sector_t sector, off_t length) {

	struct inode_disk * disk_inode = NULL;
	bool success = false;

	ASSERT (length >= 0);

	/* If this assertion fails, the inode structure is not exactly
		 one sector in size, and you should fix that. */
	ASSERT (sizeof *disk_inode == BLOCK_SECTOR_SIZE);

	disk_inode = calloc (1, sizeof *disk_inode);
	if (disk_inode != NULL)
		{
			/* Initialize disk_inode with the starting 'length' bytes */
			disk_inode->length = length;
			disk_inode->magic = INODE_MAGIC;

			//-------------------------------------------
			// Tu codiguito aqui :D
			
		}
	free (disk_inode);
	return success;
}

Lo primero que debes de hacer es calcular cuántos sectores en total necesitarás para guardar el archivo. En base a ello, nosotros lograremos conocer si es necesario hacer uso de todos los bloques o no.

No existe algo como "3.14" sectores... ¿es 3 o 4 sectores que necesitas?

Una vez ya calculaste el número de sectores que necesita el archivo, es momento de hacer la parte divertida: ¡estructuremos el inode!

Dependiendo del número de sectores que necesite el archivo, deberás de inicializar los 10 bloques directos, el bloque indirecto y/o el bloque doble indirecto. No tiene sentido que inicialices todos los bloques si el tamaño del archivo es pequeño. Recuerda, la capacidad de crecimiento o de decrecimiento es lo que caracteriza este tipo de File System. Si inicializas todos los bloques, estás reservando espacio que no se usará y que otro archivo puede ser que sí lo necesite y lo use. La funcionalidad de crecer o decrecer lo haremos en la función inode_write().

Entonces... ¿cómo estructuraremos el inode? Primero, debes de fijarte si el tamaño del archivo puede satisfacerse con los 10 bloques directos del inode. Si es así, entonces inicializas únicamente los bloques directos que necesitas.

Procedimiento para incializar un bloque directo:

  1. Obtener un sector libre.

  2. Añadir su referencia al bloque directo correspondiente en el inode_disk.

Si los 10 bloques no son suficientes, debes de emplear el bloque indirecto.

Con el bloque indirecto, las cosas se complican mucho y es muy fácil perderter. Debes de saber lo que estás haciendo y la mejor forma es hacer dibujos o bosquejos y estructurar tus ideas. Te daré una explicación básica para que tengas una idea.

Un bloque indirecto realmente es una referencia a un sector que guarda referencias a otros sectores que contienen la información del archivo. Entonces, el contenido este sector (referenciado por el bloque indirecto) encuentras los punteros o los índices de esos sectores que contienen la verdadera información.

Sabemos que el tamaño de un sector es de 512 Bytes y el tamaño de un índice de un sector (block_sector_t) es de 4 Bytes. Entonces, si reservamos un sector que se usará como bloque indirecto, este tiene la capacidad de guardar 128 índices. Y con esa premisa, podemos concluir que podemos guardar las referencias de hasta 128 sectores.

Mucho que digerir en dos párrafos, ¿no es así? Tómate tu tiempo, verás que lo entenderás luego de leerlo varias veces. Además, te dejo estas imágenes que pueden servirte.

*Insertar imagenes*

Asumiendo que tienes una idea clara de lo que quise decir anteriormente, entonces procedes a reservar un sector que será utilizado como el bloque indirecto. Luego, reservas los sectores que necesites para guardar la información y por cada sector nuevo que reserves, debes de guardar su índice (es decir, su block_sector_t) en el sector usado como bloque indirecto. Y por último, añades la referencia al bloque indirecto en el inode_disk.

Si entendiste muy bien el concepto del bloque indirecto, entonces no tendrás problema entendiendo el bloque doble indirecto.

La idea del bloque doble indirecto es la misma que del bloque indirecto, solo que añadimos un nivel extra de referencias.

El sector utilizado como bloque doble indirecto guarda 128 índices de 128 sectores cuyos contenidos guardan las referencias de otros 128 sectores y estos últimos guardan la información del archivo.

El bloque doble indirecto es con el que se tiene que tener mucho cuidado. Si te fijas, cada vez que excedes de 128 sectores, necesitas inicializar un bloque indirecto y posteriormente los sectores que necesitas de ese bloque indirecto. Incluso, puede darse la situación que debas repetir este proceso muchas veces.

Los pasos básicos son:

  1. Reservar un sector libre que será usado como el bloque doble indirecto

  2. Reservar otro sector libre que será usado como un bloque indirecto (ojo: no lo confundas con el indirect_block que está declarado en el inode_disk. Este nuevo bloque indirecto es totalmente distinto).

    1. Reservar los sectores necesarios de este bloque indirecto.

    2. Guardar las referencias de estos sectores en el bloque indirecto

  3. Guardar la referencia de este nuevo bloque indirecto en el bloque doble indirecto.

  4. Añadir la referencia al bloque doble indirecto en el inode_disk.

Te darás cuenta que el uso de la matemática es muy intensa, pero no te alegres todavía - aún falta escribir los contenidos del archivo.

Segunda Parte: Guardar el Archivo a disco

Ahora que ya tenemos construido el inode, debemos de escribir los contenidos del archivo. Ya después de quebrarte la cabeza en cómo construir el inode, te encontrarás tan familiarizado que no sentirás difícil esta parte ni las funciones del inode_read() y inode_write().

Esta segunda parte consiste en recorrer el inode e ir escribiendo por pedazos el archivo.

Como ya lo habrás inferido... estarás recorriendo en sector en sector escribiendo un máximo de hasta 512 Bytes del archivo. Quiere decir que debes ir recorriendo el archivo en pasos de 512 Bytes.

Empiezas de primero con los bloques directos, luego con el bloque indirecto y por último el bloque doble indirecto.

No debes de olvidar que cuando escribes el último byte del archivo, debes de escribir un EOF en el siguiente byte para indicar que ahí ha terminado dicho archivo.

FAQ

  • ¿El buffer cache?

    Si, harás uso del buffer cache cada vez que lees o modificas el contenido de un sector del disco.

  • ¿Puedo llorar?

    Adelante, nosotros pasamos por aquí también. Una lloradita y a terminar PintOS

Last updated