sisoputnfrba / foro

Foro de consultas para el trabajo práctico
151 stars 7 forks source link

No se como escribir en un archivo mapeado en memoria #2089

Closed julchat closed 3 years ago

julchat commented 3 years ago

El problema

Básicamente el título. Pensé que sabía, pero parece que no. En mi caso quise implementarlo para probar con el archivo Superbloques.ims Las funciones de creación de las carpetas andan, los archivos se crean bien, pero lo que creería que se escribiría en los archivos no se persiste si yo lo abro desde el explorador de linux, por ejemplo. Osea el archivo existe pero queda vacío

🔎 Búsqueda en foros

Estuve revisando los issues de los foros pero los que encontré o trataban el problema con pseudocódigo, o implicaban usar fwrite(), que tengo entendido, la idea de que usemos mmap() es para no usar muchos fwrite().

📝 Código relevante

Tengo el siguiente código:

    i_mongo_store_configuracion = leer_config_i_mongo_store(argv[1]);
    logger_i_mongo_store = iniciar_logger_i_mongo_store(argv[2]);
    inicializar_rutas(i_mongo_store_configuracion->PUNTO_MONTAJE);
    inicializar_filesystem(10,10);
void inicializar_filesystem(uint32_t block_size, uint32_t block_amount){
    crear_directorio(i_mongo_store_configuracion->PUNTO_MONTAJE);
    inicializar_superbloque(block_size,block_amount);
    inicializar_blocks(block_size,block_amount);
    crear_directorio(carpeta_files);
    crear_directorio(carpeta_bitacoras);
    log_info(logger_i_mongo_store, "FILESYSTEM INICIALIZADO DE 0 CON EXITO");
}
void crear_directorio(char* carpeta){
    int res = mkdir(carpeta, (mode_t) 0777);
    if(res == -1){
        log_error(logger_i_mongo_store,"No pude crear la carpeta %s",carpeta);
        exit(-1);
    }
}

Y, lo más importante

void inicializar_superbloque(uint32_t block_size, uint32_t block_amount){
    int fd = open(ruta_superbloque,O_CREAT | O_RDWR, (mode_t) 0777);
    if(fd==-1){
        no_pude_abrir_archivo(ruta_superbloque);
        exit(-1);
    }
    fallocate(fd,0,0,2*sizeof(uint32_t)+block_amount);
    superbloque = mmap(NULL, 2*sizeof(uint32_t)+block_amount, PROT_WRITE | PROT_READ, MAP_SHARED,fd,0);
    if(superbloque==MAP_FAILED){
        no_pude_mapear_archivo(ruta_superbloque);
        exit(-1);
    }
    memcpy(superbloque,&block_size,sizeof(uint32_t));
    memcpy(superbloque+sizeof(uint32_t),&block_amount,sizeof(uint32_t));
    int offset = 2*sizeof(uint32_t);
    bool estado = 0;
    for(int i = 0; i<block_amount;i++){
        memcpy(superbloque+offset,&estado,sizeof(bool));
        offset+=sizeof(bool);
    }
    msync(superbloque,2*sizeof(uint32_t)+block_amount,0);
}

🐛 Cómo reproducir el error

1- Borro el punto montaje si ya existe 2- Ejecuto el programa

💻 Logs

El output que conseguí al ejecutar un script que hace make y ejecuta con valgrind fue el siguiente: gcc -c -o obj/i-mongo-store-lib.o src/i-mongo-store-lib.c -I./include -I../shared/include -g -Wall

src/i-mongo-store-lib.c: In function 'inicializar_superbloque': src/i-mongo-store-lib.c:103:2: warning: implicit declaration of function 'fallocate' [-Wimplicit-function-declaration] fallocate(fd,0,0,2*sizeof(uint32_t)+block_amount); ^ gcc -o i-mongo-store obj/i-mongo-store.o obj/i-mongo-store-lib.o ../shared/obj/shared_utils.o -I./include -I../shared/include -g -Wall -lcommons -lpthread -lreadline -lcunit -lrt ==8073== Memcheck, a memory error detector ==8073== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==8073== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info ==8073== Command: ./i-mongo-store cfg/i-mongo-store.config cfg/i-mongo-store.log ==8073== [INFO] 19:42:33:867 I-MONGO-STORE/(8073:8073): FILESYSTEM INICIALIZADO DE 0 CON EXITO [INFO] 19:42:33:970 I-MONGO-STORE/(8073:8073): SERVIDOR LEVANTADO! ESCUCHANDO EN 5002

Y, al finalizar el módulo lo que tiró valgrind no fue muy relevante: (finalicé con SIGINT, quedaron bloques sin liberar).

Gracias y espero que me puedan dar una mano :D

iago64 commented 3 years ago

Buenas! como va?

