]> rtime.felk.cvut.cz Git - can-eth-gw-linux.git/blobdiff - fs/hugetlbfs/inode.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial
[can-eth-gw-linux.git] / fs / hugetlbfs / inode.c
index c98d0665fa5c979ac26ed0c979c770cd2a68a99b..78bde32ea9518d3fffe72d24864b6959bb369781 100644 (file)
@@ -151,8 +151,8 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
 {
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
-       unsigned long start_addr;
        struct hstate *h = hstate_file(file);
+       struct vm_unmapped_area_info info;
 
        if (len & ~huge_page_mask(h))
                return -EINVAL;
@@ -173,39 +173,13 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
                        return addr;
        }
 
-       if (len > mm->cached_hole_size)
-               start_addr = mm->free_area_cache;
-       else {
-               start_addr = TASK_UNMAPPED_BASE;
-               mm->cached_hole_size = 0;
-       }
-
-full_search:
-       addr = ALIGN(start_addr, huge_page_size(h));
-
-       for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
-               /* At this point:  (!vma || addr < vma->vm_end). */
-               if (TASK_SIZE - len < addr) {
-                       /*
-                        * Start a new search - just in case we missed
-                        * some holes.
-                        */
-                       if (start_addr != TASK_UNMAPPED_BASE) {
-                               start_addr = TASK_UNMAPPED_BASE;
-                               mm->cached_hole_size = 0;
-                               goto full_search;
-                       }
-                       return -ENOMEM;
-               }
-
-               if (!vma || addr + len <= vma->vm_start) {
-                       mm->free_area_cache = addr + len;
-                       return addr;
-               }
-               if (addr + mm->cached_hole_size < vma->vm_start)
-                       mm->cached_hole_size = vma->vm_start - addr;
-               addr = ALIGN(vma->vm_end, huge_page_size(h));
-       }
+       info.flags = 0;
+       info.length = len;
+       info.low_limit = TASK_UNMAPPED_BASE;
+       info.high_limit = TASK_SIZE;
+       info.align_mask = PAGE_MASK & ~huge_page_mask(h);
+       info.align_offset = 0;
+       return vm_unmapped_area(&info);
 }
 #endif
 
@@ -608,11 +582,11 @@ static int hugetlbfs_migrate_page(struct address_space *mapping,
        int rc;
 
        rc = migrate_huge_page_move_mapping(mapping, newpage, page);
-       if (rc)
+       if (rc != MIGRATEPAGE_SUCCESS)
                return rc;
        migrate_page_copy(newpage, page);
 
-       return 0;
+       return MIGRATEPAGE_SUCCESS;
 }
 
 static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf)
@@ -923,7 +897,7 @@ static struct file_system_type hugetlbfs_fs_type = {
        .kill_sb        = kill_litter_super,
 };
 
-static struct vfsmount *hugetlbfs_vfsmount;
+static struct vfsmount *hugetlbfs_vfsmount[HUGE_MAX_HSTATE];
 
 static int can_do_hugetlb_shm(void)
 {
@@ -932,9 +906,22 @@ static int can_do_hugetlb_shm(void)
        return capable(CAP_IPC_LOCK) || in_group_p(shm_group);
 }
 
