vserver 1.9.3
[linux-2.6.git] / fs / hugetlbfs / inode.c
index 4ec4283..6e7aeff 100644 (file)
@@ -52,6 +52,9 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
        loff_t len, vma_len;
        int ret;
 
+       if ((vma->vm_flags & (VM_MAYSHARE | VM_WRITE)) == VM_WRITE)
+               return -EINVAL;
+
        if (vma->vm_pgoff & (HPAGE_SIZE / PAGE_SIZE - 1))
                return -EINVAL;
 
@@ -70,10 +73,19 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
        file_accessed(file);
        vma->vm_flags |= VM_HUGETLB | VM_RESERVED;
        vma->vm_ops = &hugetlb_vm_ops;
+
+       ret = -ENOMEM;
+       len = vma_len + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
+       if (!(vma->vm_flags & VM_WRITE) && len > inode->i_size)
+               goto out;
+
        ret = hugetlb_prefault(mapping, vma);
-       len = vma_len + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
-       if (ret == 0 && inode->i_size < len)
+       if (ret)
+               goto out;
+
+       if (inode->i_size < len)
                inode->i_size = len;
+out:
        up(&inode->i_sem);
 
        return ret;
@@ -272,11 +284,10 @@ static void hugetlbfs_drop_inode(struct inode *inode)
 static inline void
 hugetlb_vmtruncate_list(struct prio_tree_root *root, unsigned long h_pgoff)
 {
-       struct vm_area_struct *vma = NULL;
+       struct vm_area_struct *vma;
        struct prio_tree_iter iter;
 
-       while ((vma = vma_prio_tree_next(vma, root, &iter,
-                                       h_pgoff, ULONG_MAX)) != NULL) {
+       vma_prio_tree_foreach(vma, &iter, root, h_pgoff, ULONG_MAX) {
                unsigned long h_vm_pgoff;
                unsigned long v_length;
                unsigned long v_offset;
@@ -640,6 +651,7 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent)
        sbinfo->free_blocks = config.nr_blocks;
        sbinfo->max_inodes = config.nr_inodes;
        sbinfo->free_inodes = config.nr_inodes;
+       sb->s_maxbytes = MAX_LFS_FILESIZE;
        sb->s_blocksize = HPAGE_SIZE;
        sb->s_blocksize_bits = HPAGE_SHIFT;
        sb->s_magic = HUGETLBFS_MAGIC;
@@ -721,12 +733,13 @@ static unsigned long hugetlbfs_counter(void)
 static int can_do_hugetlb_shm(void)
 {
        return likely(capable(CAP_IPC_LOCK) ||
-                       in_group_p(sysctl_hugetlb_shm_group));
+                       in_group_p(sysctl_hugetlb_shm_group) ||
+                       can_do_mlock());
 }
 
 struct file *hugetlb_zero_setup(size_t size)
 {
-       int error;
+       int error = -ENOMEM;
        struct file *file;
        struct inode *inode;
        struct dentry *dentry, *root;
@@ -739,6 +752,9 @@ struct file *hugetlb_zero_setup(size_t size)
        if (!is_hugepage_mem_enough(size))
                return ERR_PTR(-ENOMEM);
 
+       if (!user_shm_lock(size, current->user))
+               return ERR_PTR(-ENOMEM);
+
        root = hugetlbfs_vfsmount->mnt_root;
        snprintf(buf, 16, "%lu", hugetlbfs_counter());
        quick_string.name = buf;
@@ -746,7 +762,7 @@ struct file *hugetlb_zero_setup(size_t size)
        quick_string.hash = 0;
        dentry = d_alloc(root, &quick_string);
        if (!dentry)
-               return ERR_PTR(-ENOMEM);
+               goto out_shm_unlock;
 
        error = -ENFILE;
        file = get_empty_filp();
@@ -773,6 +789,8 @@ out_file:
        put_filp(file);
 out_dentry:
        dput(dentry);
+out_shm_unlock:
+       user_shm_unlock(size, current->user);
        return ERR_PTR(error);
 }
 
@@ -783,8 +801,7 @@ static int __init init_hugetlbfs_fs(void)
 
        hugetlbfs_inode_cachep = kmem_cache_create("hugetlbfs_inode_cache",
                                        sizeof(struct hugetlbfs_inode_info),
-                                       0, SLAB_RECLAIM_ACCOUNT,
-                                       init_once, NULL);
+                                       0, 0, init_once, NULL);
        if (hugetlbfs_inode_cachep == NULL)
                return -ENOMEM;