El código para guardar la info no parece estar mal (no soy un compilador humano, tendria que sentarme a revisarlo en detalle) pero rapidamente se me ocurre preguntarte, con que tamaño te esta quedando el archivo al final? porque me parece que por ahi puede venir el problema. Una forma super rápida de ver si todo va bien con el archivo es usar la función fstat() que te devuelve la info y si no en lugar de fallocate(), podes probar con ftruncate().

Saludos.-

RaniAgus commented 3 years ago

︎¡Buenas! Dos cositas:

  1. Fijate que te tira un warning de implicit declaration of function 'fallocate' [-Wimplicit-function-declaration], si te fijás en el manpage de fallocate también hay que definir una macro:

    #define _GNU_SOURCE             /* See feature_test_macros(7) */

    Eso debería quitar el warning, y probablemente sea el problema, el resto del código lo veo bien

  2. Ojo con los tamaños de los tipos, vos estás haciendo:

    memcpy(superbloque+offset,&estado,sizeof(bool));

    Pero como la memoria se maneja de a bytes, sizeof(bool) retorna 1, lo cual significa un byte y no un bit. Para poder implementar un bitmap de forma segura y trabajarlo a nivel bit te recomiendo el TAD bitarray de las commons: bitarray.h

Lo mismo aplica para el block_amount:

fallocate(fd,0,0,2*sizeof(uint32_t)+block_amount);

Saludos

julchat commented 3 years ago

En el i-mongo-store-lib.c:

include "i-mongo-store-lib.h"

En i-mongo-store-lib.h ahora tengo al principio:

ifndef I_MONGO_STORE_LIB_H

define I_MONGO_STORE_LIB_H

define _GNU_SOURCE

y más abajo agregué ahora:

include <sys/stat.h>

Al agregar el define con el gnu source como señalaste, el warning se solucionó, pero el archivo de superbloque.ims quedó igual. Algo que noté, es que al abrirlo con otro editor de texto o el vs code, aparecieron algunas lineas:

(linea vacia) ??? ????????????

literalmente (?)

Me puse a pensar, los dos primeros elementos del archivo deberían ser 2 enteros de 4 bytes, con valor de 10. El editor de texto debería entender los bytes como ASCII

Lo que debería tener en mis archivos, por los enteros en BCD, calculo que debería ser algo así: 0000 0000 0001 0000 (Primer 10) 0000 0000 0001 0000 (Segundo 10) 0000 0000 (booleano en 0, 10 veces, por el bitmap - que acá en realidad es un bytemap, tengo que implementar lo que dijiste del bitarray.h-)

Capaz me estoy yendo de las ramas pero usando la tabla de ASCII esto sería: NULL LF NULL LF NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL

Donde LF (Line fill) tengo entendido que salta de línea, y bueno, NULL es el no caracter.

Sigue siendo un poco distinto a lo que me muestran.

Probé también con ftruncate como indicó Damián, pero lo mismo.

Agregué un par de líneas para utilizar fstat. El buffer de informacion de estadistica que devuelve tiene muchos campos, solo supe interpretar el de block size y el de cantidad de bloques:

struct stat *algo = malloc(sizeof(struct stat));
    int resultado = fstat(fd, algo);
    if(resultado ==-1){
        log_error(logger_i_mongo_store, "no anduvo fstat");
    }
    else{
        log_info(logger_i_mongo_store,"cant bloques: %d, tam bloques: %d, ",algo->st_blocks,algo->st_blksize);
    }

a lo que se logeó:

[INFO] 17:20:09:293 I-MONGO-STORE/(5780:5780): cant bloques: 8, tam bloques: 4096,
[INFO] 17:20:09:399 I-MONGO-STORE/(5780:5780): FILESYSTEM INICIALIZADO DE 0 CON EXITO

El 4096 supongo que es porque toma el tamaño de bloque del archivo en el fs de Linux el cual sería 4KB, pero el 8 no lo se interpetar.

También esto se está haciendo muy técnico y capaz lleva a ver mas el código, para lo que sería más cómodo que el sábado de soporte / cuando haya un ayudante durante la semana analicemos mas con detalle el código. De todas formas gracias!

Saludos

RaniAgus commented 3 years ago

También esto se está haciendo muy técnico y capaz lleva a ver mas el código, para lo que sería más cómodo que el sábado de soporte / cuando haya un ayudante durante la semana analicemos mas con detalle el código.

Coincido :P

  1. Mientras tanto, algo que te puede ayudar a revisar de mejor forma el contenido del stream mapeado a memoria en ejecución es usar las funciones de memory.h para mostrar ese contenido por pantalla o en un log. Para revisar el archivo en disco el comando hexdump -C muestra el contenido exactamente de la misma manera.

  2. En cuanto al retorno de fstat(), las manpages de esa función te pueden ayudar: https://linux.die.net/man/2/fstat

julchat commented 3 years ago

Ok! Las pruebo y pregunto por soporte! Muchas gracias