Hallo,
Erstmal besteht dieses Problem schon länger. Wenn ich etwas
auf einen USB-Stick kopiere (dritt hauptsächlich bei größeren
Dateien auf) und danach das Dateisystem mit umount aushänge
und dann sofort den USB-Stick abstecke, dann sind die letzten
geschriebenen Daten immer fehlerhaft.
Also irgendwie synchronisiert Linux bei umount nicht das Dateisystem
auf den USB-Stick.
Ich habe mir als Workaround zwischenzeitlich angewöhnt, bevor ich
den USB-Stick abstecke noch den Befehl sync einzugeben und zu
warten bis der Befehl erfolgreich ausgeführt wurde.
Der Nachteil ist hier allerdings, dass alle Geräte/Dateisysteme synchronisiert werden.
Beim schnellen Überfliegen vom Kernel-Code finde ich keine betreffende
Codezeile die vorher das Dateisystem synchronisiert. Kann aber auch sein,
dass ich im Code einfach etwas übersehe. :
Auszug aus /usr/src/linux/fs/namespace.c (Linux 3.12.59/openSUSE 13.1):
Erstmal besteht dieses Problem schon länger. Wenn ich etwas
auf einen USB-Stick kopiere (dritt hauptsächlich bei größeren
Dateien auf) und danach das Dateisystem mit umount aushänge
und dann sofort den USB-Stick abstecke, dann sind die letzten
geschriebenen Daten immer fehlerhaft.
Also irgendwie synchronisiert Linux bei umount nicht das Dateisystem
auf den USB-Stick.
Ich habe mir als Workaround zwischenzeitlich angewöhnt, bevor ich
den USB-Stick abstecke noch den Befehl sync einzugeben und zu
warten bis der Befehl erfolgreich ausgeführt wurde.
Der Nachteil ist hier allerdings, dass alle Geräte/Dateisysteme synchronisiert werden.
Beim schnellen Überfliegen vom Kernel-Code finde ich keine betreffende
Codezeile die vorher das Dateisystem synchronisiert. Kann aber auch sein,
dass ich im Code einfach etwas übersehe. :
Auszug aus /usr/src/linux/fs/namespace.c (Linux 3.12.59/openSUSE 13.1):
Code:
SYSCALL_DEFINE2(umount, char __user *, name, int, flags)
{
struct path path;
struct mount *mnt;
int retval;
int lookup_flags = 0;
if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW))
return -EINVAL;
if (!may_mount())
return -EPERM;
if (!(flags & UMOUNT_NOFOLLOW))
lookup_flags |= LOOKUP_FOLLOW;
retval = user_path_mountpoint_at(AT_FDCWD, name, lookup_flags, &path);
if (retval)
goto out;
mnt = real_mount(path.mnt);
retval = -EINVAL;
if (path.dentry != path.mnt->mnt_root)
goto dput_and_out;
if (!check_mnt(mnt))
goto dput_and_out;
if (mnt->mnt.mnt_flags & MNT_LOCKED)
goto dput_and_out;
retval = -EPERM;
if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN))
goto dput_and_out;
retval = do_umount(mnt, flags);
dput_and_out:
/* we mustn't call path_put() as that would clear mnt_expiry_mark */
dput(path.dentry);
mntput_no_expire(mnt);
out:
return retval;
}
Code:
static int do_umount(struct mount *mnt, int flags)
{
struct super_block *sb = mnt->mnt.mnt_sb;
int retval;
retval = security_sb_umount(&mnt->mnt, flags);
if (retval)
return retval;
/*
* Allow userspace to request a mountpoint be expired rather than
* unmounting unconditionally. Unmount only happens if:
* (1) the mark is already set (the mark is cleared by mntput())
* (2) the usage count == 1 [parent vfsmount] + 1 [sys_umount]
*/
if (flags & MNT_EXPIRE) {
if (&mnt->mnt == current->fs->root.mnt ||
flags & (MNT_FORCE | MNT_DETACH))
return -EINVAL;
/*
* probably don't strictly need the lock here if we examined
* all race cases, but it's a slowpath.
*/
br_write_lock(&vfsmount_lock);
if (mnt_get_count(mnt) != 2) {
br_write_unlock(&vfsmount_lock);
return -EBUSY;
}
br_write_unlock(&vfsmount_lock);
if (!xchg(&mnt->mnt_expiry_mark, 1))
return -EAGAIN;
}
/*
* If we may have to abort operations to get out of this
* mount, and they will themselves hold resources we must
* allow the fs to do things. In the Unix tradition of
* 'Gee thats tricky lets do it in userspace' the umount_begin
* might fail to complete on the first run through as other tasks
* must return, and the like. Thats for the mount program to worry
* about for the moment.
*/
if (flags & MNT_FORCE && sb->s_op->umount_begin) {
sb->s_op->umount_begin(sb);
}
/*
* No sense to grab the lock for this test, but test itself looks
* somewhat bogus. Suggestions for better replacement?
* Ho-hum... In principle, we might treat that as umount + switch
* to rootfs. GC would eventually take care of the old vfsmount.
* Actually it makes sense, especially if rootfs would contain a
* /reboot - static binary that would close all descriptors and
* call reboot(9). Then init(8) could umount root and exec /reboot.
*/
if (&mnt->mnt == current->fs->root.mnt && !(flags & MNT_DETACH)) {
/*
* Special case for "unmounting" root ...
* we just try to remount it readonly.
*/
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
down_write(&sb->s_umount);
if (!(sb->s_flags & MS_RDONLY))
retval = do_remount_sb(sb, MS_RDONLY, NULL, 0);
up_write(&sb->s_umount);
return retval;
}
namespace_lock();
br_write_lock(&vfsmount_lock);
event++;
if (!(flags & MNT_DETACH))
shrink_submounts(mnt);
retval = -EBUSY;
if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) {
if (!list_empty(&mnt->mnt_list))
umount_tree(mnt, 1);
retval = 0;
}
br_write_unlock(&vfsmount_lock);
namespace_unlock();
return retval;
}