.release = mshare_release,
};
+void vma_rb_erase(struct vm_area_struct *vma, struct rb_root *root);
+
+static
+bool move_vmas(struct mm_struct *new_mm, unsigned long addr, unsigned long len)
+{
+ struct mm_struct *old_mm = current->mm;
+ struct vm_area_struct *vma, *next, *prev = NULL;
+ bool success = false;
+ int i = 0;
+
+ mmap_write_lock(old_mm);
+
+ /* Must not overlap end */
+ vma = find_vma(old_mm, addr + len);
+ if (vma && vma->vm_start < addr + len)
+ goto unlock;
+ vma = find_vma(old_mm, addr);
+ if (vma && vma->vm_start < addr)
+ goto unlock;
+ success = true;
+
+ if (vma)
+ prev = vma->vm_prev;
+ while (vma && vma->vm_start < addr + len) {
+ int ret;
+
+printk("found vma start %lx\n", vma->vm_start);
+ vma_rb_erase(vma, &old_mm->mm_rb);
+ old_mm->map_count--;
+
+ next = vma->vm_next;
+ ret = insert_vm_struct(new_mm, vma);
+ if (ret)
+ goto unlock;
+ /* XXX: VM_ACCOUNT? */
+ vm_stat_account(new_mm, vma->vm_flags, -vma_pages(vma));
+ vma = next;
+ }
+ if (prev)
+ prev->vm_next = vma;
+ if (vma)
+ vma->vm_prev = prev;
+
+ while (addr < new_mm->task_size) {
+ new_mm->pgd[i++] = *pgd_offset(old_mm, addr);
+ addr += PGDIR_SIZE;
+ }
+unlock:
+ mmap_write_unlock(old_mm);
+
+ return success;
+}
+
SYSCALL_DEFINE3(mshare, unsigned long, addr, unsigned long, len,
unsigned long, flags)
{
struct mm_struct *mm;
- struct vm_area_struct *vma;
+ struct file *file;
int fd;
- int i = 0;
if ((addr | len) & (PGDIR_SIZE - 1))
return -EINVAL;
if (!mm->task_size)
mm->task_size--;
- mmap_write_lock(current->mm);
-
- vma = find_vma(current->mm, addr + len);
- if (vma && vma->vm_start < addr + len)
- goto unlock;
- vma = find_vma(current->mm, addr);
- if (vma && vma->vm_start < addr)
- goto unlock;
-
- while (addr < mm->task_size) {
- mm->pgd[i++] = *pgd_offset(current->mm, addr);
- addr += PGDIR_SIZE;
- }
- mmap_write_unlock(current->mm);
-
- fd = anon_inode_getfd("mshare", &mshare_fops, mm, O_RDWR);
+ fd = get_unused_fd_flags(O_RDWR);
if (fd < 0)
- goto nofd;
+ goto out;
+ file = anon_inode_getfile("mshare", &mshare_fops, mm, O_RDWR);
+ if (IS_ERR(file))
+ goto nofile;
+
+ if (!move_vmas(mm, addr, len))
+ goto invalid;
+ fd_install(fd, file);
out:
return fd;
-unlock:
- mmap_write_unlock(current->mm);
- fd = -EINVAL;
-nofd:
+invalid:
+ fput(file);
+ file = ERR_PTR(-EINVAL);
+nofile:
+ put_unused_fd(fd);
+ fd = PTR_ERR(file);
mmput(mm);
goto out;
}