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);
}

最終更新 2016/04/03 15:31:30 - north
(2013/12/12 17:45:41 作成)


検索

アクセス数
3588609
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。