In order to back stacks with huge pages, we will want to make hugetlbfs files to back them; these will be used to back private mappings. Currently hugetlb_file_setup creates files to back shared memory segments. Modify this to create both private and shared files, and update callers to the new signatures. By not reserving requested huge pages for stack areas, we allow many programs to have vma's which total to more huge pages than available on the system without affecting eachother until they attempt to use all the pages. This will be the case with the proposed huge page backed stack patch in this series. Based on 2.6.25 Signed-off-by: Eric Munson --- fs/hugetlbfs/inode.c | 39 +++++++++++++++++++++++++-------------- include/linux/hugetlb.h | 16 ++++++++++++++-- ipc/shm.c | 3 ++- 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 6846785..8c0ba46 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -488,7 +488,8 @@ out: } static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, - gid_t gid, int mode, dev_t dev) + gid_t gid, int mode, dev_t dev, + unsigned long creat_flags) { struct inode *inode; @@ -504,7 +505,9 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; INIT_LIST_HEAD(&inode->i_mapping->private_list); info = HUGETLBFS_I(inode); - mpol_shared_policy_init(&info->policy, MPOL_DEFAULT, NULL); + if (creat_flags & HUGETLB_SHARED) + mpol_shared_policy_init(&info->policy, MPOL_DEFAULT, + NULL); switch (mode & S_IFMT) { default: init_special_inode(inode, mode, dev); @@ -545,7 +548,8 @@ static int hugetlbfs_mknod(struct inode *dir, } else { gid = current->fsgid; } - inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid, gid, mode, dev); + inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid, gid, mode, dev, + HUGETLB_SHARED | HUGETLB_RESERVE); if (inode) { dir->i_ctime = dir->i_mtime = CURRENT_TIME; d_instantiate(dentry, inode); @@ -581,7 +585,8 @@ static int hugetlbfs_symlink(struct inode *dir, gid = current->fsgid; inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid, - gid, S_IFLNK|S_IRWXUGO, 0); + gid, S_IFLNK|S_IRWXUGO, 0, + HUGETLB_SHARED | HUGETLB_RESERVE); if (inode) { int l = strlen(symname)+1; error = page_symlink(inode, symname, l); @@ -845,7 +850,8 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_op = &hugetlbfs_ops; sb->s_time_gran = 1; inode = hugetlbfs_get_inode(sb, config.uid, config.gid, - S_IFDIR | config.mode, 0); + S_IFDIR | config.mode, 0, + HUGETLB_SHARED | HUGETLB_RESERVE); if (!inode) goto out_free; @@ -910,7 +916,8 @@ static int can_do_hugetlb_shm(void) can_do_mlock()); } -struct file *hugetlb_file_setup(const char *name, size_t size) +struct file *hugetlb_file_setup(const char *name, size_t size, + unsigned long creat_flags) { int error = -ENOMEM; struct file *file; @@ -921,11 +928,13 @@ struct file *hugetlb_file_setup(const char *name, size_t size) if (!hugetlbfs_vfsmount) return ERR_PTR(-ENOENT); - if (!can_do_hugetlb_shm()) - return ERR_PTR(-EPERM); + if (creat_flags & HUGETLB_SHARED) { + if (!can_do_hugetlb_shm()) + return ERR_PTR(-EPERM); - if (!user_shm_lock(size, current->user)) - return ERR_PTR(-ENOMEM); + if (!user_shm_lock(size, current->user)) + return ERR_PTR(-ENOMEM); + } root = hugetlbfs_vfsmount->mnt_root; quick_string.name = name; @@ -936,13 +945,14 @@ struct file *hugetlb_file_setup(const char *name, size_t size) goto out_shm_unlock; error = -ENOSPC; - inode = hugetlbfs_get_inode(root->d_sb, current->fsuid, - current->fsgid, S_IFREG | S_IRWXUGO, 0); + inode = hugetlbfs_get_inode(root->d_sb, current->fsuid, current->fsgid, + S_IFREG | S_IRWXUGO, 0, creat_flags); if (!inode) goto out_dentry; error = -ENOMEM; - if (hugetlb_reserve_pages(inode, 0, size >> HPAGE_SHIFT)) + if ((creat_flags & HUGETLB_RESERVE) && + hugetlb_reserve_pages(inode, 0, size >> HPAGE_SHIFT)) goto out_inode; d_instantiate(dentry, inode); @@ -963,7 +973,8 @@ out_inode: out_dentry: dput(dentry); out_shm_unlock: - user_shm_unlock(size, current->user); + if (creat_flags & HUGETLB_SHARED) + user_shm_unlock(size, current->user); return ERR_PTR(error); } diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index addca4c..66b7a2b 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -165,12 +165,24 @@ static inline struct hugetlbfs_sb_info *HUGETLBFS_SB(struct super_block *sb) extern const struct file_operations hugetlbfs_file_operations; extern struct vm_operations_struct hugetlb_vm_ops; -struct file *hugetlb_file_setup(const char *name, size_t); +struct file *hugetlb_file_setup(const char *name, size_t, + unsigned long creat_flags); int hugetlb_get_quota(struct address_space *mapping, long delta); void hugetlb_put_quota(struct address_space *mapping, long delta); #define BLOCKS_PER_HUGEPAGE (HPAGE_SIZE / 512) +#define HUGETLB_SHARED 0x00000001UL /* Make the huge pages backed by the + * file being created shared */ + +#define HUGETLB_RESERVE 0x00000002UL /* Reserve the huge pages backed by the + * new file */ + +#define HUGETLB_STACK_FILE "hugetlb-stack" + +/* to align the pointer to the (next) huge page boundary */ +#define HPAGE_ALIGN(addr) (((addr)+HPAGE_SIZE-1)&HPAGE_MASK) + static inline int is_file_hugepages(struct file *file) { if (file->f_op == &hugetlbfs_file_operations) @@ -189,7 +201,7 @@ static inline void set_file_hugepages(struct file *file) #define is_file_hugepages(file) 0 #define set_file_hugepages(file) BUG() -#define hugetlb_file_setup(name,size) ERR_PTR(-ENOSYS) +#define hugetlb_file_setup(name,size,creat_flags) ERR_PTR(-ENOSYS) #endif /* !CONFIG_HUGETLBFS */ diff --git a/ipc/shm.c b/ipc/shm.c index cc63fae..38941eb 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -401,7 +401,8 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) sprintf (name, "SYSV%08x", key); if (shmflg & SHM_HUGETLB) { /* hugetlb_file_setup takes care of mlock user accounting */ - file = hugetlb_file_setup(name, size); + file = hugetlb_file_setup(name, size, + HUGETLB_SHARED | HUGETLB_RESERVE); shp->mlock_user = current->user; } else { int acctflag = VM_ACCOUNT;