umountのMNT_EXPIRE
MNT_EXPIREは、2回umountをコールする事で実現され、その間に、そのファイルシステムの参照があればumountできません。
サンプル
サンプル
#include <sys/syscall.h>
#include <stdio.h>
#include <sys/mount.h>
void main(int argc, char* argv[])
{
if(!syscall(SYS_umount2, "/mnt3", MNT_EXPIRE)) {
printf("umounted\n");
}
else {
printf("can not umount\n");
}
}
[root@localhost north]# mount -o loop disk /mnt3
[root@localhost north]# ./a.out
can not umount
[root@localhost north]# ./a.out
umounted
[root@localhost north]# mount -o loop disk /mnt3
[root@localhost north]# ./a.out
can not umount
[root@localhost north]# touch /mnt3/babakaka
[root@localhost north]# ./a.out
can not umount
[root@localhost north]# ./a.out
umounted
flags=MNT_EXPIREでmnt->mnt_expiry_markが0なら、mnt->mnt_expiry_mark=1としエラー(-EAGAIN)となり、umountできません。
static int do_umount(struct mount *mnt, int flags)
{
struct super_block *sb = mnt->mnt.mnt_sb;
int retval;
LIST_HEAD(umount_list);
retval = security_sb_umount(&mnt->mnt, flags);
if (retval)
return retval;
if (flags & MNT_EXPIRE) {
if (&mnt->mnt == current->fs->root.mnt ||
flags & (MNT_FORCE | MNT_DETACH))
return -EINVAL;
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 (flags & MNT_FORCE && sb->s_op->umount_begin) {
sb->s_op->umount_begin(sb);
}
if (&mnt->mnt == current->fs->root.mnt && !(flags & MNT_DETACH)) {
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;
}
down_write(&namespace_sem);
br_write_lock(vfsmount_lock);
event++;
if (!(flags & MNT_DETACH))
shrink_submounts(mnt, &umount_list);
retval = -EBUSY;
if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) {
if (!list_empty(&mnt->mnt_list))
umount_tree(mnt, 1, &umount_list);
retval = 0;
}
br_write_unlock(vfsmount_lock);
up_write(&namespace_sem);
release_mounts(&umount_list);
return retval;
}
ptr=xとし、元のptrを返り値とします。
#define xchg(ptr, x) \
((__typeof__(*(ptr))) __xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
static inline
unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
{
unsigned long ret, flags;
switch (size) {
case 1:
#ifdef __xchg_u8
return __xchg_u8(x, ptr);
#else
local_irq_save(flags);
ret = *(volatile u8 *)ptr;
*(volatile u8 *)ptr = x;
local_irq_restore(flags);
return ret;
#endif /* __xchg_u8 */
case 2:
#ifdef __xchg_u16
return __xchg_u16(x, ptr);
#else
local_irq_save(flags);
ret = *(volatile u16 *)ptr;
*(volatile u16 *)ptr = x;
local_irq_restore(flags);
return ret;
#endif /* __xchg_u16 */
case 4:
#ifdef __xchg_u32
return __xchg_u32(x, ptr);
#else
local_irq_save(flags);
ret = *(volatile u32 *)ptr;
*(volatile u32 *)ptr = x;
local_irq_restore(flags);
return ret;
#endif /* __xchg_u32 */
#ifdef CONFIG_64BIT
case 8:
#ifdef __xchg_u64
return __xchg_u64(x, ptr);
#else
local_irq_save(flags);
ret = *(volatile u64 *)ptr;
*(volatile u64 *)ptr = x;
local_irq_restore(flags);
return ret;
#endif /* __xchg_u64 */
#endif /* CONFIG_64BIT */
default:
__xchg_called_with_bad_pointer();
return x;
}
}
パス検索でのdentry取得、及びファイルIDによるFILE取得時に、mntput()がコールされm->mnt_expiry_mark = 0とし、MNT_EXPIRでEのumountをできなくします。
void mntput(struct vfsmount *mnt)
{
if (mnt) {
struct mount *m = real_mount(mnt);
/* avoid cacheline pingpong, hope gcc doesn't get "smart" */
if (unlikely(m->mnt_expiry_mark))
m->mnt_expiry_mark = 0;
mntput_no_expire(m);
}
}
補足
私の環境のumountコマンドは、SYS_umountのoldumount()がコールされ、-Oオプションの設定ができませんでした。
SYSCALL_DEFINE1(oldumount, char __user *, name)
{
return sys_umount(name, 0);
}






