#include <linux/pagevec.h>
#include <linux/parser.h>
#include <linux/mman.h>
-#include <linux/quotaops.h>
#include <linux/slab.h>
#include <linux/dnotify.h>
#include <linux/statfs.h>
#include <linux/security.h>
+#include <linux/magic.h>
#include <asm/uaccess.h>
-/* some random number */
-#define HUGETLBFS_MAGIC 0x958458f6
-
static const struct super_operations hugetlbfs_ops;
static const struct address_space_operations hugetlbfs_aops;
const struct file_operations hugetlbfs_file_operations;
static const struct inode_operations hugetlbfs_inode_operations;
static struct backing_dev_info hugetlbfs_backing_dev_info = {
+ .name = "hugetlbfs",
.ra_pages = 0, /* No readahead */
.capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
};
Opt_err,
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_size, "size=%s"},
{Opt_nr_inodes, "nr_inodes=%s"},
{Opt_mode, "mode=%o"},
if (hugetlb_reserve_pages(inode,
vma->vm_pgoff >> huge_page_order(h),
- len >> huge_page_shift(h), vma))
+ len >> huge_page_shift(h), vma,
+ vma->vm_flags))
goto out;
ret = 0;
for (;;) {
struct page *page;
unsigned long nr, ret;
+ int ra;
/* nr is the maximum number of bytes to copy from this page */
nr = huge_page_size(h);
*/
ret = len < nr ? len : nr;
if (clear_user(buf, ret))
- ret = -EFAULT;
+ ra = -EFAULT;
+ else
+ ra = 0;
} else {
/*
* We have the page, copy it to user space buffer.
*/
- ret = hugetlbfs_read_actor(page, offset, buf, len, nr);
+ ra = hugetlbfs_read_actor(page, offset, buf, len, nr);
+ ret = ra;
}
- if (ret < 0) {
+ if (ra < 0) {
if (retval == 0)
- retval = ret;
+ retval = ra;
if (page)
page_cache_release(page);
goto out;
return retval;
}
-/*
- * Read a page. Again trivial. If it didn't already exist
- * in the page cache, it is zero-filled.
- */
-static int hugetlbfs_readpage(struct file *file, struct page * page)
-{
- unlock_page(page);
- return -EINVAL;
-}
-
static int hugetlbfs_write_begin(struct file *file,
struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
static void hugetlbfs_forget_inode(struct inode *inode) __releases(inode_lock)
{
- struct super_block *sb = inode->i_sb;
-
- if (!hlist_unhashed(&inode->i_hash)) {
- if (!(inode->i_state & (I_DIRTY|I_SYNC)))
- list_move(&inode->i_list, &inode_unused);
- inodes_stat.nr_unused++;
- if (!sb || (sb->s_flags & MS_ACTIVE)) {
- spin_unlock(&inode_lock);
- return;
- }
- inode->i_state |= I_WILL_FREE;
- spin_unlock(&inode_lock);
- /*
- * write_inode_now is a noop as we set BDI_CAP_NO_WRITEBACK
- * in our backing_dev_info.
- */
- write_inode_now(inode, 1);
- spin_lock(&inode_lock);
- inode->i_state &= ~I_WILL_FREE;
- inodes_stat.nr_unused--;
- hlist_del_init(&inode->i_hash);
+ if (generic_detach_inode(inode)) {
+ truncate_hugepages(inode, 0);
+ clear_inode(inode);
+ destroy_inode(inode);
}
- 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);
- truncate_hugepages(inode, 0);
- clear_inode(inode);
- destroy_inode(inode);
}
static void hugetlbfs_drop_inode(struct inode *inode)
inode->i_mode = mode;
inode->i_uid = uid;
inode->i_gid = gid;
- inode->i_blocks = 0;
inode->i_mapping->a_ops = &hugetlbfs_aops;
inode->i_mapping->backing_dev_info =&hugetlbfs_backing_dev_info;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
INIT_LIST_HEAD(&inode->i_mapping->private_list);
info = HUGETLBFS_I(inode);
+ /*
+ * The policy is initialized here even if we are creating a
+ * private inode because initialization simply creates an
+ * an empty rb tree and calls spin_lock_init(), later when we
+ * call mpol_free_shared_policy() it will just return because
+ * the rb tree will still be empty.
+ */
mpol_shared_policy_init(&info->policy, NULL);
switch (mode & S_IFMT) {
default:
if (S_ISDIR(mode))
mode |= S_ISGID;
} else {
- gid = current->fsgid;
+ 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);
if (inode) {
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
d_instantiate(dentry, inode);
if (dir->i_mode & S_ISGID)
gid = dir->i_gid;
else
- gid = current->fsgid;
+ gid = current_fsgid();
- inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid,
+ inode = hugetlbfs_get_inode(dir->i_sb, current_fsuid(),
gid, S_IFLNK|S_IRWXUGO, 0);
if (inode) {
int l = strlen(symname)+1;
}
static const struct address_space_operations hugetlbfs_aops = {
- .readpage = hugetlbfs_readpage,
.write_begin = hugetlbfs_write_begin,
.write_end = hugetlbfs_write_end,
.set_page_dirty = hugetlbfs_set_page_dirty,
};
-static void init_once(struct kmem_cache *cachep, void *foo)
+static void init_once(void *foo)
{
struct hugetlbfs_inode_info *ei = (struct hugetlbfs_inode_info *)foo;
bad_val:
printk(KERN_ERR "hugetlbfs: Bad value '%s' for mount option '%s'\n",
args[0].from, p);
- return 1;
+ return -EINVAL;
}
static int
config.nr_blocks = -1; /* No limit on size by default */
config.nr_inodes = -1; /* No limit on number of inodes by default */
- config.uid = current->fsuid;
- config.gid = current->fsgid;
+ config.uid = current_fsuid();
+ config.gid = current_fsgid();
config.mode = 0755;
config.hstate = &default_hstate;
ret = hugetlbfs_parse_options(data, &config);
static int can_do_hugetlb_shm(void)
{
- return likely(capable(CAP_IPC_LOCK) ||
- in_group_p(sysctl_hugetlb_shm_group) ||
- can_do_mlock());
+ return capable(CAP_IPC_LOCK) || in_group_p(sysctl_hugetlb_shm_group);
}
-struct file *hugetlb_file_setup(const char *name, size_t size)
+struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag,
+ struct user_struct **user, int creat_flags)
{
int error = -ENOMEM;
struct file *file;
struct inode *inode;
- struct dentry *dentry, *root;
+ struct path path;
+ struct dentry *root;
struct qstr quick_string;
+ *user = NULL;
if (!hugetlbfs_vfsmount)
return ERR_PTR(-ENOENT);
- if (!can_do_hugetlb_shm())
- return ERR_PTR(-EPERM);
-
- if (!user_shm_lock(size, current->user))
- return ERR_PTR(-ENOMEM);
+ if (creat_flags == HUGETLB_SHMFS_INODE && !can_do_hugetlb_shm()) {
+ *user = current_user();
+ if (user_shm_lock(size, *user)) {
+ WARN_ONCE(1,
+ "Using mlock ulimits for SHM_HUGETLB deprecated\n");
+ } else {
+ *user = NULL;
+ return ERR_PTR(-EPERM);
+ }
+ }
root = hugetlbfs_vfsmount->mnt_root;
quick_string.name = name;
quick_string.len = strlen(quick_string.name);
quick_string.hash = 0;
- dentry = d_alloc(root, &quick_string);
- if (!dentry)
+ path.dentry = d_alloc(root, &quick_string);
+ if (!path.dentry)
goto out_shm_unlock;
+ path.mnt = mntget(hugetlbfs_vfsmount);
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);
if (!inode)
goto out_dentry;
error = -ENOMEM;
if (hugetlb_reserve_pages(inode, 0,
- size >> huge_page_shift(hstate_inode(inode)), NULL))
+ size >> huge_page_shift(hstate_inode(inode)), NULL,
+ acctflag))
goto out_inode;
- d_instantiate(dentry, inode);
+ d_instantiate(path.dentry, inode);
inode->i_size = size;
inode->i_nlink = 0;
error = -ENFILE;
- file = alloc_file(hugetlbfs_vfsmount, dentry,
- FMODE_WRITE | FMODE_READ,
+ file = alloc_file(&path, FMODE_WRITE | FMODE_READ,
&hugetlbfs_file_operations);
if (!file)
goto out_dentry; /* inode is already attached */
out_inode:
iput(inode);
out_dentry:
- dput(dentry);
+ path_put(&path);
out_shm_unlock:
- user_shm_unlock(size, current->user);
+ if (*user) {
+ user_shm_unlock(size, *user);
+ *user = NULL;
+ }
return ERR_PTR(error);
}