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;
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;
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
+ unsigned long start_addr;
if (len & ~HPAGE_MASK)
return -EINVAL;
return addr;
}
- addr = ALIGN(mm->free_area_cache, HPAGE_SIZE);
+ start_addr = mm->free_area_cache;
+
+full_search:
+ addr = ALIGN(start_addr, HPAGE_SIZE);
for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
/* At this point: (!vma || addr < vma->vm_end). */
- if (TASK_SIZE - len < addr)
+ 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;
+ goto full_search;
+ }
return -ENOMEM;
+ }
+
if (!vma || addr + len <= vma->vm_start)
return addr;
addr = ALIGN(vma->vm_end, HPAGE_SIZE);
return -EINVAL;
}
-void huge_pagevec_release(struct pagevec *pvec)
+static void huge_pagevec_release(struct pagevec *pvec)
{
int i;
pagevec_reinit(pvec);
}
-void truncate_huge_page(struct page *page)
+static void truncate_huge_page(struct page *page)
{
clear_page_dirty(page);
ClearPageUptodate(page);
put_page(page);
}
-void truncate_hugepages(struct address_space *mapping, loff_t lstart)
+static void truncate_hugepages(struct address_space *mapping, loff_t lstart)
{
const pgoff_t start = lstart >> HPAGE_SHIFT;
struct pagevec pvec;
hlist_del_init(&inode->i_hash);
list_del_init(&inode->i_list);
+ list_del_init(&inode->i_sb_list);
inode->i_state |= I_FREEING;
inodes_stat.nr_inodes--;
spin_unlock(&inode_lock);
hlist_del_init(&inode->i_hash);
out_truncate:
list_del_init(&inode->i_list);
+ list_del_init(&inode->i_sb_list);
inode->i_state |= I_FREEING;
inodes_stat.nr_inodes--;
spin_unlock(&inode_lock);
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;
/*
* For direct-IO reads into hugetlb pages
*/
-int hugetlbfs_set_page_dirty(struct page *page)
+static int hugetlbfs_set_page_dirty(struct page *page)
{
return 0;
}
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;
sb->s_op = &hugetlbfs_ops;
+ sb->s_time_gran = 1;
inode = hugetlbfs_get_inode(sb, config.uid, config.gid,
S_IFDIR | config.mode, 0);
if (!inode)
*/
static unsigned long hugetlbfs_counter(void)
{
- static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+ static DEFINE_SPINLOCK(lock);
static unsigned long counter;
unsigned long ret;
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;
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;
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();
put_filp(file);
out_dentry:
dput(dentry);
+out_shm_unlock:
+ user_shm_unlock(size, current->user);
return ERR_PTR(error);
}
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;