Member of The Internet Defense League Últimos cambios
Últimos Cambios
Blog personal: El hilo del laberinto Geocaching

Grabación USB lenta con Linux

Última Actualización: 14 de julio de 2007 - Sábado

Recientemente me he comprado un dispositivo de almacenamiento USB en memoria flash y aunque el rendimiento en lectura es "razonable" (960KB/s, de un máximo teórico de 1.4MB/s), la escritura es muy lenta. En mi máquina SUSE 10.0, escribo en ese dispositivo a unos 200KB/s. Es decir, unas cinco veces más lento de lo que debería.

Lo primero es descartar que el dispositivo USB tenga algún tipo de defecto, cosa que se comprueba con facilidad conectando el dispositivo a una máquina Windows. La comprobación experimental fue grabar 30 megabytes en la memoria USB, proceso que supuso un minuto de tiempo, aproximadamente. Es decir, unos 500KB/s, poco más o menos.

Así pues, la grabación es bastante lenta, pero en mi linux Suse es incluso más lenta todavía. Desesperantemente lenta, de hecho. ¡¡Llenar el gigabyte de capacidad de la memoria USB me supone casi una hora y media!!.

Investigando el asunto con detenimiento y la ayuda de Google, veo que el problema es que el subsistema "submount", utilizado por SUSE y otras distribuciones Linux para gestionar dispositivos removibles como USB o CDs/DVDs, "monta" los dispositivos USB con la opción de "sync".

Utilizar la opción "sync" tiene su lógica para así poder desenchufar el USB sin necesidad de realizar una operación explícita en el GUI, como la típica aplicación de Windows para "desenchufar dispositivo de forma segura". En Linux SUSE (y posiblemente otras distribuciones que empleen "submount"), se puede desenchufar el USB directamente porque el dispositivo se monta con la opción "sync", que implica que cuando escribimos algo se fuerza inmediatamente al dispositivo, sin pasar por la caché interna del sistema previamente. Por tanto, en cuanto el ordenador nos dice que ha terminado de grabar algo, realmente ha terminado de grabar en el dispositivo. De verdad.

El problema es que "sync" implica escrituras síncronas en el USB o, lo que es lo mismo, no envía al dispositivo el bloque X hasta que éste no haya confirmado que ha almacenado correctamente el bloque X-1. Ello supone un gran desperdicio de ancho de banda USB (y por tanto, tiempo de grabación), a cambio de ganar comodidad y conveniencia. Asimismo, puede haber efectos de segundo orden debido a que las memorias flash tienen un número de escrituras limitados, y en modo síncrono un sector determinado puede reescribirse varias veces durante una sesión de grabación.

Para comprobar si es el caso en vuestros sistemas, probad a conectar un dispositivo de almacenamiento USB, montadlo (o dejad que lo haga el sistema, si es automático), y ved el resultado. En Linux SUSE 10.0, que utiliza "submount", parecerá algo parecido a:

# mount
...
/dev/sdb1 on /media/usbdisk type subfs (rw,nosuid,nodev,sync,fs=floppyfss,procuid,utf8=true)

El punto delicado es el "sync" resaltado en el listado anterior.

Una vez localizado el problema, la solución es muy simple. Basta con montar el dispositivo manualmente, pero indicándole que queremos utilizar escrituras asíncronas, más rápidas pero que exigen desconectar el USB de forma "controlada" (más sobre esto después).

La primera opción es desmontar el dispositivo y montarlo manualmente, con las opciones que nos interesan:

# mount
...
/dev/sdb1 on /media/usbdisk type subfs (rw,nosuid,nodev,sync,fs=floppyfss,procuid,utf8=true)
# umount /media/usbdisk
# mount -t subfs /dev/sdb1 /media/usbdisk -o rw,nosuid,nodev,fs=floppyfss,procuid,utf8=true
# mount
...
/dev/sdb1 on /media/usbdisk type subfs (rw,nosuid,nodev,fs=floppyfss,procuid,utf8=true)

En el ejemplo anterior primero vemos las opciones con las que se monta el dispositivo USB. Seguidamente lo desmontamos manualmente y lo volvemos a montar con las mismas opciones que acabamos de ver PERO eliminando el modo "sync". Volviendo a visualizar las opciones, vemos que ya no aparece "sync". Como debe ser.

Otra opción más limpia es utilizar las funcionalidades "remount" de los kernel Linux modernos, para realizar las operaciones de forma más simple:

