1 Sistema de ficheros ext2 Ramírez Viera, Jesús Alberto Romero Santana, Samuel Llamadas al sistema read y write.

1 2 ...
Author: Xavier Aguirre Hidalgo
0 downloads 2 Views

1

2 1 Sistema de ficheros ext2 Ramírez Viera, Jesús Alberto Romero Santana, Samuel Llamadas al sistema read y write

3 2 Llamada al sistema read Uso y parámetros La llamada al sistema read realiza la lectura de datos desde un archivo Sus parámetros son: Descriptor del fichero que se va a leer Buffer donde se almacenarán los datos Número de bytes a leer Devuelve: Número de bytes que se consiguieron leer < 0 en caso de error

4 3 Esquema de funcionamiento del read Sys_Read Lock_kernel fgetLocks_verify_areareadfputunlock_kernel fcheckLocks_mandatory_area locks_remove_flock _fputremove_filpinsert_file_free

5 4 Llamada al sistema read fs/read_write.c asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count) { ssize_t ret; struct file * file; ssize_t (*read)(struct file *, char *, size_t, loff_t *); lock_kernel(); ret = -EBADF; file = fget(fd); if (!file) goto bad_file; if (!(file->f_mode & FMODE_READ)) goto out; Zona de exclusión mutua Obtenemos la estructura file a través del descriptor de fichero Si no existe estructura de fichero asociada, error Verificamos modo de lectura

6 5 Llamada al sistema read fs/read_write.c ret = locks_verify_area(FLOCK_VERIFY_READ, file- >f_dentry->d_inode,file, file->f_pos, count); if (ret) goto out; ret = -EINVAL; if (!file->f_op || !(read =.file->f_op->read)). goto out; ret = read(file, buf, count, &file->f_pos); out: fput(file); bad_file: unlock_kernel(); return ret; } Dejamos el descriptor de fichero Comprueba si existe bloqueo Si está bloqueada, sale (salta a out) Efectuamos la lectura usando la función que acabamos de obtener

7 6 fget & fcheck include/linux/file.h extern inline struct file * fget(unsigned int fd) { struct file * file = fcheck(fd); if (file) file->f_count++; return file; } extern inline struct file * fcheck(unsigned int fd) { struct file * file = NULL; if (fd files->max_fds) file = current->files->fd[fd]; return file; } Comprueba que el descriptor es válido (no se pasa del máximo) Chequea el descriptor de fichero Aumentamos el contador de accesos Asigna la estructura file asociada al descriptor

8 7 fput include/linux/file.h void fput(struct file *file) { int count = file->f_count-1; if (!count) { locks_remove_flock(file); __fput(file); file->f_count = 0; remove_filp(file); insert_file_free(file); } else file->f_count = count; } Disminuimos contador de accesos al fichero Si ya no se va a realizar ninguna operación en el fichero, se libera de la tabla de descriptores, para tener el descriptor de esa entrada, libre.