+static int get_hstate_idx(int page_size_log)
+{
+       struct hstate *h;
+
+       if (!page_size_log)
+               return default_hstate_idx;
+       h = size_to_hstate(1 << page_size_log);
+       if (!h)
+               return -1;
+       return h - hstates;
+}
+
 struct file *hugetlb_file_setup(const char *name, unsigned long addr,
                                size_t size, vm_flags_t acctflag,
-                               struct user_struct **user, int creat_flags)
+                               struct user_struct **user,
+                               int creat_flags, int page_size_log)
 {
        int error = -ENOMEM;
        struct file *file;
@@ -944,9 +931,14 @@ struct file *hugetlb_file_setup(const char *name, unsigned long addr,
        struct qstr quick_string;
        struct hstate *hstate;
        unsigned long num_pages;
+       int hstate_idx;
+
+       hstate_idx = get_hstate_idx(page_size_log);
+       if (hstate_idx < 0)
+               return ERR_PTR(-ENODEV);
 
        *user = NULL;
-       if (!hugetlbfs_vfsmount)
+       if (!hugetlbfs_vfsmount[hstate_idx])
                return ERR_PTR(-ENOENT);
 
        if (creat_flags == HUGETLB_SHMFS_INODE && !can_do_hugetlb_shm()) {
@@ -963,7 +955,7 @@ struct file *hugetlb_file_setup(const char *name, unsigned long addr,
                }
        }
 
-       root = hugetlbfs_vfsmount->mnt_root;
+       root = hugetlbfs_vfsmount[hstate_idx]->mnt_root;
        quick_string.name = name;
        quick_string.len = strlen(quick_string.name);
        quick_string.hash = 0;
@@ -971,7 +963,7 @@ struct file *hugetlb_file_setup(const char *name, unsigned long addr,
        if (!path.dentry)
                goto out_shm_unlock;
 
-       path.mnt = mntget(hugetlbfs_vfsmount);
+       path.mnt = mntget(hugetlbfs_vfsmount[hstate_idx]);
        error = -ENOSPC;
        inode = hugetlbfs_get_inode(root->d_sb, NULL, S_IFREG | S_IRWXUGO, 0);
        if (!inode)
@@ -1011,8 +1003,9 @@ out_shm_unlock:
 
 static int __init init_hugetlbfs_fs(void)
 {
+       struct hstate *h;
        int error;
-       struct vfsmount *vfsmount;
+       int i;
 
        error = bdi_init(&hugetlbfs_backing_dev_info);
        if (error)
@@ -1029,14 +1022,26 @@ static int __init init_hugetlbfs_fs(void)
        if (error)
                goto out;
 
-       vfsmount = kern_mount(&hugetlbfs_fs_type);
+       i = 0;
+       for_each_hstate(h) {
+               char buf[50];
+               unsigned ps_kb = 1U << (h->order + PAGE_SHIFT - 10);
 
-       if (!IS_ERR(vfsmount)) {
-               hugetlbfs_vfsmount = vfsmount;
-               return 0;
-       }
+               snprintf(buf, sizeof(buf), "pagesize=%uK", ps_kb);
+               hugetlbfs_vfsmount[i] = kern_mount_data(&hugetlbfs_fs_type,
+                                                       buf);
 
-       error = PTR_ERR(vfsmount);
+               if (IS_ERR(hugetlbfs_vfsmount[i])) {
+                       pr_err("hugetlb: Cannot mount internal hugetlbfs for "
+                               "page size %uK", ps_kb);
+                       error = PTR_ERR(hugetlbfs_vfsmount[i]);
+                       hugetlbfs_vfsmount[i] = NULL;
+               }
+               i++;
+       }
+       /* Non default hstates are optional */
+       if (!IS_ERR_OR_NULL(hugetlbfs_vfsmount[default_hstate_idx]))
+               return 0;
 
  out:
        kmem_cache_destroy(hugetlbfs_inode_cachep);
@@ -1047,13 +1052,19 @@ static int __init init_hugetlbfs_fs(void)
 
 static void __exit exit_hugetlbfs_fs(void)
 {
+       struct hstate *h;
+       int i;
+
+
        /*
         * Make sure all delayed rcu free inodes are flushed before we
         * destroy cache.
         */
        rcu_barrier();
        kmem_cache_destroy(hugetlbfs_inode_cachep);
-       kern_unmount(hugetlbfs_vfsmount);
+       i = 0;
+       for_each_hstate(h)
+               kern_unmount(hugetlbfs_vfsmount[i++]);
        unregister_filesystem(&hugetlbfs_fs_type);
        bdi_destroy(&hugetlbfs_backing_dev_info);
 }