# mount
...
/dev/sdb1 on /media/usbdisk type subfs (rw,nosuid,nodev,sync,fs=floppyfss,procuid,utf8=true)
# mount /media/usbdisk -o remount,async
# mount
...
/dev/sdb1 on /media/usbdisk type subfs (rw,nosuid,nodev,fs=floppyfss,procuid,utf8=true)

Usemos la opción que usemos, si nuestro sistema emplea "submount" (el tipo de ficheros "subfs", como se puede ver en los ejemplos anteriores), el sistema operativo desmontará automáticamente el dispositivo USB cuando lo desenchufemos, como siempre.

No obstante, ahora tenemos que asegurarnos de que los datos se han almacenado realmente en el dispositivo de almacenamiento USB, ya que ahora las escrituras pasan por la caché de disco interna de Linux. Para ello hay varias opciones. Por ejemplo, en el escritorio KDE de SUSE hay un menú para "desenchufar de forma segura", muy semejante a Windows (aunque con la configuración estándar de SUSE, al emplear escrituras síncronas, es innecesario). Otra opción, ya que tenemos una ventana de terminal abierta, es utilizar el comando "sync" de Unix para asegurarnos de que todos los datos modificados en la caché de escritura de Linux son volcados a los sistemas de almacenamiento del ordenador. Este comando puede tardar bastante tiempo en "terminar" (lo que tarde en grabar todo lo pendiente que mantenía en RAM, la caché), pero cuando acabe significará que no queda nada pendiente y podemos desenchufar el USB sin problemas.

Por tanto, utilizando un simple comando "mount /media/usbdisk -o remount,async" consigo pasar de grabar a una velocidad de 200KB/s a grabar a 560KB/s. Casi tres veces más rápido. E igual de rápido que con Windows.

Por supuesto las velocidades concretas dependerán de cada dispositivo USB. El mío es bastante "cutre", ya se ve, porque incluso a su velocidad de "pico" graba a la mitad de la capacidad del estándar USB 1.1. Pero menos da una piedra...

Pero vuelvo a reiterar: ¡mucho cuidado con asegurarnos de que todos los datos se han grabado en el dispositivo de almacenamiento USB ANTES de desenchufarlo del ordenador!. Recuerda utilizar el comando "sync" o similares, al terminar la grabación.

El único efecto secundario de trabajar en modo asíncrono, aparte de requerir que seamos cuidadosos, es que una vez que el sistema nos dice que ha terminado de grabar, todavía puede tardar varios minutos en completar realmente todas las operaciones pendientes que contenga en su caché en RAM. Y el acceso de lectura a un dispositivo USB mientras se está grabando en él a toda velocidad, suele ser bastante lento y poco cómodo. Por ejemplo, si durante la grabación pulsamos "cancelar", aún se pueden almacenar muchos megas adicionales y podemos tener que esperar fácilmente un minuto o dos hasta que realmente aborta la operación. Exactamente igual que en Windows...

Parche a nivel de sistema operativo

Más de un año después de haber escrito originariamente este artículo, he llegado por casualidad a una entrada del sistema de seguimiento de "bugs" de SUSE, que describe este problema y una posible solución temporal, mientras no se dispone de un parche oficial (a estas alturas, dudo que lo publiquen).

Lo que sigue es válido solo para SUSE 10.0.

Hay que añadir el siguiente fichero, en "/usr/share/hal/fdi/policy/20thirdparty/95-storage-nosync.fdi":

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- disable sync for mount -->
<deviceinfo version="0.2">
  <device>
  <match key="block.is_volume" bool="true">
  <match key="volume.fsusage" string="filesystem">
  <match key="@info.parent:storage.bus" string="usb">
    <merge key="volume.policy.mount_option.sync" type="bool">false</merge>
  </match>
  </match>
  </match>
  </device>
</deviceinfo>

Una vez creado el fichero, hay que reiniciar el ordenador o, si no se desea hacerlo, ejecutar "rchal restart".

A partir de ahora, todos los dispositivos de almacenamiento conectados por USB se montarán con la opción de grabación asíncrona de datos. Por tanto, la grabación será "rápida" pero, como antes, hay que asegurarse de hacer el "sync" al final, para garantizar que el dispositivo USB se ha actualizado por completo antes de desconectarlo.


Historia

  • 14/jul/07: Parche a nivel de sistema operativo.

  • 11/abr/06: Primera versión de este documento.



Python Zope ©2006-2007 jcea@jcea.es

Más información sobre los OpenBadges

Donación BitCoin: 19niBN42ac2pqDQFx6GJZxry2JQSFvwAfS