On Wed, Jan 23, 2008 at 12:12:25PM -0500, Jeff Dike wrote:
> Major changes since version 2 -

Also forgot to tell git about a couple of new files, without which
this totally won't work.

Below is mm/mfs.c - just drop it into your tree.

                                Jeff

-- 
Work email - jdike at linux dot intel dot com

#define __FRAME_OFFSETS
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/mount.h>
#include <linux/sched.h>
#include <asm/mmu_context.h>
#include <asm/ptrace.h>
#include <asm/uaccess.h>
#include <asm/user.h>

static int release_mm(struct inode *inode, struct file *file)
{
        struct mm_struct *mm = file->private_data;

        mmput(mm);
        return 0;
}

#define MM_MAGIC 0xE0AAC500

static int mm_get_sb(struct file_system_type *fs_type,
                     int flags, const char *dev_name, void *data,
                     struct vfsmount *mnt)
{
        return get_sb_pseudo(fs_type, "mm:", NULL, MM_MAGIC, mnt);
}

static struct vfsmount *mm_mnt;

static struct file_system_type mm_fs_type = {
        .name           = "mm",
        .get_sb         = mm_get_sb,
        .kill_sb        = kill_anon_super,
};

static int __init init_mm_fs(void)
{
        int err;

        err = register_filesystem(&mm_fs_type);
        if (err)
                return err;

        mm_mnt = kern_mount(&mm_fs_type);
        if (IS_ERR(mm_mnt)) {
                err = PTR_ERR(mm_mnt);
                unregister_filesystem(&mm_fs_type);
        }

        return err;
}

static void __exit exit_mm_fs(void)
{
        unregister_filesystem(&mm_fs_type);
        mntput(mm_mnt);
}

fs_initcall(init_mm_fs);
module_exit(exit_mm_fs);

static int mm_delete_dentry(struct dentry *dentry)
{
        /*
         * At creation time, we pretended this dentry was hashed
         * (by clearing DCACHE_UNHASHED bit in d_flags)
         * At delete time, we restore the truth : not hashed.
         * (so that dput() can proceed correctly)
         */
        dentry->d_flags |= DCACHE_UNHASHED;
        return 0;
}

/*
 * pipefs_dname() is called from d_path().
 */
static char *mm_dname(struct dentry *dentry, char *buffer, int buflen)
{
        return dynamic_dname(dentry, buffer, buflen, "mm:[%lu]",
                             dentry->d_inode->i_ino);
}

static struct dentry_operations mm_dentry_operations = {
        .d_delete       = mm_delete_dentry,
        .d_dname        = mm_dname,
};

static struct file_operations mm_fops = {
        .release        = release_mm,
};

#define MM_FLAGS_MASK 1
#define MM_INIT_MASK 1

#define MM_COPY 0
#define MM_EMPTY 1

asmlinkage long sys_new_mm(int flags)
{
        struct file *file;
        struct mm_struct *mm;
        struct inode *inode;
        struct dentry *dentry;
        struct qstr name = { .name = "" };
        int err, fd;

        if ((flags & ~MM_FLAGS_MASK) != 0)
                return -EINVAL;

        if ((flags & MM_INIT_MASK) == MM_COPY) {
                mm = dup_mm(current);
                if (mm == NULL)
                        return -ENOMEM;
        }
        else
                return -EINVAL;

        fd = get_unused_fd();
        if (fd < 0) {
                err = fd;
                goto out_free;
        }

        err = -ENOMEM;
        dentry = d_alloc(mm_mnt->mnt_sb->s_root, &name);
        if (dentry == NULL)
                goto out_put;

        dentry->d_op = &mm_dentry_operations;
        dentry->d_flags &= ~DCACHE_UNHASHED;

        inode = new_inode(mm_mnt->mnt_sb);
        if (inode == NULL)
                goto out_dput;

        inode->i_mode = S_IRUSR;
        inode->i_uid = current->fsuid;
        inode->i_gid = current->fsgid;
        inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;

        d_instantiate(dentry, inode);

        file = alloc_file(mm_mnt, dentry, FMODE_READ, &mm_fops);
        if (file == NULL)
                goto out_dput;

        file->f_flags = O_RDONLY;
        file->private_data = mm;

        fd_install(fd, file);

        return fd;

 out_dput:
        dput(dentry);
 out_put:
        put_unused_fd(fd);
 out_free:
        mmput(mm);
        return err;
}

extern const struct file_operations proc_pid_mm_operations;

/* Returns with an extra reference on mm */
struct mm_struct *fd_to_mm(int fd)
{
        struct mm_struct *mm;
        struct file *file = fget(fd);

        if (!file)
                return ERR_PTR(-EBADF);

        if ((file->f_op != &mm_fops) &&
            (file->f_op != &proc_pid_mm_operations))
                mm = ERR_PTR(-EINVAL);
        else {
                mm = file->private_data;
                atomic_inc(&mm->mm_users);
        }

        fput(file);

        return mm;
}

void do_switch(struct task_struct *task, struct mm_struct *mm)
{
        struct mm_struct *old = task->mm;

        task_lock(task);

        atomic_inc(&mm->mm_users);
        task->mm = mm;
        task->active_mm = mm;

        if(task == current)
                switch_mm(old, task->mm, task);

        task_unlock(task);

        mmput(old);
}

#define MM_SWITCH_MASK 3
#define MM_REGS_MASK 3

#define MM_ALL_REGS 0
#define MM_SP_IP 1
#define MM_SAME 2

long do_switch_mm(int fd, unsigned long flags, long __user *new,
                  long __user *save, struct pt_regs *regs)
{
        struct user_regs new_regs;
        struct mm_struct *old_mm, *new_mm;
        int regs_init, ret = 0;

        if ((flags & ~MM_SWITCH_MASK) != 0)
                return -EINVAL;

        regs_init = flags & MM_SWITCH_MASK;
        if (regs_init > MM_SAME)
                return -EINVAL;

        old_mm = current->mm;
        if (old_mm == NULL)
                return -EINVAL;

        if ((new == NULL) && (regs_init != MM_SAME))
                return -EINVAL;
        if (copyin_user_regs(&new_regs, new))
                return -EFAULT;

        new_mm = fd_to_mm(fd);
        if (IS_ERR(new_mm))
                return PTR_ERR(new_mm);

        atomic_inc(&old_mm->mm_users);
        do_switch(current, new_mm);

        mmput(new_mm);

        if ((save != NULL) && pt_regs_to_ptrace(save, regs)) {
                do_switch(current, old_mm);
                ret = EFAULT;
                goto out;
        }

        if (regs_init == MM_SP_IP) {
                pt_regs_ip(*regs) = ptrace_ip(&new_regs);
                pt_regs_sp(*regs) = ptrace_sp(&new_regs);
        }
        else if (regs_init == MM_SAME)
                ret = 1;
        else
                ret = ptrace_to_pt_regs(regs, &new_regs);

 out:
        mmput(old_mm);
        return ret;
}

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
User-mode-linux-user mailing list
User-mode-linux-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/user-mode-linux-user

Reply via email to