mm/hugetlbfs: unmap pages if page fault raced with hole punch
[linux-2.6-microblaze.git] / fs / namespace.c
index 0570729..a830e14 100644 (file)
@@ -1584,6 +1584,14 @@ static inline bool may_mount(void)
        return ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN);
 }
 
+static inline bool may_mandlock(void)
+{
+#ifndef        CONFIG_MANDATORY_FILE_LOCKING
+       return false;
+#endif
+       return capable(CAP_SYS_ADMIN);
+}
+
 /*
  * Now umount can handle mount points as well as block devices.
  * This is important for filesystems which use unnamed block devices.
@@ -2601,18 +2609,18 @@ static long exact_copy_from_user(void *to, const void __user * from,
        return n;
 }
 
-int copy_mount_options(const void __user * data, unsigned long *where)
+void *copy_mount_options(const void __user * data)
 {
        int i;
-       unsigned long page;
        unsigned long size;
+       char *copy;
 
-       *where = 0;
        if (!data)
-               return 0;
+               return NULL;
 
-       if (!(page = __get_free_page(GFP_KERNEL)))
-               return -ENOMEM;
+       copy = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!copy)
+               return ERR_PTR(-ENOMEM);
 
        /* We only care that *some* data at the address the user
         * gave us is valid.  Just in case, we'll zero
@@ -2623,15 +2631,14 @@ int copy_mount_options(const void __user * data, unsigned long *where)
        if (size > PAGE_SIZE)
                size = PAGE_SIZE;
 
-       i = size - exact_copy_from_user((void *)page, data, size);
+       i = size - exact_copy_from_user(copy, data, size);
        if (!i) {
-               free_page(page);
-               return -EFAULT;
+               kfree(copy);
+               return ERR_PTR(-EFAULT);
        }
        if (i != PAGE_SIZE)
-               memset((char *)page + i, 0, PAGE_SIZE - i);
-       *where = page;
-       return 0;
+               memset(copy + i, 0, PAGE_SIZE - i);
+       return copy;
 }
 
 char *copy_mount_string(const void __user *data)
@@ -2677,6 +2684,8 @@ long do_mount(const char *dev_name, const char __user *dir_name,
                                   type_page, flags, data_page);
        if (!retval && !may_mount())
                retval = -EPERM;
+       if (!retval && (flags & MS_MANDLOCK) && !may_mandlock())
+               retval = -EPERM;
        if (retval)
                goto dput_out;
 
@@ -2896,7 +2905,7 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
        int ret;
        char *kernel_type;
        char *kernel_dev;
-       unsigned long data_page;
+       void *options;
 
        kernel_type = copy_mount_string(type);
        ret = PTR_ERR(kernel_type);
@@ -2908,14 +2917,14 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
        if (IS_ERR(kernel_dev))
                goto out_dev;
 
-       ret = copy_mount_options(data, &data_page);
-       if (ret < 0)
+       options = copy_mount_options(data);
+       ret = PTR_ERR(options);
+       if (IS_ERR(options))
                goto out_data;
 
-       ret = do_mount(kernel_dev, dir_name, kernel_type, flags,
-               (void *) data_page);
+       ret = do_mount(kernel_dev, dir_name, kernel_type, flags, options);
 
-       free_page(data_page);
+       kfree(options);
 out_data:
        kfree(kernel_dev);
 out_dev:
@@ -2939,9 +2948,9 @@ bool is_path_reachable(struct mount *mnt, struct dentry *dentry,
        return &mnt->mnt == root->mnt && is_subdir(dentry, root->dentry);
 }
 
-int path_is_under(struct path *path1, struct path *path2)
+bool path_is_under(struct path *path1, struct path *path2)
 {
-       int res;
+       bool res;
        read_seqlock_excl(&mount_lock);
        res = is_path_reachable(real_mount(path1->mnt), path1->dentry, path2);
        read_sequnlock_excl(&mount_lock);