1 Sistema de ficheros ext2 Ramírez Viera, Jesús Alberto Romero Santana, Samuel Llamadas al sistema...
-
Upload
xavier-aguirre-hidalgo -
Category
Documents
-
view
218 -
download
0
Transcript of 1 Sistema de ficheros ext2 Ramírez Viera, Jesús Alberto Romero Santana, Samuel Llamadas al sistema...
1
Sistema de ficheros ext2
Ramírez Viera, Jesús AlbertoRomero Santana, Samuel
Llamadas al sistema read y write
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
3
Esquema de funcionamiento del read
Sys_Read
Lock_kernel fget Locks_verify_area read fput unlock_kernel
fcheck Locks_mandatory_area
locks_remove_flock _fput remove_filp insert_file_free
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
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
6
fget & fcheckinclude/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 < current->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
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.
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?
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
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
11
Estructuras include/linux/fs.hstruct 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 */... }
12
Esquema Readpara el formato EXT2
generic_file_read
do_generic_file_read
page_hash _find_page Page_cache_alloc Page_cache_entry
add_to_page_cache readpage page_cache_release
generic_readpage
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
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é.
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é
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
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 */
...};
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
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 mutua
Tomamos descriptor
Comprobamos el permiso de escritura
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 descriptor
Realizamos escritura
La sección a escribir no está bloqueada
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)
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
23
Ext2_file_writefs/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
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
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)
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