9 8 locks_verify_area include/linux/fs.h extern inline int locks_verify_area(int read_write, struct inode *inode, struct file *filp, loff_t offset, size_t count) { if (IS_MANDLOCK(inode) && (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) return (locks_mandatory_area(read_write, inode, filp, offset, count)); return (0); } Intenta bloquear ¿Se cumplen las condiciones para poder realizar el bloqueo?

10 9 locks_mandatory_area include/linux/fs.h int locks_mandatory_area(int read_write, struct inode *inode,struct file *filp, loff_t offset,size_t count) { struct file_lock *fl; struct file_lock tfl; memset(&tfl, 0, sizeof(tfl)); tfl.fl_file = filp; tfl.fl_flags = FL_POSIX | FL_ACCESS; tfl.fl_owner = current->files; tfl.fl_pid = current->pid; tfl.fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK; tfl.fl_start = offset; tfl.fl_end = offset + count - 1; Introducimos la información del nuevo nodo Reservamos memoria para el nuevo elemento de la lista de áreas bloqueadas

11 10 Locks_mandatory_area include/linux/fs.h repeat : for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { if (!(fl->fl_flags & FL_POSIX)) continue ; if (posix_locks_conflict(fl, &tfl)) {... locks_insert_block(fl, &tfl); interruptible_sleep_on(&tfl.fl_wait); locks_delete_block(fl, &tfl);... Si existe conflicto del tipo escritura contra bloqueo de lectura o lectura/escritura contra bloqueo de escritura,ponemos nuestro inodo en espera, y esperamos por que las condiciones de bloqueo desaparezcan

12 11 Estructuras include/linux/fs.h struct file {... struct file_operations *fop;... } struct file_operations { loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char *, size_t, loff_t *); ssize_t (*write) (struct file *, const char *, size_t, loff_t *); int (*readdir) (struct file *, void *, filldir_t);...} static struct file_operations ext2_file_operations = { // include/linux/file.c ext2_file_lseek,/* lseek */ generic_file_read,/* read */ ext2_file_write,/* write */... }

13 12 Esquema Read para el formato EXT2 generic_file_read do_generic_file_read page_hash _find_pagePage_cache_allocPage_cache_entry add_to_page_cache readpagepage_cache_release generic_readpage

14 13 generic_file_read /mm/filemap.c ssize_t generic_file_read(struct file * filp, char * buf, size_t count, loff_t *ppos) { ssize_t retval; retval = -EFAULT; if (access_ok(VERIFY_WRITE, buf, count)) { retval = 0; if (count) { read_descriptor_t desc; desc.written = 0; desc.count = count; desc.buf = buf; desc.error = 0; do_generic_file_read(filp, ppos, &desc, file_read_actor); retval = desc.written; if (!retval) retval = desc.error; }} return retval;} Introducimos la información pasada por parámetro, en la estructura que necesitará do_generic_file_read Número de bytes escritos, o error Comprobamos el área de memoria donde se escribirá la información

15 14 do_generic_file_read mm/filemap.c static void do_generic_file_read(struct file * filp, loff_t *ppos, read_descriptor_t * desc, read_actor_t actor) {... for (;;) { struct page *page, **hash; if (pos >= inode->i_size) break; hash = page_hash(inode, pos & PAGE_CACHE_MASK); page = __find_page(inode, pos & PAGE_CACHE_MASK, *hash);... Efectúa un bucle llamando a find_page, para buscar las páginas correspondientes a los datos a leer. Se busca en caché.

16 15 do_generic_file_read mm/filemap.c no_cached_page: if (!page_cache) { page_cache = page_cache_alloc(); if (page_cache) continue; desc->error = -ENOMEM; break;} page = page_cache_entry(page_cache); page_cache = 0; add_to_page_cache(page, inode, pos & PAGE_CACHE_MASK, hash); if (reada_ok && filp->f_ramax > MIN_READAHEAD) filp->f_ramax = MIN_READAHEAD;{ int error = inode->i_op->readpage(filp, page); if (!error) goto found_page; desc->error = error; page_cache_release(page); break;} Por último, leemos la página Si hay error, borramos la página de caché Buscamos espacio para alojar en caché una nueva página Añadimos la página a la caché

17 16 generic_readpage fs/buffer.c int generic_readpage(struct file * file, struct page * page) { atomic_inc(&page->count); i = PAGE_SIZE >> inode->i_sb->s_blocksize_bits; block = page->offset >> inode->i_sb->s_blocksize_bits; p = nr; do { *p = inode->i_op->bmap(inode, block); i--; block++; p++; } while (i > 0);... return 0; } No permite que la lectura se interrumpa por cualquier evento Obtenemos número de bloques a leer Vamos leyendo del inodo y dirección especificados

18 17 Estructuras de inodos mm/filemap.c struct dentry { unsigned long d_time;/* used by d_revalidate */ struct dentry_operations *d_op; struct super_block * d_sb;/* The root of the dentry tree */...} struct inode_operations { struct dentry * (*follow_link) (struct dentry *, struct dentry *, unsigned int); int (*readpage) (struct file *, struct page *); int (*writepage) (struct file *, struct page *);....}; struct inode_operations ext2_file_inode_operations = { generic_readpage,/* readpage */ ext2_bmap,/* bmap */ ext2_truncate,/* truncate */ ext2_permission,/* permission */ NULL/* smap */...};

19 18 Llamada al sistema write · Uso y parámetros Sus parámetros son: Descriptor del fichero que se va a escribir Buffer donde están los datos a escribir Número de bytes a escribir Devuelve: Número de bytes que se consiguieron escribir < 0 en caso de error La llamada al sistema write realiza la escritura de datos desde un archivo

20 19 sys_write /fs/red_write.c asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count) { ssize_t ret; struct file * file; struct inode * inode; ssize_t (*write)(struct file *, const char *, size_t, loff_t *); lock_kernel(); ret = -EBADF; file = fget(fd); if (!file) goto bad_file; if (!(file->f_mode & FMODE_WRITE)) goto out; Exclusión mutuaTomamos descriptor Comprobamos el permiso de escritura

21 20 sys_write /fs/red_write.c inode = file->f_dentry->d_inode; ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,file->f_pos, count); if (ret) goto out; ret = -EINVAL; if (!file->f_op || !(write = file->f_op->write)) goto out; down(&inode->i_sem); ret = write(file, buf, count, &file->f_pos); up(&inode->i_sem); out: fput(file); bad_file: unlock_kernel(); return ret; } Tomamos función para realizar escritura en EXT2 Controlamos el problema de los lectores / escritores Liberamos descriptorRealizamos escritura La sección a escribir no está bloqueada

22 21 Ext2_file_write fs/ext2/file.c static ssize_t ext2_file_write (struct file * filp, const char * buf, size_t count, loff_t *ppos) {... if (!count) return 0; if (((signed) count) < 0) return -EINVAL; write_error = buffercount = 0; if (!inode) { printk("ext2_file_write: inode = NULL\n"); return -EINVAL; } sb = inode->i_sb; if (sb->s_flags & MS_RDONLY) return -ENOSPC; Comprobamos que existe un inodo asociado al fichero Comprobamos que no es de solo lectura Comprobamos valor del count (bytes a escribir)

23 22 Ext2_file_write fs/ext2/file.c if (!S_ISREG(inode->i_mode)) { ext2_warning (sb, "ext2_file_write", "mode = %07o", inode->i_mode); return -EINVAL; } remove_suid(inode); if (filp->f_flags & O_APPEND) pos = inode->i_size; else { pos = *ppos; if (pos != *ppos) return -EINVAL; } Borrar del inode setgid setuid Comprobamos permiso de escritura Flag de añadir al fichero Escribimos en una posición determinada

24 23 Ext2_file_write fs/ext2/file.c if (((unsigned) pos) >= 0x7FFFFFFFUL) return -EFBIG; if (((unsigned) pos + count) > 0x7FFFFFFFUL) { count = 0x7FFFFFFFL - pos; if (((signed) count) < 0) return -EFBIG;... Se chequean el resto de parámetros... La posición a escribir no sobrepasa el máximo Los bytes a escribir no sobrepasan el máximo

25 24 ext2_file_write fs/ext2/file.c do { bh = ext2_getblk (inode, block, 1, &err); if (!bh) { if (!written) written = err; break; } if (c > count) c = count; set_bit(BH_Lock, &bh->b_state); c -= copy_from_user (bh->b_data + offset, buf, c); if (c != sb->s_blocksize) { c = 0; unlock_buffer(bh); brelse(bh); if (!written) written = -EFAULT;} mark_buffer_uptodate(bh, 1); unlock_buffer(bh); Bucle de escritura mientras queden datos por escribir Copia datos a la memoria intermedia. Si hubo error, devuelve el número de bytes No se ha podido escribir nada Obtenemos memoria intermedia donde se irá copiando la información que después se escribirá C indica los bytes q se copian en cada iteración. (Tamaño de bloque). La última iteración puede ser diferente

26 25 ext2_file_write fs/ext2/file.c mark_buffer_dirty(bh, 0);... pos += c; written += c; buf += c; count -= c;... block++; offset = 0; c = sb->s_blocksize; } while (count); Actualizamos contadores Marca la memoria como modificada Número de bloques copiados Actualizamos c (bytes que se copian en cada iteración)

27 26 ext2_file_write fs/ext2/file.c if (pos > inode->i_size) inode->i_size = pos; inode->i_ctime = inode->i_mtime = CURRENT_TIME; *ppos = pos; mark_inode_dirty(inode); return written; } Si se aumentó el tamaño del fichero, se actualiza Actualizamos información del inodo Marcamos inodo como modificado