mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
Merge branch 'lineage-17.1' into followmsi-10
This commit is contained in:
commit
8c8560e60f
58 changed files with 1903 additions and 836 deletions
|
@ -59,7 +59,6 @@ prototypes:
|
|||
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
|
||||
ssize_t (*listxattr) (struct dentry *, char *, size_t);
|
||||
int (*removexattr) (struct dentry *, const char *);
|
||||
void (*truncate_range)(struct inode *, loff_t, loff_t);
|
||||
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len);
|
||||
void (*update_time)(struct inode *, struct timespec *, int);
|
||||
int (*atomic_open)(struct inode *, struct dentry *,
|
||||
|
@ -91,7 +90,6 @@ setxattr: yes
|
|||
getxattr: no
|
||||
listxattr: no
|
||||
removexattr: yes
|
||||
truncate_range: yes
|
||||
fiemap: no
|
||||
update_time: no
|
||||
atomic_open: yes
|
||||
|
|
|
@ -363,7 +363,6 @@ struct inode_operations {
|
|||
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
|
||||
ssize_t (*listxattr) (struct dentry *, char *, size_t);
|
||||
int (*removexattr) (struct dentry *, const char *);
|
||||
void (*truncate_range)(struct inode *, loff_t, loff_t);
|
||||
void (*update_time)(struct inode *, struct timespec *, int);
|
||||
int (*atomic_open)(struct inode *, struct dentry *, struct file *,
|
||||
unsigned open_flag, umode_t create_mode, int *opened);
|
||||
|
@ -476,9 +475,6 @@ otherwise noted.
|
|||
removexattr: called by the VFS to remove an extended attribute from
|
||||
a file. This method is called by removexattr(2) system call.
|
||||
|
||||
truncate_range: a method provided by the underlying filesystem to truncate a
|
||||
range of blocks , i.e. punch a hole somewhere in a file.
|
||||
|
||||
update_time: called by the VFS to update a specific time or the i_version of
|
||||
an inode. If this is not defined the VFS will update the inode itself
|
||||
and call mark_inode_dirty_sync.
|
||||
|
@ -780,7 +776,7 @@ struct file_operations
|
|||
----------------------
|
||||
|
||||
This describes how the VFS can manipulate an open file. As of kernel
|
||||
2.6.22, the following members are defined:
|
||||
3.5, the following members are defined:
|
||||
|
||||
struct file_operations {
|
||||
struct module *owner;
|
||||
|
@ -810,6 +806,8 @@ struct file_operations {
|
|||
int (*flock) (struct file *, int, struct file_lock *);
|
||||
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, size_t, unsigned int);
|
||||
ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned int);
|
||||
int (*setlease)(struct file *, long arg, struct file_lock **);
|
||||
long (*fallocate)(struct file *, int mode, loff_t offset, loff_t len);
|
||||
};
|
||||
|
||||
Again, all methods are called without any locks being held, unless
|
||||
|
@ -878,6 +876,11 @@ otherwise noted.
|
|||
splice_read: called by the VFS to splice data from file to a pipe. This
|
||||
method is used by the splice(2) system call
|
||||
|
||||
setlease: called by the VFS to set or release a file lock lease.
|
||||
setlease has the file_lock_lock held and must not sleep.
|
||||
|
||||
fallocate: called by the VFS to preallocate blocks or punch a hole.
|
||||
|
||||
Note that the file operations are implemented by the specific
|
||||
filesystem in which the inode resides. When opening a device node
|
||||
(character or block special) most filesystems will call special
|
||||
|
|
|
@ -350,7 +350,7 @@ struct io_cq *ioc_create_icq(struct request_queue *q, gfp_t gfp_mask)
|
|||
if (!icq)
|
||||
return NULL;
|
||||
|
||||
if (radix_tree_preload(gfp_mask) < 0) {
|
||||
if (radix_tree_maybe_preload(gfp_mask) < 0) {
|
||||
kmem_cache_free(et->icq_cache, icq);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/mm.h>
|
||||
|
@ -374,11 +375,12 @@ static int ashmem_shrink(struct shrinker *s, struct shrink_control *sc)
|
|||
return -1;
|
||||
|
||||
list_for_each_entry_safe(range, next, &ashmem_lru_list, lru) {
|
||||
struct inode *inode = range->asma->file->f_dentry->d_inode;
|
||||
loff_t start = range->pgstart * PAGE_SIZE;
|
||||
loff_t end = (range->pgend + 1) * PAGE_SIZE - 1;
|
||||
loff_t end = (range->pgend + 1) * PAGE_SIZE;
|
||||
|
||||
vmtruncate_range(inode, start, end);
|
||||
do_fallocate(range->asma->file,
|
||||
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
|
||||
start, end - start);
|
||||
range->purged = ASHMEM_WAS_PURGED;
|
||||
lru_del(range);
|
||||
|
||||
|
|
12
fs/9p/acl.c
12
fs/9p/acl.c
|
@ -37,7 +37,7 @@ static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, char *name)
|
|||
return ERR_PTR(-ENOMEM);
|
||||
size = v9fs_fid_xattr_get(fid, name, value, size);
|
||||
if (size > 0) {
|
||||
acl = posix_acl_from_xattr(value, size);
|
||||
acl = posix_acl_from_xattr(&init_user_ns, value, size);
|
||||
if (IS_ERR(acl))
|
||||
goto err_out;
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ static int v9fs_set_acl(struct dentry *dentry, int type, struct posix_acl *acl)
|
|||
buffer = kmalloc(size, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
retval = posix_acl_to_xattr(acl, buffer, size);
|
||||
retval = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
|
||||
if (retval < 0)
|
||||
goto err_free_out;
|
||||
switch (type) {
|
||||
|
@ -160,7 +160,7 @@ int v9fs_acl_chmod(struct dentry *dentry)
|
|||
return -EOPNOTSUPP;
|
||||
acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
|
||||
if (acl) {
|
||||
retval = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
retval = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = v9fs_set_acl(dentry, ACL_TYPE_ACCESS, acl);
|
||||
|
@ -199,7 +199,7 @@ int v9fs_acl_mode(struct inode *dir, umode_t *modep,
|
|||
if (acl) {
|
||||
if (S_ISDIR(mode))
|
||||
*dpacl = posix_acl_dup(acl);
|
||||
retval = posix_acl_create(&acl, GFP_NOFS, &mode);
|
||||
retval = __posix_acl_create(&acl, GFP_NOFS, &mode);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
if (retval > 0)
|
||||
|
@ -251,7 +251,7 @@ static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name,
|
|||
return PTR_ERR(acl);
|
||||
if (acl == NULL)
|
||||
return -ENODATA;
|
||||
error = posix_acl_to_xattr(acl, buffer, size);
|
||||
error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
|
||||
posix_acl_release(acl);
|
||||
|
||||
return error;
|
||||
|
@ -304,7 +304,7 @@ static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
|
|||
return -EPERM;
|
||||
if (value) {
|
||||
/* update the cached acl value */
|
||||
acl = posix_acl_from_xattr(value, size);
|
||||
acl = posix_acl_from_xattr(&init_user_ns, value, size);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
else if (acl) {
|
||||
|
|
|
@ -81,10 +81,6 @@ config CUSE
|
|||
If you want to develop or use userspace character device
|
||||
based on CUSE, answer Y or M.
|
||||
|
||||
config GENERIC_ACL
|
||||
bool
|
||||
select FS_POSIX_ACL
|
||||
|
||||
menu "Caches"
|
||||
|
||||
source "fs/fscache/Kconfig"
|
||||
|
@ -133,7 +129,7 @@ config TMPFS_POSIX_ACL
|
|||
bool "Tmpfs POSIX Access Control Lists"
|
||||
depends on TMPFS
|
||||
select TMPFS_XATTR
|
||||
select GENERIC_ACL
|
||||
select FS_POSIX_ACL
|
||||
help
|
||||
POSIX Access Control Lists (ACLs) support additional access rights
|
||||
for users and groups beyond the standard owner/group/world scheme,
|
||||
|
|
|
@ -46,9 +46,8 @@ obj-$(CONFIG_BINFMT_SOM) += binfmt_som.o
|
|||
obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o
|
||||
|
||||
obj-$(CONFIG_FS_MBCACHE) += mbcache.o
|
||||
obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o
|
||||
obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o
|
||||
obj-$(CONFIG_NFS_COMMON) += nfs_common/
|
||||
obj-$(CONFIG_GENERIC_ACL) += generic_acl.o
|
||||
|
||||
obj-$(CONFIG_FHANDLE) += fhandle.o
|
||||
|
||||
|
|
|
@ -292,7 +292,6 @@ static const struct inode_operations bad_inode_ops =
|
|||
.getxattr = bad_inode_getxattr,
|
||||
.listxattr = bad_inode_listxattr,
|
||||
.removexattr = bad_inode_removexattr,
|
||||
/* truncate_range returns void */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
|
|||
size = __btrfs_getxattr(inode, name, value, size);
|
||||
}
|
||||
if (size > 0) {
|
||||
acl = posix_acl_from_xattr(value, size);
|
||||
acl = posix_acl_from_xattr(&init_user_ns, value, size);
|
||||
} else if (size == -ENOENT || size == -ENODATA || size == 0) {
|
||||
/* FIXME, who returns -ENOENT? I think nobody */
|
||||
acl = NULL;
|
||||
|
@ -91,7 +91,7 @@ static int btrfs_xattr_acl_get(struct dentry *dentry, const char *name,
|
|||
return PTR_ERR(acl);
|
||||
if (acl == NULL)
|
||||
return -ENODATA;
|
||||
ret = posix_acl_to_xattr(acl, value, size);
|
||||
ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
|
||||
posix_acl_release(acl);
|
||||
|
||||
return ret;
|
||||
|
@ -141,7 +141,7 @@ static int btrfs_set_acl(struct btrfs_trans_handle *trans,
|
|||
goto out;
|
||||
}
|
||||
|
||||
ret = posix_acl_to_xattr(acl, value, size);
|
||||
ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
|
|||
return -EOPNOTSUPP;
|
||||
|
||||
if (value) {
|
||||
acl = posix_acl_from_xattr(value, size);
|
||||
acl = posix_acl_from_xattr(&init_user_ns, value, size);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
|
||||
|
@ -220,7 +220,7 @@ int btrfs_init_acl(struct btrfs_trans_handle *trans,
|
|||
if (ret)
|
||||
goto failed;
|
||||
}
|
||||
ret = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
|
||||
ret = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -250,7 +250,7 @@ int btrfs_acl_chmod(struct inode *inode)
|
|||
if (IS_ERR_OR_NULL(acl))
|
||||
return PTR_ERR(acl);
|
||||
|
||||
ret = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = btrfs_set_acl(NULL, inode, acl, ACL_TYPE_ACCESS);
|
||||
|
|
|
@ -252,7 +252,7 @@ ext2_init_acl(struct inode *inode, struct inode *dir)
|
|||
if (error)
|
||||
goto cleanup;
|
||||
}
|
||||
error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
|
||||
error = __posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
|
||||
if (error < 0)
|
||||
return error;
|
||||
if (error > 0) {
|
||||
|
@ -292,7 +292,7 @@ ext2_acl_chmod(struct inode *inode)
|
|||
acl = ext2_get_acl(inode, ACL_TYPE_ACCESS);
|
||||
if (IS_ERR(acl) || !acl)
|
||||
return PTR_ERR(acl);
|
||||
error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
error = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
if (error)
|
||||
return error;
|
||||
error = ext2_set_acl(inode, ACL_TYPE_ACCESS, acl);
|
||||
|
@ -346,7 +346,7 @@ ext2_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer,
|
|||
return PTR_ERR(acl);
|
||||
if (acl == NULL)
|
||||
return -ENODATA;
|
||||
error = posix_acl_to_xattr(acl, buffer, size);
|
||||
error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
|
||||
posix_acl_release(acl);
|
||||
|
||||
return error;
|
||||
|
@ -367,7 +367,7 @@ ext2_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
|
|||
return -EPERM;
|
||||
|
||||
if (value) {
|
||||
acl = posix_acl_from_xattr(value, size);
|
||||
acl = posix_acl_from_xattr(&init_user_ns, value, size);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
else if (acl) {
|
||||
|
|
|
@ -255,7 +255,7 @@ ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
|
|||
if (error)
|
||||
goto cleanup;
|
||||
}
|
||||
error = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
|
||||
error = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
|
@ -298,7 +298,7 @@ ext3_acl_chmod(struct inode *inode)
|
|||
acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);
|
||||
if (IS_ERR(acl) || !acl)
|
||||
return PTR_ERR(acl);
|
||||
error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
error = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
if (error)
|
||||
return error;
|
||||
retry:
|
||||
|
@ -365,7 +365,7 @@ ext3_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer,
|
|||
return PTR_ERR(acl);
|
||||
if (acl == NULL)
|
||||
return -ENODATA;
|
||||
error = posix_acl_to_xattr(acl, buffer, size);
|
||||
error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
|
||||
posix_acl_release(acl);
|
||||
|
||||
return error;
|
||||
|
@ -388,7 +388,7 @@ ext3_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
|
|||
return -EPERM;
|
||||
|
||||
if (value) {
|
||||
acl = posix_acl_from_xattr(value, size);
|
||||
acl = posix_acl_from_xattr(&init_user_ns, value, size);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
else if (acl) {
|
||||
|
|
|
@ -259,7 +259,7 @@ ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
|
|||
if (error)
|
||||
goto cleanup;
|
||||
}
|
||||
error = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
|
||||
error = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
|
@ -303,7 +303,7 @@ ext4_acl_chmod(struct inode *inode)
|
|||
acl = ext4_get_acl(inode, ACL_TYPE_ACCESS);
|
||||
if (IS_ERR(acl) || !acl)
|
||||
return PTR_ERR(acl);
|
||||
error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
error = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
if (error)
|
||||
return error;
|
||||
retry:
|
||||
|
@ -370,7 +370,7 @@ ext4_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer,
|
|||
return PTR_ERR(acl);
|
||||
if (acl == NULL)
|
||||
return -ENODATA;
|
||||
error = posix_acl_to_xattr(acl, buffer, size);
|
||||
error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
|
||||
posix_acl_release(acl);
|
||||
|
||||
return error;
|
||||
|
@ -393,7 +393,7 @@ ext4_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
|
|||
return -EPERM;
|
||||
|
||||
if (value) {
|
||||
acl = posix_acl_from_xattr(value, size);
|
||||
acl = posix_acl_from_xattr(&init_user_ns, value, size);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
else if (acl) {
|
||||
|
|
|
@ -272,7 +272,7 @@ int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage,
|
|||
if (error)
|
||||
goto cleanup;
|
||||
}
|
||||
error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
|
||||
error = __posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
|
||||
if (error < 0)
|
||||
return error;
|
||||
if (error > 0)
|
||||
|
@ -298,7 +298,7 @@ int f2fs_acl_chmod(struct inode *inode)
|
|||
if (IS_ERR(acl) || !acl)
|
||||
return PTR_ERR(acl);
|
||||
|
||||
error = posix_acl_chmod(&acl, GFP_KERNEL, mode);
|
||||
error = __posix_acl_chmod(&acl, GFP_KERNEL, mode);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -343,7 +343,7 @@ static int f2fs_xattr_get_acl(struct dentry *dentry, const char *name,
|
|||
return PTR_ERR(acl);
|
||||
if (!acl)
|
||||
return -ENODATA;
|
||||
error = posix_acl_to_xattr(acl, buffer, size);
|
||||
error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
|
||||
posix_acl_release(acl);
|
||||
|
||||
return error;
|
||||
|
@ -365,7 +365,7 @@ static int f2fs_xattr_set_acl(struct dentry *dentry, const char *name,
|
|||
return -EPERM;
|
||||
|
||||
if (value) {
|
||||
acl = posix_acl_from_xattr(value, size);
|
||||
acl = posix_acl_from_xattr(&init_user_ns, value, size);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
if (acl) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/signal.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/pid_namespace.h>
|
||||
#include <linux/shmem_fs.h>
|
||||
|
||||
#include <asm/poll.h>
|
||||
#include <asm/siginfo.h>
|
||||
|
@ -420,6 +421,10 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
|
|||
case F_GETPIPE_SZ:
|
||||
err = pipe_fcntl(filp, cmd, arg);
|
||||
break;
|
||||
case F_ADD_SEALS:
|
||||
case F_GET_SEALS:
|
||||
err = shmem_fcntl(filp, cmd, arg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -767,7 +767,7 @@ int __fscache_write_page(struct fscache_cookie *cookie,
|
|||
fscache_release_write_op);
|
||||
op->op.flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_WAITING);
|
||||
|
||||
ret = radix_tree_preload(gfp & ~__GFP_HIGHMEM);
|
||||
ret = radix_tree_maybe_preload(gfp & ~__GFP_HIGHMEM);
|
||||
if (ret < 0)
|
||||
goto nomem_free;
|
||||
|
||||
|
|
180
fs/generic_acl.c
180
fs/generic_acl.c
|
@ -1,180 +0,0 @@
|
|||
/*
|
||||
* (C) 2005 Andreas Gruenbacher <agruen@suse.de>
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*
|
||||
* Generic ACL support for in-memory filesystems.
|
||||
*/
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/generic_acl.h>
|
||||
#include <linux/posix_acl.h>
|
||||
#include <linux/posix_acl_xattr.h>
|
||||
|
||||
|
||||
static size_t
|
||||
generic_acl_list(struct dentry *dentry, char *list, size_t list_size,
|
||||
const char *name, size_t name_len, int type)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
const char *xname;
|
||||
size_t size;
|
||||
|
||||
acl = get_cached_acl(dentry->d_inode, type);
|
||||
if (!acl)
|
||||
return 0;
|
||||
posix_acl_release(acl);
|
||||
|
||||
switch (type) {
|
||||
case ACL_TYPE_ACCESS:
|
||||
xname = POSIX_ACL_XATTR_ACCESS;
|
||||
break;
|
||||
case ACL_TYPE_DEFAULT:
|
||||
xname = POSIX_ACL_XATTR_DEFAULT;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
size = strlen(xname) + 1;
|
||||
if (list && size <= list_size)
|
||||
memcpy(list, xname, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
static int
|
||||
generic_acl_get(struct dentry *dentry, const char *name, void *buffer,
|
||||
size_t size, int type)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int error;
|
||||
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
|
||||
acl = get_cached_acl(dentry->d_inode, type);
|
||||
if (!acl)
|
||||
return -ENODATA;
|
||||
error = posix_acl_to_xattr(acl, buffer, size);
|
||||
posix_acl_release(acl);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
generic_acl_set(struct dentry *dentry, const char *name, const void *value,
|
||||
size_t size, int flags, int type)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct posix_acl *acl = NULL;
|
||||
int error;
|
||||
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
if (S_ISLNK(inode->i_mode))
|
||||
return -EOPNOTSUPP;
|
||||
if (!inode_owner_or_capable(inode))
|
||||
return -EPERM;
|
||||
if (value) {
|
||||
acl = posix_acl_from_xattr(value, size);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
}
|
||||
if (acl) {
|
||||
error = posix_acl_valid(acl);
|
||||
if (error)
|
||||
goto failed;
|
||||
switch (type) {
|
||||
case ACL_TYPE_ACCESS:
|
||||
error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
|
||||
if (error)
|
||||
goto failed;
|
||||
inode->i_ctime = CURRENT_TIME;
|
||||
break;
|
||||
case ACL_TYPE_DEFAULT:
|
||||
if (!S_ISDIR(inode->i_mode)) {
|
||||
error = -EINVAL;
|
||||
goto failed;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
set_cached_acl(inode, type, acl);
|
||||
error = 0;
|
||||
failed:
|
||||
posix_acl_release(acl);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* generic_acl_init - Take care of acl inheritance at @inode create time
|
||||
*
|
||||
* Files created inside a directory with a default ACL inherit the
|
||||
* directory's default ACL.
|
||||
*/
|
||||
int
|
||||
generic_acl_init(struct inode *inode, struct inode *dir)
|
||||
{
|
||||
struct posix_acl *acl = NULL;
|
||||
int error;
|
||||
|
||||
if (!S_ISLNK(inode->i_mode))
|
||||
acl = get_cached_acl(dir, ACL_TYPE_DEFAULT);
|
||||
if (acl) {
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
set_cached_acl(inode, ACL_TYPE_DEFAULT, acl);
|
||||
error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
|
||||
if (error < 0)
|
||||
return error;
|
||||
if (error > 0)
|
||||
set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
|
||||
} else {
|
||||
inode->i_mode &= ~current_umask();
|
||||
}
|
||||
error = 0;
|
||||
|
||||
posix_acl_release(acl);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* generic_acl_chmod - change the access acl of @inode upon chmod()
|
||||
*
|
||||
* A chmod also changes the permissions of the owner, group/mask, and
|
||||
* other ACL entries.
|
||||
*/
|
||||
int
|
||||
generic_acl_chmod(struct inode *inode)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int error = 0;
|
||||
|
||||
if (S_ISLNK(inode->i_mode))
|
||||
return -EOPNOTSUPP;
|
||||
acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
|
||||
if (acl) {
|
||||
error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
if (error)
|
||||
return error;
|
||||
set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
|
||||
posix_acl_release(acl);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
const struct xattr_handler generic_acl_access_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_ACCESS,
|
||||
.flags = ACL_TYPE_ACCESS,
|
||||
.list = generic_acl_list,
|
||||
.get = generic_acl_get,
|
||||
.set = generic_acl_set,
|
||||
};
|
||||
|
||||
const struct xattr_handler generic_acl_default_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_DEFAULT,
|
||||
.flags = ACL_TYPE_DEFAULT,
|
||||
.list = generic_acl_list,
|
||||
.get = generic_acl_get,
|
||||
.set = generic_acl_set,
|
||||
};
|
|
@ -63,7 +63,7 @@ struct posix_acl *gfs2_get_acl(struct inode *inode, int type)
|
|||
if (len == 0)
|
||||
return NULL;
|
||||
|
||||
acl = posix_acl_from_xattr(data, len);
|
||||
acl = posix_acl_from_xattr(&init_user_ns, data, len);
|
||||
kfree(data);
|
||||
return acl;
|
||||
}
|
||||
|
@ -92,13 +92,13 @@ static int gfs2_acl_set(struct inode *inode, int type, struct posix_acl *acl)
|
|||
const char *name = gfs2_acl_name(type);
|
||||
|
||||
BUG_ON(name == NULL);
|
||||
len = posix_acl_to_xattr(acl, NULL, 0);
|
||||
len = posix_acl_to_xattr(&init_user_ns, acl, NULL, 0);
|
||||
if (len == 0)
|
||||
return 0;
|
||||
data = kmalloc(len, GFP_NOFS);
|
||||
if (data == NULL)
|
||||
return -ENOMEM;
|
||||
error = posix_acl_to_xattr(acl, data, len);
|
||||
error = posix_acl_to_xattr(&init_user_ns, acl, data, len);
|
||||
if (error < 0)
|
||||
goto out;
|
||||
error = __gfs2_xattr_set(inode, name, data, len, 0, GFS2_EATYPE_SYS);
|
||||
|
@ -137,7 +137,7 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode)
|
|||
goto out;
|
||||
}
|
||||
|
||||
error = posix_acl_create(&acl, GFP_NOFS, &mode);
|
||||
error = __posix_acl_create(&acl, GFP_NOFS, &mode);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
|
@ -168,16 +168,16 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
|
|||
if (!acl)
|
||||
return gfs2_setattr_simple(inode, attr);
|
||||
|
||||
error = posix_acl_chmod(&acl, GFP_NOFS, attr->ia_mode);
|
||||
error = __posix_acl_chmod(&acl, GFP_NOFS, attr->ia_mode);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
len = posix_acl_to_xattr(acl, NULL, 0);
|
||||
len = posix_acl_to_xattr(&init_user_ns, acl, NULL, 0);
|
||||
data = kmalloc(len, GFP_NOFS);
|
||||
error = -ENOMEM;
|
||||
if (data == NULL)
|
||||
goto out;
|
||||
posix_acl_to_xattr(acl, data, len);
|
||||
posix_acl_to_xattr(&init_user_ns, acl, data, len);
|
||||
error = gfs2_xattr_acl_chmod(ip, attr, data);
|
||||
kfree(data);
|
||||
set_cached_acl(&ip->i_inode, ACL_TYPE_ACCESS, acl);
|
||||
|
@ -218,7 +218,7 @@ static int gfs2_xattr_system_get(struct dentry *dentry, const char *name,
|
|||
if (acl == NULL)
|
||||
return -ENODATA;
|
||||
|
||||
error = posix_acl_to_xattr(acl, buffer, size);
|
||||
error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
|
||||
posix_acl_release(acl);
|
||||
|
||||
return error;
|
||||
|
@ -251,7 +251,7 @@ static int gfs2_xattr_system_set(struct dentry *dentry, const char *name,
|
|||
if (!value)
|
||||
goto set_acl;
|
||||
|
||||
acl = posix_acl_from_xattr(value, size);
|
||||
acl = posix_acl_from_xattr(&init_user_ns, value, size);
|
||||
if (!acl) {
|
||||
/*
|
||||
* acl_set_file(3) may request that we set default ACLs with
|
||||
|
|
|
@ -164,6 +164,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
|
|||
mapping->a_ops = &empty_aops;
|
||||
mapping->host = inode;
|
||||
mapping->flags = 0;
|
||||
atomic_set(&mapping->i_mmap_writable, 0);
|
||||
mapping_set_gfp_mask(mapping, GFP_HIGHUSER_MOVABLE);
|
||||
mapping->assoc_mapping = NULL;
|
||||
mapping->backing_dev_info = &default_backing_dev_info;
|
||||
|
|
|
@ -280,7 +280,7 @@ int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, umode_t *i_mode
|
|||
if (S_ISDIR(*i_mode))
|
||||
set_cached_acl(inode, ACL_TYPE_DEFAULT, acl);
|
||||
|
||||
rc = posix_acl_create(&acl, GFP_KERNEL, i_mode);
|
||||
rc = __posix_acl_create(&acl, GFP_KERNEL, i_mode);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (rc > 0)
|
||||
|
@ -320,7 +320,7 @@ int jffs2_acl_chmod(struct inode *inode)
|
|||
acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS);
|
||||
if (IS_ERR(acl) || !acl)
|
||||
return PTR_ERR(acl);
|
||||
rc = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
rc = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, acl);
|
||||
|
@ -362,7 +362,7 @@ static int jffs2_acl_getxattr(struct dentry *dentry, const char *name,
|
|||
return PTR_ERR(acl);
|
||||
if (!acl)
|
||||
return -ENODATA;
|
||||
rc = posix_acl_to_xattr(acl, buffer, size);
|
||||
rc = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
|
||||
posix_acl_release(acl);
|
||||
|
||||
return rc;
|
||||
|
@ -380,7 +380,7 @@ static int jffs2_acl_setxattr(struct dentry *dentry, const char *name,
|
|||
return -EPERM;
|
||||
|
||||
if (value) {
|
||||
acl = posix_acl_from_xattr(value, size);
|
||||
acl = posix_acl_from_xattr(&init_user_ns, value, size);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
if (acl) {
|
||||
|
|
|
@ -64,7 +64,7 @@ struct posix_acl *jfs_get_acl(struct inode *inode, int type)
|
|||
else
|
||||
acl = ERR_PTR(size);
|
||||
} else {
|
||||
acl = posix_acl_from_xattr(value, size);
|
||||
acl = posix_acl_from_xattr(&init_user_ns, value, size);
|
||||
}
|
||||
kfree(value);
|
||||
if (!IS_ERR(acl))
|
||||
|
@ -100,7 +100,7 @@ static int jfs_set_acl(tid_t tid, struct inode *inode, int type,
|
|||
value = kmalloc(size, GFP_KERNEL);
|
||||
if (!value)
|
||||
return -ENOMEM;
|
||||
rc = posix_acl_to_xattr(acl, value, size);
|
||||
rc = posix_acl_to_xattr(&init_user_ns, acl, value, size);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir)
|
|||
if (rc)
|
||||
goto cleanup;
|
||||
}
|
||||
rc = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
|
||||
rc = __posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
|
||||
if (rc < 0)
|
||||
goto cleanup; /* posix_acl_release(NULL) is no-op */
|
||||
if (rc > 0)
|
||||
|
@ -161,7 +161,7 @@ int jfs_acl_chmod(struct inode *inode)
|
|||
if (IS_ERR(acl) || !acl)
|
||||
return PTR_ERR(acl);
|
||||
|
||||
rc = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
rc = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
|
@ -685,7 +685,7 @@ static int can_set_system_xattr(struct inode *inode, const char *name,
|
|||
* POSIX_ACL_XATTR_ACCESS is tied to i_mode
|
||||
*/
|
||||
if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) {
|
||||
acl = posix_acl_from_xattr(value, value_len);
|
||||
acl = posix_acl_from_xattr(&init_user_ns, value, value_len);
|
||||
if (IS_ERR(acl)) {
|
||||
rc = PTR_ERR(acl);
|
||||
printk(KERN_ERR "posix_acl_from_xattr returned %d\n",
|
||||
|
@ -710,7 +710,7 @@ static int can_set_system_xattr(struct inode *inode, const char *name,
|
|||
|
||||
return 0;
|
||||
} else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) {
|
||||
acl = posix_acl_from_xattr(value, value_len);
|
||||
acl = posix_acl_from_xattr(&init_user_ns, value, value_len);
|
||||
if (IS_ERR(acl)) {
|
||||
rc = PTR_ERR(acl);
|
||||
printk(KERN_ERR "posix_acl_from_xattr returned %d\n",
|
||||
|
|
20
fs/namei.c
20
fs/namei.c
|
@ -230,27 +230,9 @@ static int check_acl(struct inode *inode, int mask)
|
|||
return posix_acl_permission(inode, acl, mask & ~MAY_NOT_BLOCK);
|
||||
}
|
||||
|
||||
acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
|
||||
|
||||
/*
|
||||
* A filesystem can force a ACL callback by just never filling the
|
||||
* ACL cache. But normally you'd fill the cache either at inode
|
||||
* instantiation time, or on the first ->get_acl call.
|
||||
*
|
||||
* If the filesystem doesn't have a get_acl() function at all, we'll
|
||||
* just create the negative cache entry.
|
||||
*/
|
||||
if (acl == ACL_NOT_CACHED) {
|
||||
if (inode->i_op->get_acl) {
|
||||
acl = inode->i_op->get_acl(inode, ACL_TYPE_ACCESS);
|
||||
acl = get_acl(inode, ACL_TYPE_ACCESS);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
} else {
|
||||
set_cached_acl(inode, ACL_TYPE_ACCESS, NULL);
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
if (acl) {
|
||||
int error = posix_acl_permission(inode, acl, mask);
|
||||
posix_acl_release(acl);
|
||||
|
|
|
@ -70,7 +70,7 @@ ssize_t nfs3_getxattr(struct dentry *dentry, const char *name,
|
|||
if (type == ACL_TYPE_ACCESS && acl->a_count == 0)
|
||||
error = -ENODATA;
|
||||
else
|
||||
error = posix_acl_to_xattr(acl, buffer, size);
|
||||
error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
|
||||
posix_acl_release(acl);
|
||||
} else
|
||||
error = -ENODATA;
|
||||
|
@ -92,7 +92,7 @@ int nfs3_setxattr(struct dentry *dentry, const char *name,
|
|||
else
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
acl = posix_acl_from_xattr(value, size);
|
||||
acl = posix_acl_from_xattr(&init_user_ns, value, size);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
error = nfs3_proc_setacl(inode, type, acl);
|
||||
|
@ -428,7 +428,7 @@ int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode,
|
|||
if (!dfacl)
|
||||
return 0;
|
||||
acl = posix_acl_dup(dfacl);
|
||||
error = posix_acl_create(&acl, GFP_KERNEL, &mode);
|
||||
error = __posix_acl_create(&acl, GFP_KERNEL, &mode);
|
||||
if (error < 0)
|
||||
goto out_release_dfacl;
|
||||
error = nfs3_proc_setacls(inode, acl, S_ISDIR(inode->i_mode) ?
|
||||
|
|
|
@ -517,7 +517,7 @@ set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key)
|
|||
if (buf == NULL)
|
||||
goto out;
|
||||
|
||||
len = posix_acl_to_xattr(pacl, buf, buflen);
|
||||
len = posix_acl_to_xattr(&init_user_ns, pacl, buf, buflen);
|
||||
if (len < 0) {
|
||||
error = len;
|
||||
goto out;
|
||||
|
@ -586,7 +586,7 @@ _get_posix_acl(struct dentry *dentry, char *key)
|
|||
if (buflen <= 0)
|
||||
return ERR_PTR(buflen);
|
||||
|
||||
pacl = posix_acl_from_xattr(buf, buflen);
|
||||
pacl = posix_acl_from_xattr(&init_user_ns, buf, buflen);
|
||||
kfree(buf);
|
||||
return pacl;
|
||||
}
|
||||
|
@ -2299,7 +2299,7 @@ nfsd_get_posix_acl(struct svc_fh *fhp, int type)
|
|||
if (size < 0)
|
||||
return ERR_PTR(size);
|
||||
|
||||
acl = posix_acl_from_xattr(value, size);
|
||||
acl = posix_acl_from_xattr(&init_user_ns, value, size);
|
||||
kfree(value);
|
||||
return acl;
|
||||
}
|
||||
|
@ -2332,7 +2332,7 @@ nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl)
|
|||
value = kmalloc(size, GFP_KERNEL);
|
||||
if (!value)
|
||||
return -ENOMEM;
|
||||
error = posix_acl_to_xattr(acl, value, size);
|
||||
error = posix_acl_to_xattr(&init_user_ns, acl, value, size);
|
||||
if (error < 0)
|
||||
goto getout;
|
||||
size = error;
|
||||
|
|
|
@ -321,7 +321,7 @@ int ocfs2_acl_chmod(struct inode *inode)
|
|||
acl = ocfs2_get_acl(inode, ACL_TYPE_ACCESS);
|
||||
if (IS_ERR(acl) || !acl)
|
||||
return PTR_ERR(acl);
|
||||
ret = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS,
|
||||
|
@ -372,7 +372,7 @@ int ocfs2_init_acl(handle_t *handle,
|
|||
goto cleanup;
|
||||
}
|
||||
mode = inode->i_mode;
|
||||
ret = posix_acl_create(&acl, GFP_NOFS, &mode);
|
||||
ret = __posix_acl_create(&acl, GFP_NOFS, &mode);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -446,7 +446,7 @@ static int ocfs2_xattr_get_acl(struct dentry *dentry, const char *name,
|
|||
return PTR_ERR(acl);
|
||||
if (acl == NULL)
|
||||
return -ENODATA;
|
||||
ret = posix_acl_to_xattr(acl, buffer, size);
|
||||
ret = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
|
||||
posix_acl_release(acl);
|
||||
|
||||
return ret;
|
||||
|
@ -469,7 +469,7 @@ static int ocfs2_xattr_set_acl(struct dentry *dentry, const char *name,
|
|||
return -EPERM;
|
||||
|
||||
if (value) {
|
||||
acl = posix_acl_from_xattr(value, size);
|
||||
acl = posix_acl_from_xattr(&init_user_ns, value, size);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
else if (acl) {
|
||||
|
|
451
fs/posix_acl.c
451
fs/posix_acl.c
|
@ -1,7 +1,5 @@
|
|||
/*
|
||||
* linux/fs/posix_acl.c
|
||||
*
|
||||
* Copyright (C) 2002 by Andreas Gruenbacher <a.gruenbacher@computer.org>
|
||||
* Copyright (C) 2002,2003 by Andreas Gruenbacher <a.gruenbacher@computer.org>
|
||||
*
|
||||
* Fixes from William Schumacher incorporated on 15 March 2001.
|
||||
* (Reported by Charles Bertsch, <CBertsch@microtest.com>).
|
||||
|
@ -18,9 +16,10 @@
|
|||
#include <linux/fs.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/posix_acl.h>
|
||||
#include <linux/posix_acl_xattr.h>
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/user_namespace.h>
|
||||
|
||||
EXPORT_SYMBOL(posix_acl_init);
|
||||
EXPORT_SYMBOL(posix_acl_alloc);
|
||||
|
@ -28,6 +27,33 @@ EXPORT_SYMBOL(posix_acl_valid);
|
|||
EXPORT_SYMBOL(posix_acl_equiv_mode);
|
||||
EXPORT_SYMBOL(posix_acl_from_mode);
|
||||
|
||||
struct posix_acl *get_acl(struct inode *inode, int type)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
|
||||
acl = get_cached_acl(inode, type);
|
||||
if (acl != ACL_NOT_CACHED)
|
||||
return acl;
|
||||
|
||||
if (!IS_POSIXACL(inode))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* A filesystem can force a ACL callback by just never filling the
|
||||
* ACL cache. But normally you'd fill the cache either at inode
|
||||
* instantiation time, or on the first ->get_acl call.
|
||||
*
|
||||
* If the filesystem doesn't have a get_acl() function at all, we'll
|
||||
* just create the negative cache entry.
|
||||
*/
|
||||
if (!inode->i_op->get_acl) {
|
||||
set_cached_acl(inode, type, NULL);
|
||||
return NULL;
|
||||
}
|
||||
return inode->i_op->get_acl(inode, type);
|
||||
}
|
||||
EXPORT_SYMBOL(get_acl);
|
||||
|
||||
/*
|
||||
* Init a fresh posix_acl
|
||||
*/
|
||||
|
@ -78,7 +104,6 @@ posix_acl_valid(const struct posix_acl *acl)
|
|||
{
|
||||
const struct posix_acl_entry *pa, *pe;
|
||||
int state = ACL_USER_OBJ;
|
||||
unsigned int id = 0; /* keep gcc happy */
|
||||
int needs_mask = 0;
|
||||
|
||||
FOREACH_ACL_ENTRY(pa, acl, pe) {
|
||||
|
@ -87,7 +112,6 @@ posix_acl_valid(const struct posix_acl *acl)
|
|||
switch (pa->e_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
if (state == ACL_USER_OBJ) {
|
||||
id = 0;
|
||||
state = ACL_USER;
|
||||
break;
|
||||
}
|
||||
|
@ -96,16 +120,13 @@ posix_acl_valid(const struct posix_acl *acl)
|
|||
case ACL_USER:
|
||||
if (state != ACL_USER)
|
||||
return -EINVAL;
|
||||
if (pa->e_id == ACL_UNDEFINED_ID ||
|
||||
pa->e_id < id)
|
||||
if (!uid_valid(pa->e_uid))
|
||||
return -EINVAL;
|
||||
id = pa->e_id + 1;
|
||||
needs_mask = 1;
|
||||
break;
|
||||
|
||||
case ACL_GROUP_OBJ:
|
||||
if (state == ACL_USER) {
|
||||
id = 0;
|
||||
state = ACL_GROUP;
|
||||
break;
|
||||
}
|
||||
|
@ -114,10 +135,8 @@ posix_acl_valid(const struct posix_acl *acl)
|
|||
case ACL_GROUP:
|
||||
if (state != ACL_GROUP)
|
||||
return -EINVAL;
|
||||
if (pa->e_id == ACL_UNDEFINED_ID ||
|
||||
pa->e_id < id)
|
||||
if (!gid_valid(pa->e_gid))
|
||||
return -EINVAL;
|
||||
id = pa->e_id + 1;
|
||||
needs_mask = 1;
|
||||
break;
|
||||
|
||||
|
@ -201,15 +220,12 @@ posix_acl_from_mode(umode_t mode, gfp_t flags)
|
|||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
acl->a_entries[0].e_tag = ACL_USER_OBJ;
|
||||
acl->a_entries[0].e_id = ACL_UNDEFINED_ID;
|
||||
acl->a_entries[0].e_perm = (mode & S_IRWXU) >> 6;
|
||||
|
||||
acl->a_entries[1].e_tag = ACL_GROUP_OBJ;
|
||||
acl->a_entries[1].e_id = ACL_UNDEFINED_ID;
|
||||
acl->a_entries[1].e_perm = (mode & S_IRWXG) >> 3;
|
||||
|
||||
acl->a_entries[2].e_tag = ACL_OTHER;
|
||||
acl->a_entries[2].e_id = ACL_UNDEFINED_ID;
|
||||
acl->a_entries[2].e_perm = (mode & S_IRWXO);
|
||||
return acl;
|
||||
}
|
||||
|
@ -230,11 +246,11 @@ posix_acl_permission(struct inode *inode, const struct posix_acl *acl, int want)
|
|||
switch(pa->e_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
/* (May have been checked already) */
|
||||
if (inode->i_uid == current_fsuid())
|
||||
if (uid_eq(inode->i_uid, current_fsuid()))
|
||||
goto check_perm;
|
||||
break;
|
||||
case ACL_USER:
|
||||
if (pa->e_id == current_fsuid())
|
||||
if (uid_eq(pa->e_uid, current_fsuid()))
|
||||
goto mask;
|
||||
break;
|
||||
case ACL_GROUP_OBJ:
|
||||
|
@ -245,7 +261,7 @@ posix_acl_permission(struct inode *inode, const struct posix_acl *acl, int want)
|
|||
}
|
||||
break;
|
||||
case ACL_GROUP:
|
||||
if (in_group_p(pa->e_id)) {
|
||||
if (in_group_p(pa->e_gid)) {
|
||||
found = 1;
|
||||
if ((pa->e_perm & want) == want)
|
||||
goto mask;
|
||||
|
@ -375,7 +391,7 @@ EXPORT_SYMBOL(posix_acl_update_mode);
|
|||
/*
|
||||
* Modify the ACL for the chmod syscall.
|
||||
*/
|
||||
static int posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode)
|
||||
static int __posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode)
|
||||
{
|
||||
struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL;
|
||||
struct posix_acl_entry *pa, *pe;
|
||||
|
@ -421,7 +437,7 @@ static int posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode)
|
|||
}
|
||||
|
||||
int
|
||||
posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p)
|
||||
__posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p)
|
||||
{
|
||||
struct posix_acl *clone = posix_acl_clone(*acl, gfp);
|
||||
int err = -ENOMEM;
|
||||
|
@ -436,15 +452,15 @@ posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p)
|
|||
*acl = clone;
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(posix_acl_create);
|
||||
EXPORT_SYMBOL(__posix_acl_create);
|
||||
|
||||
int
|
||||
posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode)
|
||||
__posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode)
|
||||
{
|
||||
struct posix_acl *clone = posix_acl_clone(*acl, gfp);
|
||||
int err = -ENOMEM;
|
||||
if (clone) {
|
||||
err = posix_acl_chmod_masq(clone, mode);
|
||||
err = __posix_acl_chmod_masq(clone, mode);
|
||||
if (err) {
|
||||
posix_acl_release(clone);
|
||||
clone = NULL;
|
||||
|
@ -454,4 +470,389 @@ posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode)
|
|||
*acl = clone;
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(__posix_acl_chmod);
|
||||
|
||||
int
|
||||
posix_acl_chmod(struct inode *inode, umode_t mode)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int ret = 0;
|
||||
|
||||
if (!IS_POSIXACL(inode))
|
||||
return 0;
|
||||
if (!inode->i_op->set_acl)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
acl = get_acl(inode, ACL_TYPE_ACCESS);
|
||||
if (IS_ERR_OR_NULL(acl)) {
|
||||
if (acl == ERR_PTR(-EOPNOTSUPP))
|
||||
return 0;
|
||||
return PTR_ERR(acl);
|
||||
}
|
||||
|
||||
ret = __posix_acl_chmod(&acl, GFP_KERNEL, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = inode->i_op->set_acl(inode, acl, ACL_TYPE_ACCESS);
|
||||
posix_acl_release(acl);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(posix_acl_chmod);
|
||||
|
||||
int
|
||||
posix_acl_create(struct inode *dir, umode_t *mode,
|
||||
struct posix_acl **default_acl, struct posix_acl **acl)
|
||||
{
|
||||
struct posix_acl *p;
|
||||
int ret;
|
||||
|
||||
if (S_ISLNK(*mode) || !IS_POSIXACL(dir))
|
||||
goto no_acl;
|
||||
|
||||
p = get_acl(dir, ACL_TYPE_DEFAULT);
|
||||
if (IS_ERR(p)) {
|
||||
if (p == ERR_PTR(-EOPNOTSUPP))
|
||||
goto apply_umask;
|
||||
return PTR_ERR(p);
|
||||
}
|
||||
|
||||
if (!p)
|
||||
goto apply_umask;
|
||||
|
||||
*acl = posix_acl_clone(p, GFP_NOFS);
|
||||
if (!*acl)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = posix_acl_create_masq(*acl, mode);
|
||||
if (ret < 0) {
|
||||
posix_acl_release(*acl);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
posix_acl_release(*acl);
|
||||
*acl = NULL;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(*mode)) {
|
||||
posix_acl_release(p);
|
||||
*default_acl = NULL;
|
||||
} else {
|
||||
*default_acl = p;
|
||||
}
|
||||
return 0;
|
||||
|
||||
apply_umask:
|
||||
*mode &= ~current_umask();
|
||||
no_acl:
|
||||
*default_acl = NULL;
|
||||
*acl = NULL;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(posix_acl_create);
|
||||
|
||||
/*
|
||||
* Fix up the uids and gids in posix acl extended attributes in place.
|
||||
*/
|
||||
static void posix_acl_fix_xattr_userns(
|
||||
struct user_namespace *to, struct user_namespace *from,
|
||||
void *value, size_t size)
|
||||
{
|
||||
posix_acl_xattr_header *header = (posix_acl_xattr_header *)value;
|
||||
posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end;
|
||||
int count;
|
||||
kuid_t uid;
|
||||
kgid_t gid;
|
||||
|
||||
if (!value)
|
||||
return;
|
||||
if (size < sizeof(posix_acl_xattr_header))
|
||||
return;
|
||||
if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
|
||||
return;
|
||||
|
||||
count = posix_acl_xattr_count(size);
|
||||
if (count < 0)
|
||||
return;
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
for (end = entry + count; entry != end; entry++) {
|
||||
switch(le16_to_cpu(entry->e_tag)) {
|
||||
case ACL_USER:
|
||||
uid = make_kuid(from, le32_to_cpu(entry->e_id));
|
||||
entry->e_id = cpu_to_le32(from_kuid(to, uid));
|
||||
break;
|
||||
case ACL_GROUP:
|
||||
gid = make_kgid(from, le32_to_cpu(entry->e_id));
|
||||
entry->e_id = cpu_to_le32(from_kgid(to, gid));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void posix_acl_fix_xattr_from_user(void *value, size_t size)
|
||||
{
|
||||
struct user_namespace *user_ns = current_user_ns();
|
||||
if (user_ns == &init_user_ns)
|
||||
return;
|
||||
posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size);
|
||||
}
|
||||
|
||||
void posix_acl_fix_xattr_to_user(void *value, size_t size)
|
||||
{
|
||||
struct user_namespace *user_ns = current_user_ns();
|
||||
if (user_ns == &init_user_ns)
|
||||
return;
|
||||
posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert from extended attribute to in-memory representation.
|
||||
*/
|
||||
struct posix_acl *
|
||||
posix_acl_from_xattr(struct user_namespace *user_ns,
|
||||
const void *value, size_t size)
|
||||
{
|
||||
posix_acl_xattr_header *header = (posix_acl_xattr_header *)value;
|
||||
posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end;
|
||||
int count;
|
||||
struct posix_acl *acl;
|
||||
struct posix_acl_entry *acl_e;
|
||||
|
||||
if (!value)
|
||||
return NULL;
|
||||
if (size < sizeof(posix_acl_xattr_header))
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
|
||||
count = posix_acl_xattr_count(size);
|
||||
if (count < 0)
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (count == 0)
|
||||
return NULL;
|
||||
|
||||
acl = posix_acl_alloc(count, GFP_NOFS);
|
||||
if (!acl)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
acl_e = acl->a_entries;
|
||||
|
||||
for (end = entry + count; entry != end; acl_e++, entry++) {
|
||||
acl_e->e_tag = le16_to_cpu(entry->e_tag);
|
||||
acl_e->e_perm = le16_to_cpu(entry->e_perm);
|
||||
|
||||
switch(acl_e->e_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
case ACL_GROUP_OBJ:
|
||||
case ACL_MASK:
|
||||
case ACL_OTHER:
|
||||
break;
|
||||
|
||||
case ACL_USER:
|
||||
acl_e->e_uid =
|
||||
make_kuid(user_ns,
|
||||
le32_to_cpu(entry->e_id));
|
||||
if (!uid_valid(acl_e->e_uid))
|
||||
goto fail;
|
||||
break;
|
||||
case ACL_GROUP:
|
||||
acl_e->e_gid =
|
||||
make_kgid(user_ns,
|
||||
le32_to_cpu(entry->e_id));
|
||||
if (!gid_valid(acl_e->e_gid))
|
||||
goto fail;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return acl;
|
||||
|
||||
fail:
|
||||
posix_acl_release(acl);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
EXPORT_SYMBOL (posix_acl_from_xattr);
|
||||
|
||||
/*
|
||||
* Convert from in-memory to extended attribute representation.
|
||||
*/
|
||||
int
|
||||
posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
posix_acl_xattr_header *ext_acl = (posix_acl_xattr_header *)buffer;
|
||||
posix_acl_xattr_entry *ext_entry;
|
||||
int real_size, n;
|
||||
|
||||
real_size = posix_acl_xattr_size(acl->a_count);
|
||||
if (!buffer)
|
||||
return real_size;
|
||||
if (real_size > size)
|
||||
return -ERANGE;
|
||||
|
||||
ext_entry = ext_acl->a_entries;
|
||||
ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
|
||||
|
||||
for (n=0; n < acl->a_count; n++, ext_entry++) {
|
||||
const struct posix_acl_entry *acl_e = &acl->a_entries[n];
|
||||
ext_entry->e_tag = cpu_to_le16(acl_e->e_tag);
|
||||
ext_entry->e_perm = cpu_to_le16(acl_e->e_perm);
|
||||
switch(acl_e->e_tag) {
|
||||
case ACL_USER:
|
||||
ext_entry->e_id =
|
||||
cpu_to_le32(from_kuid(user_ns, acl_e->e_uid));
|
||||
break;
|
||||
case ACL_GROUP:
|
||||
ext_entry->e_id =
|
||||
cpu_to_le32(from_kgid(user_ns, acl_e->e_gid));
|
||||
break;
|
||||
default:
|
||||
ext_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return real_size;
|
||||
}
|
||||
EXPORT_SYMBOL (posix_acl_to_xattr);
|
||||
|
||||
static int
|
||||
posix_acl_xattr_get(struct dentry *dentry, const char *name,
|
||||
void *value, size_t size, int type)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int error;
|
||||
|
||||
if (!IS_POSIXACL(dentry->d_inode))
|
||||
return -EOPNOTSUPP;
|
||||
if (S_ISLNK(dentry->d_inode->i_mode))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
acl = get_acl(dentry->d_inode, type);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
if (acl == NULL)
|
||||
return -ENODATA;
|
||||
|
||||
error = posix_acl_to_xattr(&init_user_ns, acl, value, size);
|
||||
posix_acl_release(acl);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
posix_acl_xattr_set(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags, int type)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct posix_acl *acl = NULL;
|
||||
int ret;
|
||||
|
||||
if (!IS_POSIXACL(inode))
|
||||
return -EOPNOTSUPP;
|
||||
if (!inode->i_op->set_acl)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
|
||||
return value ? -EACCES : 0;
|
||||
if (!inode_owner_or_capable(inode))
|
||||
return -EPERM;
|
||||
|
||||
if (value) {
|
||||
acl = posix_acl_from_xattr(&init_user_ns, value, size);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
|
||||
if (acl) {
|
||||
ret = posix_acl_valid(acl);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = inode->i_op->set_acl(inode, acl, type);
|
||||
out:
|
||||
posix_acl_release(acl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t
|
||||
posix_acl_xattr_list(struct dentry *dentry, char *list, size_t list_size,
|
||||
const char *name, size_t name_len, int type)
|
||||
{
|
||||
const char *xname;
|
||||
size_t size;
|
||||
|
||||
if (!IS_POSIXACL(dentry->d_inode))
|
||||
return -EOPNOTSUPP;
|
||||
if (S_ISLNK(dentry->d_inode->i_mode))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (type == ACL_TYPE_ACCESS)
|
||||
xname = POSIX_ACL_XATTR_ACCESS;
|
||||
else
|
||||
xname = POSIX_ACL_XATTR_DEFAULT;
|
||||
|
||||
size = strlen(xname) + 1;
|
||||
if (list && size <= list_size)
|
||||
memcpy(list, xname, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
const struct xattr_handler posix_acl_access_xattr_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_ACCESS,
|
||||
.flags = ACL_TYPE_ACCESS,
|
||||
.list = posix_acl_xattr_list,
|
||||
.get = posix_acl_xattr_get,
|
||||
.set = posix_acl_xattr_set,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(posix_acl_access_xattr_handler);
|
||||
|
||||
const struct xattr_handler posix_acl_default_xattr_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_DEFAULT,
|
||||
.flags = ACL_TYPE_DEFAULT,
|
||||
.list = posix_acl_xattr_list,
|
||||
.get = posix_acl_xattr_get,
|
||||
.set = posix_acl_xattr_set,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(posix_acl_default_xattr_handler);
|
||||
|
||||
int simple_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (type == ACL_TYPE_ACCESS) {
|
||||
error = posix_acl_equiv_mode(acl, &inode->i_mode);
|
||||
if (error < 0)
|
||||
return 0;
|
||||
if (error == 0)
|
||||
acl = NULL;
|
||||
}
|
||||
|
||||
inode->i_ctime = CURRENT_TIME;
|
||||
set_cached_acl(inode, type, acl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int simple_acl_create(struct inode *dir, struct inode *inode)
|
||||
{
|
||||
struct posix_acl *default_acl, *acl;
|
||||
int error;
|
||||
|
||||
error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
set_cached_acl(inode, ACL_TYPE_DEFAULT, default_acl);
|
||||
set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
|
||||
|
||||
if (default_acl)
|
||||
posix_acl_release(default_acl);
|
||||
if (acl)
|
||||
posix_acl_release(acl);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ posix_acl_set(struct dentry *dentry, const char *name, const void *value,
|
|||
return -EPERM;
|
||||
|
||||
if (value) {
|
||||
acl = posix_acl_from_xattr(value, size);
|
||||
acl = posix_acl_from_xattr(&init_user_ns, value, size);
|
||||
if (IS_ERR(acl)) {
|
||||
return PTR_ERR(acl);
|
||||
} else if (acl) {
|
||||
|
@ -77,7 +77,7 @@ posix_acl_get(struct dentry *dentry, const char *name, void *buffer,
|
|||
return PTR_ERR(acl);
|
||||
if (acl == NULL)
|
||||
return -ENODATA;
|
||||
error = posix_acl_to_xattr(acl, buffer, size);
|
||||
error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
|
||||
posix_acl_release(acl);
|
||||
|
||||
return error;
|
||||
|
@ -358,7 +358,7 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
|
|||
|
||||
/* Now we reconcile the new ACL and the mode,
|
||||
potentially modifying both */
|
||||
err = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
|
||||
err = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
@ -440,7 +440,7 @@ int reiserfs_acl_chmod(struct inode *inode)
|
|||
return 0;
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
error = posix_acl_chmod(&acl, GFP_NOFS, inode->i_mode);
|
||||
error = __posix_acl_chmod(&acl, GFP_NOFS, inode->i_mode);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
|
217
fs/xattr.c
217
fs/xattr.c
|
@ -20,6 +20,7 @@
|
|||
#include <linux/fsnotify.h>
|
||||
#include <linux/audit.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/posix_acl_xattr.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
|
@ -295,11 +296,13 @@ vfs_removexattr(struct dentry *dentry, const char *name)
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
error = security_inode_removexattr(dentry, name);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
mutex_lock(&inode->i_mutex);
|
||||
error = security_inode_removexattr(dentry, name);
|
||||
if (error) {
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = inode->i_op->removexattr(dentry, name);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
|
@ -347,6 +350,9 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value,
|
|||
error = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
|
||||
(strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
|
||||
posix_acl_fix_xattr_from_user(kvalue, size);
|
||||
}
|
||||
|
||||
error = vfs_setxattr(d, kname, kvalue, size, flags);
|
||||
|
@ -399,11 +405,12 @@ SYSCALL_DEFINE5(lsetxattr, const char __user *, pathname,
|
|||
SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
|
||||
const void __user *,value, size_t, size, int, flags)
|
||||
{
|
||||
int fput_needed;
|
||||
struct file *f;
|
||||
struct dentry *dentry;
|
||||
int error = -EBADF;
|
||||
|
||||
f = fget(fd);
|
||||
f = fget_light(fd, &fput_needed);
|
||||
if (!f)
|
||||
return error;
|
||||
dentry = f->f_path.dentry;
|
||||
|
@ -413,7 +420,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
|
|||
error = setxattr(dentry, name, value, size, flags);
|
||||
mnt_drop_write_file(f);
|
||||
}
|
||||
fput(f);
|
||||
fput_light(f, fput_needed);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -444,6 +451,9 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
|
|||
|
||||
error = vfs_getxattr(d, kname, kvalue, size);
|
||||
if (error > 0) {
|
||||
if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
|
||||
(strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
|
||||
posix_acl_fix_xattr_to_user(kvalue, size);
|
||||
if (size && copy_to_user(value, kvalue, error))
|
||||
error = -EFAULT;
|
||||
} else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {
|
||||
|
@ -486,15 +496,16 @@ SYSCALL_DEFINE4(lgetxattr, const char __user *, pathname,
|
|||
SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name,
|
||||
void __user *, value, size_t, size)
|
||||
{
|
||||
int fput_needed;
|
||||
struct file *f;
|
||||
ssize_t error = -EBADF;
|
||||
|
||||
f = fget(fd);
|
||||
f = fget_light(fd, &fput_needed);
|
||||
if (!f)
|
||||
return error;
|
||||
audit_inode(NULL, f->f_path.dentry);
|
||||
error = getxattr(f->f_path.dentry, name, value, size);
|
||||
fput(f);
|
||||
fput_light(f, fput_needed);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -566,15 +577,16 @@ SYSCALL_DEFINE3(llistxattr, const char __user *, pathname, char __user *, list,
|
|||
|
||||
SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size)
|
||||
{
|
||||
int fput_needed;
|
||||
struct file *f;
|
||||
ssize_t error = -EBADF;
|
||||
|
||||
f = fget(fd);
|
||||
f = fget_light(fd, &fput_needed);
|
||||
if (!f)
|
||||
return error;
|
||||
audit_inode(NULL, f->f_path.dentry);
|
||||
error = listxattr(f->f_path.dentry, list, size);
|
||||
fput(f);
|
||||
fput_light(f, fput_needed);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -634,11 +646,12 @@ SYSCALL_DEFINE2(lremovexattr, const char __user *, pathname,
|
|||
|
||||
SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)
|
||||
{
|
||||
int fput_needed;
|
||||
struct file *f;
|
||||
struct dentry *dentry;
|
||||
int error = -EBADF;
|
||||
|
||||
f = fget(fd);
|
||||
f = fget_light(fd, &fput_needed);
|
||||
if (!f)
|
||||
return error;
|
||||
dentry = f->f_path.dentry;
|
||||
|
@ -648,7 +661,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)
|
|||
error = removexattr(dentry, name);
|
||||
mnt_drop_write_file(f);
|
||||
}
|
||||
fput(f);
|
||||
fput_light(f, fput_needed);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -779,3 +792,183 @@ EXPORT_SYMBOL(generic_getxattr);
|
|||
EXPORT_SYMBOL(generic_listxattr);
|
||||
EXPORT_SYMBOL(generic_setxattr);
|
||||
EXPORT_SYMBOL(generic_removexattr);
|
||||
|
||||
/*
|
||||
* Allocate new xattr and copy in the value; but leave the name to callers.
|
||||
*/
|
||||
struct simple_xattr *simple_xattr_alloc(const void *value, size_t size)
|
||||
{
|
||||
struct simple_xattr *new_xattr;
|
||||
size_t len;
|
||||
|
||||
/* wrap around? */
|
||||
len = sizeof(*new_xattr) + size;
|
||||
if (len <= sizeof(*new_xattr))
|
||||
return NULL;
|
||||
|
||||
new_xattr = kmalloc(len, GFP_KERNEL);
|
||||
if (!new_xattr)
|
||||
return NULL;
|
||||
|
||||
new_xattr->size = size;
|
||||
memcpy(new_xattr->value, value, size);
|
||||
return new_xattr;
|
||||
}
|
||||
|
||||
/*
|
||||
* xattr GET operation for in-memory/pseudo filesystems
|
||||
*/
|
||||
int simple_xattr_get(struct simple_xattrs *xattrs, const char *name,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
struct simple_xattr *xattr;
|
||||
int ret = -ENODATA;
|
||||
|
||||
spin_lock(&xattrs->lock);
|
||||
list_for_each_entry(xattr, &xattrs->head, list) {
|
||||
if (strcmp(name, xattr->name))
|
||||
continue;
|
||||
|
||||
ret = xattr->size;
|
||||
if (buffer) {
|
||||
if (size < xattr->size)
|
||||
ret = -ERANGE;
|
||||
else
|
||||
memcpy(buffer, xattr->value, xattr->size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
spin_unlock(&xattrs->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
struct simple_xattr *xattr;
|
||||
struct simple_xattr *new_xattr = NULL;
|
||||
int err = 0;
|
||||
|
||||
/* value == NULL means remove */
|
||||
if (value) {
|
||||
new_xattr = simple_xattr_alloc(value, size);
|
||||
if (!new_xattr)
|
||||
return -ENOMEM;
|
||||
|
||||
new_xattr->name = kstrdup(name, GFP_KERNEL);
|
||||
if (!new_xattr->name) {
|
||||
kfree(new_xattr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock(&xattrs->lock);
|
||||
list_for_each_entry(xattr, &xattrs->head, list) {
|
||||
if (!strcmp(name, xattr->name)) {
|
||||
if (flags & XATTR_CREATE) {
|
||||
xattr = new_xattr;
|
||||
err = -EEXIST;
|
||||
} else if (new_xattr) {
|
||||
list_replace(&xattr->list, &new_xattr->list);
|
||||
} else {
|
||||
list_del(&xattr->list);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (flags & XATTR_REPLACE) {
|
||||
xattr = new_xattr;
|
||||
err = -ENODATA;
|
||||
} else {
|
||||
list_add(&new_xattr->list, &xattrs->head);
|
||||
xattr = NULL;
|
||||
}
|
||||
out:
|
||||
spin_unlock(&xattrs->lock);
|
||||
if (xattr) {
|
||||
kfree(xattr->name);
|
||||
kfree(xattr);
|
||||
}
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* simple_xattr_set - xattr SET operation for in-memory/pseudo filesystems
|
||||
* @xattrs: target simple_xattr list
|
||||
* @name: name of the new extended attribute
|
||||
* @value: value of the new xattr. If %NULL, will remove the attribute
|
||||
* @size: size of the new xattr
|
||||
* @flags: %XATTR_{CREATE|REPLACE}
|
||||
*
|
||||
* %XATTR_CREATE is set, the xattr shouldn't exist already; otherwise fails
|
||||
* with -EEXIST. If %XATTR_REPLACE is set, the xattr should exist;
|
||||
* otherwise, fails with -ENODATA.
|
||||
*
|
||||
* Returns 0 on success, -errno on failure.
|
||||
*/
|
||||
int simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
if (size == 0)
|
||||
value = ""; /* empty EA, do not remove */
|
||||
return __simple_xattr_set(xattrs, name, value, size, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* xattr REMOVE operation for in-memory/pseudo filesystems
|
||||
*/
|
||||
int simple_xattr_remove(struct simple_xattrs *xattrs, const char *name)
|
||||
{
|
||||
return __simple_xattr_set(xattrs, name, NULL, 0, XATTR_REPLACE);
|
||||
}
|
||||
|
||||
static bool xattr_is_trusted(const char *name)
|
||||
{
|
||||
return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
|
||||
}
|
||||
|
||||
/*
|
||||
* xattr LIST operation for in-memory/pseudo filesystems
|
||||
*/
|
||||
ssize_t simple_xattr_list(struct simple_xattrs *xattrs, char *buffer,
|
||||
size_t size)
|
||||
{
|
||||
bool trusted = capable(CAP_SYS_ADMIN);
|
||||
struct simple_xattr *xattr;
|
||||
size_t used = 0;
|
||||
|
||||
spin_lock(&xattrs->lock);
|
||||
list_for_each_entry(xattr, &xattrs->head, list) {
|
||||
size_t len;
|
||||
|
||||
/* skip "trusted." attributes for unprivileged callers */
|
||||
if (!trusted && xattr_is_trusted(xattr->name))
|
||||
continue;
|
||||
|
||||
len = strlen(xattr->name) + 1;
|
||||
used += len;
|
||||
if (buffer) {
|
||||
if (size < used) {
|
||||
used = -ERANGE;
|
||||
break;
|
||||
}
|
||||
memcpy(buffer, xattr->name, len);
|
||||
buffer += len;
|
||||
}
|
||||
}
|
||||
spin_unlock(&xattrs->lock);
|
||||
|
||||
return used;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds an extended attribute to the list
|
||||
*/
|
||||
void simple_xattr_list_add(struct simple_xattrs *xattrs,
|
||||
struct simple_xattr *new_xattr)
|
||||
{
|
||||
spin_lock(&xattrs->lock);
|
||||
list_add(&new_xattr->list, &xattrs->head);
|
||||
spin_unlock(&xattrs->lock);
|
||||
}
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
* linux/fs/xattr_acl.c
|
||||
*
|
||||
* Almost all from linux/fs/ext2/acl.c:
|
||||
* Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/posix_acl_xattr.h>
|
||||
#include <linux/gfp.h>
|
||||
|
||||
|
||||
/*
|
||||
* Convert from extended attribute to in-memory representation.
|
||||
*/
|
||||
struct posix_acl *
|
||||
posix_acl_from_xattr(const void *value, size_t size)
|
||||
{
|
||||
posix_acl_xattr_header *header = (posix_acl_xattr_header *)value;
|
||||
posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end;
|
||||
int count;
|
||||
struct posix_acl *acl;
|
||||
struct posix_acl_entry *acl_e;
|
||||
|
||||
if (!value)
|
||||
return NULL;
|
||||
if (size < sizeof(posix_acl_xattr_header))
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
|
||||
count = posix_acl_xattr_count(size);
|
||||
if (count < 0)
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (count == 0)
|
||||
return NULL;
|
||||
|
||||
acl = posix_acl_alloc(count, GFP_NOFS);
|
||||
if (!acl)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
acl_e = acl->a_entries;
|
||||
|
||||
for (end = entry + count; entry != end; acl_e++, entry++) {
|
||||
acl_e->e_tag = le16_to_cpu(entry->e_tag);
|
||||
acl_e->e_perm = le16_to_cpu(entry->e_perm);
|
||||
|
||||
switch(acl_e->e_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
case ACL_GROUP_OBJ:
|
||||
case ACL_MASK:
|
||||
case ACL_OTHER:
|
||||
acl_e->e_id = ACL_UNDEFINED_ID;
|
||||
break;
|
||||
|
||||
case ACL_USER:
|
||||
case ACL_GROUP:
|
||||
acl_e->e_id = le32_to_cpu(entry->e_id);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return acl;
|
||||
|
||||
fail:
|
||||
posix_acl_release(acl);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
EXPORT_SYMBOL (posix_acl_from_xattr);
|
||||
|
||||
/*
|
||||
* Convert from in-memory to extended attribute representation.
|
||||
*/
|
||||
int
|
||||
posix_acl_to_xattr(const struct posix_acl *acl, void *buffer, size_t size)
|
||||
{
|
||||
posix_acl_xattr_header *ext_acl = (posix_acl_xattr_header *)buffer;
|
||||
posix_acl_xattr_entry *ext_entry = ext_acl->a_entries;
|
||||
int real_size, n;
|
||||
|
||||
real_size = posix_acl_xattr_size(acl->a_count);
|
||||
if (!buffer)
|
||||
return real_size;
|
||||
if (real_size > size)
|
||||
return -ERANGE;
|
||||
|
||||
ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
|
||||
|
||||
for (n=0; n < acl->a_count; n++, ext_entry++) {
|
||||
ext_entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag);
|
||||
ext_entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
|
||||
ext_entry->e_id = cpu_to_le32(acl->a_entries[n].e_id);
|
||||
}
|
||||
return real_size;
|
||||
}
|
||||
EXPORT_SYMBOL (posix_acl_to_xattr);
|
|
@ -278,12 +278,12 @@ xfs_inherit_acl(struct inode *inode, struct posix_acl *acl)
|
|||
goto out;
|
||||
}
|
||||
|
||||
error = posix_acl_create(&acl, GFP_KERNEL, &mode);
|
||||
error = __posix_acl_create(&acl, GFP_KERNEL, &mode);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* If posix_acl_create returns a positive value we need to
|
||||
* If __posix_acl_create returns a positive value we need to
|
||||
* inherit a permission that can't be represented using the Unix
|
||||
* mode bits and we actually need to set an ACL.
|
||||
*/
|
||||
|
@ -315,7 +315,7 @@ xfs_acl_chmod(struct inode *inode)
|
|||
if (IS_ERR(acl) || !acl)
|
||||
return PTR_ERR(acl);
|
||||
|
||||
error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
error = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -337,7 +337,7 @@ xfs_xattr_acl_get(struct dentry *dentry, const char *name,
|
|||
if (acl == NULL)
|
||||
return -ENODATA;
|
||||
|
||||
error = posix_acl_to_xattr(acl, value, size);
|
||||
error = posix_acl_to_xattr(&init_user_ns, acl, value, size);
|
||||
posix_acl_release(acl);
|
||||
|
||||
return error;
|
||||
|
@ -361,7 +361,7 @@ xfs_xattr_acl_set(struct dentry *dentry, const char *name,
|
|||
if (!value)
|
||||
goto set_acl;
|
||||
|
||||
acl = posix_acl_from_xattr(value, size);
|
||||
acl = posix_acl_from_xattr(&init_user_ns, value, size);
|
||||
if (!acl) {
|
||||
/*
|
||||
* acl_set_file(3) may request that we set default ACLs with
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/key.h>
|
||||
#include <linux/selinux.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/uidgid.h>
|
||||
|
||||
struct user_struct;
|
||||
struct cred;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/mutex.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/uidgid.h>
|
||||
#include <asm/device.h>
|
||||
|
||||
struct device;
|
||||
|
|
|
@ -27,6 +27,21 @@
|
|||
#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
|
||||
#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8)
|
||||
|
||||
/*
|
||||
* Set/Get seals
|
||||
*/
|
||||
#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
|
||||
#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
|
||||
|
||||
/*
|
||||
* Types of seals
|
||||
*/
|
||||
#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */
|
||||
#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */
|
||||
#define F_SEAL_GROW 0x0004 /* prevent file from growing */
|
||||
#define F_SEAL_WRITE 0x0008 /* prevent writes */
|
||||
/* (1U << 31) is reserved for signed error codes */
|
||||
|
||||
/*
|
||||
* Types of directory notifications that may be requested.
|
||||
*/
|
||||
|
|
|
@ -428,6 +428,7 @@ struct fscrypt_policy {
|
|||
#include <linux/atomic.h>
|
||||
#include <linux/shrinker.h>
|
||||
#include <linux/migrate_mode.h>
|
||||
#include <linux/uidgid.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
|
@ -683,7 +684,7 @@ struct address_space {
|
|||
struct inode *host; /* owner: inode, block_device */
|
||||
struct radix_tree_root page_tree; /* radix tree of all pages */
|
||||
spinlock_t tree_lock; /* and lock protecting it */
|
||||
unsigned int i_mmap_writable;/* count VM_SHARED mappings */
|
||||
atomic_t i_mmap_writable;/* count VM_SHARED mappings */
|
||||
struct prio_tree_root i_mmap; /* tree of private and shared mappings */
|
||||
struct list_head i_mmap_nonlinear;/*list VM_NONLINEAR mappings */
|
||||
struct mutex i_mmap_mutex; /* protect tree, count, list */
|
||||
|
@ -765,10 +766,35 @@ static inline int mapping_mapped(struct address_space *mapping)
|
|||
* Note that i_mmap_writable counts all VM_SHARED vmas: do_mmap_pgoff
|
||||
* marks vma as VM_SHARED if it is shared, and the file was opened for
|
||||
* writing i.e. vma may be mprotected writable even if now readonly.
|
||||
*
|
||||
* If i_mmap_writable is negative, no new writable mappings are allowed. You
|
||||
* can only deny writable mappings, if none exists right now.
|
||||
*/
|
||||
static inline int mapping_writably_mapped(struct address_space *mapping)
|
||||
{
|
||||
return mapping->i_mmap_writable != 0;
|
||||
return atomic_read(&mapping->i_mmap_writable) > 0;
|
||||
}
|
||||
|
||||
static inline int mapping_map_writable(struct address_space *mapping)
|
||||
{
|
||||
return atomic_inc_unless_negative(&mapping->i_mmap_writable) ?
|
||||
0 : -EPERM;
|
||||
}
|
||||
|
||||
static inline void mapping_unmap_writable(struct address_space *mapping)
|
||||
{
|
||||
atomic_dec(&mapping->i_mmap_writable);
|
||||
}
|
||||
|
||||
static inline int mapping_deny_writable(struct address_space *mapping)
|
||||
{
|
||||
return atomic_dec_unless_positive(&mapping->i_mmap_writable) ?
|
||||
0 : -EBUSY;
|
||||
}
|
||||
|
||||
static inline void mapping_allow_writable(struct address_space *mapping)
|
||||
{
|
||||
atomic_inc(&mapping->i_mmap_writable);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1708,10 +1734,10 @@ struct inode_operations {
|
|||
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
|
||||
ssize_t (*listxattr) (struct dentry *, char *, size_t);
|
||||
int (*removexattr) (struct dentry *, const char *);
|
||||
void (*truncate_range)(struct inode *, loff_t, loff_t);
|
||||
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
|
||||
u64 len);
|
||||
int (*update_time)(struct inode *, struct timespec *, int);
|
||||
int (*set_acl)(struct inode *, struct posix_acl *, int);
|
||||
int (*atomic_open)(struct inode *, struct dentry *,
|
||||
struct file *, unsigned open_flag,
|
||||
umode_t create_mode, int *opened);
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
#ifndef LINUX_GENERIC_ACL_H
|
||||
#define LINUX_GENERIC_ACL_H
|
||||
|
||||
#include <linux/xattr.h>
|
||||
|
||||
struct inode;
|
||||
|
||||
extern const struct xattr_handler generic_acl_access_handler;
|
||||
extern const struct xattr_handler generic_acl_default_handler;
|
||||
|
||||
int generic_acl_init(struct inode *, struct inode *);
|
||||
int generic_acl_chmod(struct inode *);
|
||||
|
||||
#endif /* LINUX_GENERIC_ACL_H */
|
|
@ -79,6 +79,7 @@ struct ipc_kludge {
|
|||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/uidgid.h>
|
||||
|
||||
#define IPCMNI 32768 /* <= MAX_INT limit for ipc arrays (including sysctl changes) */
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/atomic.h>
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/uidgid.h>
|
||||
|
||||
/* key handle serial number */
|
||||
typedef int32_t key_serial_t;
|
||||
|
|
|
@ -879,8 +879,6 @@ extern void pagefault_out_of_memory(void);
|
|||
extern void show_free_areas(unsigned int flags);
|
||||
extern bool skip_free_areas_node(unsigned int flags, int nid);
|
||||
|
||||
int shmem_lock(struct file *file, int lock, struct user_struct *user);
|
||||
struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags);
|
||||
void shmem_set_file(struct vm_area_struct *vma, struct file *file);
|
||||
int shmem_zero_setup(struct vm_area_struct *);
|
||||
|
||||
|
@ -963,11 +961,9 @@ extern void truncate_pagecache(struct inode *inode, loff_t old, loff_t new);
|
|||
extern void truncate_setsize(struct inode *inode, loff_t newsize);
|
||||
void pagecache_isize_extended(struct inode *inode, loff_t from, loff_t to);
|
||||
extern int vmtruncate(struct inode *inode, loff_t offset);
|
||||
extern int vmtruncate_range(struct inode *inode, loff_t offset, loff_t end);
|
||||
void truncate_pagecache_range(struct inode *inode, loff_t offset, loff_t end);
|
||||
int truncate_inode_page(struct address_space *mapping, struct page *page);
|
||||
int generic_error_remove_page(struct address_space *mapping, struct page *page);
|
||||
|
||||
int invalidate_inode_page(struct page *page);
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
|
|
|
@ -167,6 +167,7 @@ enum nfs4_acl_whotype {
|
|||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/list.h>
|
||||
#include <linux/uidgid.h>
|
||||
|
||||
struct nfs4_ace {
|
||||
uint32_t type;
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#ifndef NFS_IDMAP_H
|
||||
#define NFS_IDMAP_H
|
||||
|
||||
#include <linux/uidgid.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* XXX from bits/utmp.h */
|
||||
|
|
|
@ -36,7 +36,13 @@
|
|||
struct posix_acl_entry {
|
||||
short e_tag;
|
||||
unsigned short e_perm;
|
||||
union {
|
||||
kuid_t e_uid;
|
||||
kgid_t e_gid;
|
||||
#ifndef CONFIG_UIDGID_STRICT_TYPE_CHECKS
|
||||
unsigned int e_id;
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
struct posix_acl {
|
||||
|
@ -82,14 +88,21 @@ extern int posix_acl_valid(const struct posix_acl *);
|
|||
extern int posix_acl_permission(struct inode *, const struct posix_acl *, int);
|
||||
extern struct posix_acl *posix_acl_from_mode(umode_t, gfp_t);
|
||||
extern int posix_acl_equiv_mode(const struct posix_acl *, umode_t *);
|
||||
extern int posix_acl_create(struct posix_acl **, gfp_t, umode_t *);
|
||||
extern int posix_acl_chmod(struct posix_acl **, gfp_t, umode_t);
|
||||
extern int __posix_acl_create(struct posix_acl **, gfp_t, umode_t *);
|
||||
extern int __posix_acl_chmod(struct posix_acl **, gfp_t, umode_t);
|
||||
extern int posix_acl_update_mode(struct inode *, umode_t *, struct posix_acl **);
|
||||
|
||||
extern struct posix_acl *get_posix_acl(struct inode *, int);
|
||||
extern int set_posix_acl(struct inode *, int, struct posix_acl *);
|
||||
|
||||
#ifdef CONFIG_FS_POSIX_ACL
|
||||
extern int posix_acl_chmod(struct inode *, umode_t);
|
||||
extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **,
|
||||
struct posix_acl **);
|
||||
|
||||
extern int simple_set_acl(struct inode *, struct posix_acl *, int);
|
||||
extern int simple_acl_create(struct inode *, struct inode *);
|
||||
|
||||
static inline struct posix_acl **acl_by_type(struct inode *inode, int type)
|
||||
{
|
||||
switch (type) {
|
||||
|
@ -160,14 +173,36 @@ static inline void forget_all_cached_acls(struct inode *inode)
|
|||
if (old_default != ACL_NOT_CACHED)
|
||||
posix_acl_release(old_default);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void cache_no_acl(struct inode *inode)
|
||||
{
|
||||
#ifdef CONFIG_FS_POSIX_ACL
|
||||
inode->i_acl = NULL;
|
||||
inode->i_default_acl = NULL;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static inline int posix_acl_chmod(struct inode *inode, umode_t mode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define simple_set_acl NULL
|
||||
|
||||
static inline int simple_acl_create(struct inode *dir, struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void cache_no_acl(struct inode *inode)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int posix_acl_create(struct inode *inode, umode_t *mode,
|
||||
struct posix_acl **default_acl, struct posix_acl **acl)
|
||||
{
|
||||
*default_acl = *acl = NULL;
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_FS_POSIX_ACL */
|
||||
|
||||
struct posix_acl *get_acl(struct inode *inode, int type);
|
||||
|
||||
#endif /* __LINUX_POSIX_ACL_H */
|
||||
|
|
|
@ -52,7 +52,24 @@ posix_acl_xattr_count(size_t size)
|
|||
return size / sizeof(posix_acl_xattr_entry);
|
||||
}
|
||||
|
||||
struct posix_acl *posix_acl_from_xattr(const void *value, size_t size);
|
||||
int posix_acl_to_xattr(const struct posix_acl *acl, void *buffer, size_t size);
|
||||
#ifdef CONFIG_FS_POSIX_ACL
|
||||
void posix_acl_fix_xattr_from_user(void *value, size_t size);
|
||||
void posix_acl_fix_xattr_to_user(void *value, size_t size);
|
||||
#else
|
||||
static inline void posix_acl_fix_xattr_from_user(void *value, size_t size)
|
||||
{
|
||||
}
|
||||
static inline void posix_acl_fix_xattr_to_user(void *value, size_t size)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
struct posix_acl *posix_acl_from_xattr(struct user_namespace *user_ns,
|
||||
const void *value, size_t size);
|
||||
int posix_acl_to_xattr(struct user_namespace *user_ns,
|
||||
const struct posix_acl *acl, void *buffer, size_t size);
|
||||
|
||||
extern const struct xattr_handler posix_acl_access_xattr_handler;
|
||||
extern const struct xattr_handler posix_acl_default_xattr_handler;
|
||||
|
||||
#endif /* _POSIX_ACL_XATTR_H */
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/uidgid.h>
|
||||
|
||||
#define __DQUOT_VERSION__ "dquot_6.5.2"
|
||||
|
||||
|
|
|
@ -231,6 +231,7 @@ unsigned long radix_tree_next_hole(struct radix_tree_root *root,
|
|||
unsigned long radix_tree_prev_hole(struct radix_tree_root *root,
|
||||
unsigned long index, unsigned long max_scan);
|
||||
int radix_tree_preload(gfp_t gfp_mask);
|
||||
int radix_tree_maybe_preload(gfp_t gfp_mask);
|
||||
void radix_tree_init(void);
|
||||
void *radix_tree_tag_set(struct radix_tree_root *root,
|
||||
unsigned long index, unsigned int tag);
|
||||
|
|
|
@ -90,6 +90,7 @@ struct sched_param {
|
|||
#include <linux/latencytop.h>
|
||||
#include <linux/cred.h>
|
||||
#include <linux/llist.h>
|
||||
#include <linux/uidgid.h>
|
||||
|
||||
#include <asm/processor.h>
|
||||
|
||||
|
@ -2721,6 +2722,15 @@ extern int __cond_resched_softirq(void);
|
|||
__cond_resched_softirq(); \
|
||||
})
|
||||
|
||||
static inline void cond_resched_rcu(void)
|
||||
{
|
||||
#if defined(CONFIG_DEBUG_ATOMIC_SLEEP) || !defined(CONFIG_PREEMPT_RCU)
|
||||
rcu_read_unlock();
|
||||
cond_resched();
|
||||
rcu_read_lock();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Does a critical section need to be broken due to another
|
||||
* task waiting?: (technically does not depend on CONFIG_PREEMPT,
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
#ifndef __SHMEM_FS_H
|
||||
#define __SHMEM_FS_H
|
||||
|
||||
#include <linux/file.h>
|
||||
#include <linux/swap.h>
|
||||
#include <linux/mempolicy.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/percpu_counter.h>
|
||||
#include <linux/xattr.h>
|
||||
|
||||
/* inode in-kernel data */
|
||||
|
||||
struct shmem_inode_info {
|
||||
spinlock_t lock;
|
||||
unsigned int seals; /* shmem seals */
|
||||
unsigned long flags;
|
||||
unsigned long alloced; /* data pages alloced to file */
|
||||
union {
|
||||
|
@ -18,7 +21,7 @@ struct shmem_inode_info {
|
|||
};
|
||||
struct shared_policy policy; /* NUMA memory alloc policy */
|
||||
struct list_head swaplist; /* chain of maybes on swap */
|
||||
struct list_head xattr_list; /* list of shmem_xattr */
|
||||
struct simple_xattrs xattrs; /* list of xattrs */
|
||||
struct inode vfs_inode;
|
||||
};
|
||||
|
||||
|
@ -46,6 +49,8 @@ extern int shmem_init(void);
|
|||
extern int shmem_fill_super(struct super_block *sb, void *data, int silent);
|
||||
extern struct file *shmem_file_setup(const char *name,
|
||||
loff_t size, unsigned long flags);
|
||||
extern struct file *shmem_kernel_file_setup(const char *name, loff_t size,
|
||||
unsigned long flags);
|
||||
extern int shmem_zero_setup(struct vm_area_struct *);
|
||||
extern int shmem_lock(struct file *file, int lock, struct user_struct *user);
|
||||
extern void shmem_unlock_mapping(struct address_space *mapping);
|
||||
|
@ -61,4 +66,19 @@ static inline struct page *shmem_read_mapping_page(
|
|||
mapping_gfp_mask(mapping));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TMPFS
|
||||
|
||||
extern int shmem_add_seals(struct file *file, unsigned int seals);
|
||||
extern int shmem_get_seals(struct file *file);
|
||||
extern long shmem_fcntl(struct file *file, unsigned int cmd, unsigned long arg);
|
||||
|
||||
#else
|
||||
|
||||
static inline long shmem_fcntl(struct file *f, unsigned int c, unsigned long a)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/uidgid.h>
|
||||
|
||||
struct kstat {
|
||||
u64 ino;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/uidgid.h>
|
||||
|
||||
/* size of the nodename buffer */
|
||||
#define UNX_MAXNODENAME 32
|
||||
|
|
|
@ -59,7 +59,9 @@
|
|||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
struct inode;
|
||||
struct dentry;
|
||||
|
@ -96,6 +98,52 @@ ssize_t vfs_getxattr_alloc(struct dentry *dentry, const char *name,
|
|||
char **xattr_value, size_t size, gfp_t flags);
|
||||
int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name,
|
||||
const char *value, size_t size, gfp_t flags);
|
||||
|
||||
struct simple_xattrs {
|
||||
struct list_head head;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct simple_xattr {
|
||||
struct list_head list;
|
||||
char *name;
|
||||
size_t size;
|
||||
char value[0];
|
||||
};
|
||||
|
||||
/*
|
||||
* initialize the simple_xattrs structure
|
||||
*/
|
||||
static inline void simple_xattrs_init(struct simple_xattrs *xattrs)
|
||||
{
|
||||
INIT_LIST_HEAD(&xattrs->head);
|
||||
spin_lock_init(&xattrs->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* free all the xattrs
|
||||
*/
|
||||
static inline void simple_xattrs_free(struct simple_xattrs *xattrs)
|
||||
{
|
||||
struct simple_xattr *xattr, *node;
|
||||
|
||||
list_for_each_entry_safe(xattr, node, &xattrs->head, list) {
|
||||
kfree(xattr->name);
|
||||
kfree(xattr);
|
||||
}
|
||||
}
|
||||
|
||||
struct simple_xattr *simple_xattr_alloc(const void *value, size_t size);
|
||||
int simple_xattr_get(struct simple_xattrs *xattrs, const char *name,
|
||||
void *buffer, size_t size);
|
||||
int simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
|
||||
const void *value, size_t size, int flags);
|
||||
int simple_xattr_remove(struct simple_xattrs *xattrs, const char *name);
|
||||
ssize_t simple_xattr_list(struct simple_xattrs *xattrs, char *buffer,
|
||||
size_t size);
|
||||
void simple_xattr_list_add(struct simple_xattrs *xattrs,
|
||||
struct simple_xattr *new_xattr);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* _LINUX_XATTR_H */
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#ifndef __NETNS_IPV4_H__
|
||||
#define __NETNS_IPV4_H__
|
||||
|
||||
#include <linux/uidgid.h>
|
||||
#include <net/inet_frag.h>
|
||||
|
||||
struct ctl_table_header;
|
||||
|
|
|
@ -416,7 +416,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
|
|||
atomic_dec(&inode->i_writecount);
|
||||
mutex_lock(&mapping->i_mmap_mutex);
|
||||
if (tmp->vm_flags & VM_SHARED)
|
||||
mapping->i_mmap_writable++;
|
||||
atomic_inc(&mapping->i_mmap_writable);
|
||||
flush_dcache_mmap_lock(mapping);
|
||||
/* insert tmp into the share list, just after mpnt */
|
||||
vma_prio_tree_add(tmp, mpnt);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/hardirq.h> /* in_interrupt() */
|
||||
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
@ -194,7 +195,12 @@ radix_tree_node_alloc(struct radix_tree_root *root)
|
|||
struct radix_tree_node *ret = NULL;
|
||||
gfp_t gfp_mask = root_gfp_mask(root);
|
||||
|
||||
if (!(gfp_mask & __GFP_WAIT)) {
|
||||
/*
|
||||
* Preload code isn't irq safe and it doesn't make sence to use
|
||||
* preloading in the interrupt anyway as all the allocations have to
|
||||
* be atomic. So just do normal allocation when in interrupt.
|
||||
*/
|
||||
if (!(gfp_mask & __GFP_WAIT) && !in_interrupt()) {
|
||||
struct radix_tree_preload *rtp;
|
||||
|
||||
/*
|
||||
|
@ -251,7 +257,7 @@ radix_tree_node_free(struct radix_tree_node *node)
|
|||
* To make use of this facility, the radix tree must be initialised without
|
||||
* __GFP_WAIT being passed to INIT_RADIX_TREE().
|
||||
*/
|
||||
int radix_tree_preload(gfp_t gfp_mask)
|
||||
static int __radix_tree_preload(gfp_t gfp_mask)
|
||||
{
|
||||
struct radix_tree_preload *rtp;
|
||||
struct radix_tree_node *node;
|
||||
|
@ -275,8 +281,39 @@ int radix_tree_preload(gfp_t gfp_mask)
|
|||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load up this CPU's radix_tree_node buffer with sufficient objects to
|
||||
* ensure that the addition of a single element in the tree cannot fail. On
|
||||
* success, return zero, with preemption disabled. On error, return -ENOMEM
|
||||
* with preemption not disabled.
|
||||
*
|
||||
* To make use of this facility, the radix tree must be initialised without
|
||||
* __GFP_WAIT being passed to INIT_RADIX_TREE().
|
||||
*/
|
||||
int radix_tree_preload(gfp_t gfp_mask)
|
||||
{
|
||||
/* Warn on non-sensical use... */
|
||||
WARN_ON_ONCE(!(gfp_mask & __GFP_WAIT));
|
||||
return __radix_tree_preload(gfp_mask);
|
||||
}
|
||||
EXPORT_SYMBOL(radix_tree_preload);
|
||||
|
||||
/*
|
||||
* The same as above function, except we don't guarantee preloading happens.
|
||||
* We do it, if we decide it helps. On success, return zero with preemption
|
||||
* disabled. On error, return -ENOMEM with preemption not disabled.
|
||||
*/
|
||||
int radix_tree_maybe_preload(gfp_t gfp_mask)
|
||||
{
|
||||
if (gfp_mask & __GFP_WAIT)
|
||||
return __radix_tree_preload(gfp_mask);
|
||||
/* Preloading doesn't help anything with this gfp mask, skip it */
|
||||
preempt_disable();
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(radix_tree_maybe_preload);
|
||||
|
||||
/*
|
||||
* Return the maximum key which can be store into a
|
||||
* radix tree with height HEIGHT.
|
||||
|
|
|
@ -453,7 +453,7 @@ int add_to_page_cache_locked(struct page *page, struct address_space *mapping,
|
|||
if (error)
|
||||
goto out;
|
||||
|
||||
error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
|
||||
error = radix_tree_maybe_preload(gfp_mask & ~__GFP_HIGHMEM);
|
||||
if (error == 0) {
|
||||
page_cache_get(page);
|
||||
page->mapping = mapping;
|
||||
|
|
15
mm/madvise.c
15
mm/madvise.c
|
@ -11,8 +11,10 @@
|
|||
#include <linux/mempolicy.h>
|
||||
#include <linux/page-isolation.h>
|
||||
#include <linux/hugetlb.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/ksm.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/file.h>
|
||||
|
||||
/*
|
||||
|
@ -202,8 +204,7 @@ static long madvise_remove(struct vm_area_struct *vma,
|
|||
struct vm_area_struct **prev,
|
||||
unsigned long start, unsigned long end)
|
||||
{
|
||||
struct address_space *mapping;
|
||||
loff_t offset, endoff;
|
||||
loff_t offset;
|
||||
int error;
|
||||
struct file *f;
|
||||
|
||||
|
@ -221,22 +222,20 @@ static long madvise_remove(struct vm_area_struct *vma,
|
|||
if ((vma->vm_flags & (VM_SHARED|VM_WRITE)) != (VM_SHARED|VM_WRITE))
|
||||
return -EACCES;
|
||||
|
||||
mapping = vma->vm_file->f_mapping;
|
||||
|
||||
offset = (loff_t)(start - vma->vm_start)
|
||||
+ ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
|
||||
endoff = (loff_t)(end - vma->vm_start - 1)
|
||||
+ ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
|
||||
|
||||
/*
|
||||
* vmtruncate_range may need to take i_mutex. We need to
|
||||
* Filesystem's fallocate may need to take i_mutex. We need to
|
||||
* explicitly grab a reference because the vma (and hence the
|
||||
* vma's reference to the file) can go away as soon as we drop
|
||||
* mmap_sem.
|
||||
*/
|
||||
get_file(f);
|
||||
up_read(¤t->mm->mmap_sem);
|
||||
error = vmtruncate_range(mapping->host, offset, endoff);
|
||||
error = do_fallocate(f,
|
||||
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
|
||||
offset, end - start);
|
||||
fput(f);
|
||||
down_read(¤t->mm->mmap_sem);
|
||||
return error;
|
||||
|
|
|
@ -3372,7 +3372,7 @@ void mem_cgroup_end_migration(struct mem_cgroup *memcg,
|
|||
void mem_cgroup_replace_page_cache(struct page *oldpage,
|
||||
struct page *newpage)
|
||||
{
|
||||
struct mem_cgroup *memcg;
|
||||
struct mem_cgroup *memcg = NULL;
|
||||
struct page_cgroup *pc;
|
||||
enum charge_type type = MEM_CGROUP_CHARGE_TYPE_CACHE;
|
||||
|
||||
|
@ -3382,11 +3382,20 @@ void mem_cgroup_replace_page_cache(struct page *oldpage,
|
|||
pc = lookup_page_cgroup(oldpage);
|
||||
/* fix accounting on old pages */
|
||||
lock_page_cgroup(pc);
|
||||
if (PageCgroupUsed(pc)) {
|
||||
memcg = pc->mem_cgroup;
|
||||
mem_cgroup_charge_statistics(memcg, false, -1);
|
||||
ClearPageCgroupUsed(pc);
|
||||
}
|
||||
unlock_page_cgroup(pc);
|
||||
|
||||
/*
|
||||
* When called from shmem_replace_page(), in some cases the
|
||||
* oldpage has already been charged, and in some cases not.
|
||||
*/
|
||||
if (!memcg)
|
||||
return;
|
||||
|
||||
if (PageSwapBacked(oldpage))
|
||||
type = MEM_CGROUP_CHARGE_TYPE_SHMEM;
|
||||
|
||||
|
|
36
mm/mmap.c
36
mm/mmap.c
|
@ -207,7 +207,7 @@ static void __remove_shared_vm_struct(struct vm_area_struct *vma,
|
|||
if (vma->vm_flags & VM_DENYWRITE)
|
||||
atomic_inc(&file->f_path.dentry->d_inode->i_writecount);
|
||||
if (vma->vm_flags & VM_SHARED)
|
||||
mapping->i_mmap_writable--;
|
||||
mapping_unmap_writable(mapping);
|
||||
|
||||
flush_dcache_mmap_lock(mapping);
|
||||
if (unlikely(vma->vm_flags & VM_NONLINEAR))
|
||||
|
@ -453,7 +453,7 @@ static void __vma_link_file(struct vm_area_struct *vma)
|
|||
if (vma->vm_flags & VM_DENYWRITE)
|
||||
atomic_dec(&file->f_path.dentry->d_inode->i_writecount);
|
||||
if (vma->vm_flags & VM_SHARED)
|
||||
mapping->i_mmap_writable++;
|
||||
atomic_inc(&mapping->i_mmap_writable);
|
||||
|
||||
flush_dcache_mmap_lock(mapping);
|
||||
if (unlikely(vma->vm_flags & VM_NONLINEAR))
|
||||
|
@ -1290,11 +1290,9 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
|
|||
{
|
||||
struct mm_struct *mm = current->mm;
|
||||
struct vm_area_struct *vma, *prev;
|
||||
int correct_wcount = 0;
|
||||
int error;
|
||||
struct rb_node **rb_link, *rb_parent;
|
||||
unsigned long charged = 0;
|
||||
struct inode *inode = file ? file->f_path.dentry->d_inode : NULL;
|
||||
|
||||
/* Check against address space limit. */
|
||||
if (!may_expand_vm(mm, len >> PAGE_SHIFT)) {
|
||||
|
@ -1383,8 +1381,18 @@ munmap_back:
|
|||
error = deny_write_access(file);
|
||||
if (error)
|
||||
goto free_vma;
|
||||
correct_wcount = 1;
|
||||
}
|
||||
if (vm_flags & VM_SHARED) {
|
||||
error = mapping_map_writable(file->f_mapping);
|
||||
if (error)
|
||||
goto allow_write_and_free_vma;
|
||||
}
|
||||
|
||||
/* ->mmap() can change vma->vm_file, but must guarantee that
|
||||
* vma_link() below can deny write-access if VM_DENYWRITE is set
|
||||
* and map writably if VM_SHARED is set. This usually means the
|
||||
* new file must not have been exposed to user-space, yet.
|
||||
*/
|
||||
vma->vm_file = file;
|
||||
get_file(file);
|
||||
error = file->f_op->mmap(file, vma);
|
||||
|
@ -1425,11 +1433,14 @@ munmap_back:
|
|||
}
|
||||
|
||||
vma_link(mm, vma, prev, rb_link, rb_parent);
|
||||
file = vma->vm_file;
|
||||
|
||||
/* Once vma denies write, undo our temporary denial count */
|
||||
if (correct_wcount)
|
||||
atomic_inc(&inode->i_writecount);
|
||||
if (file) {
|
||||
if (vm_flags & VM_SHARED)
|
||||
mapping_unmap_writable(file->f_mapping);
|
||||
if (vm_flags & VM_DENYWRITE)
|
||||
allow_write_access(file);
|
||||
}
|
||||
file = vma->vm_file;
|
||||
out:
|
||||
perf_event_mmap(vma);
|
||||
|
||||
|
@ -1443,14 +1454,17 @@ out:
|
|||
return addr;
|
||||
|
||||
unmap_and_free_vma:
|
||||
if (correct_wcount)
|
||||
atomic_inc(&inode->i_writecount);
|
||||
vma->vm_file = NULL;
|
||||
fput(file);
|
||||
|
||||
/* Undo any partial mapping done by a device driver. */
|
||||
unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end);
|
||||
charged = 0;
|
||||
if (vm_flags & VM_SHARED)
|
||||
mapping_unmap_writable(file->f_mapping);
|
||||
allow_write_and_free_vma:
|
||||
if (vm_flags & VM_DENYWRITE)
|
||||
allow_write_access(file);
|
||||
free_vma:
|
||||
kmem_cache_free(vm_area_cachep, vma);
|
||||
unacct_error:
|
||||
|
|
1182
mm/shmem.c
1182
mm/shmem.c
File diff suppressed because it is too large
Load diff
|
@ -38,6 +38,7 @@ static struct backing_dev_info swap_backing_dev_info = {
|
|||
struct address_space swapper_spaces[MAX_SWAPFILES] = {
|
||||
[0 ... MAX_SWAPFILES - 1] = {
|
||||
.page_tree = RADIX_TREE_INIT(GFP_ATOMIC|__GFP_NOWARN),
|
||||
.i_mmap_writable = ATOMIC_INIT(0),
|
||||
.a_ops = &swap_aops,
|
||||
.backing_dev_info = &swap_backing_dev_info,
|
||||
}
|
||||
|
@ -120,7 +121,7 @@ int add_to_swap_cache(struct page *page, swp_entry_t entry, gfp_t gfp_mask)
|
|||
{
|
||||
int error;
|
||||
|
||||
error = radix_tree_preload(gfp_mask);
|
||||
error = radix_tree_maybe_preload(gfp_mask);
|
||||
if (!error) {
|
||||
error = __add_to_swap_cache(page, entry);
|
||||
radix_tree_preload_end();
|
||||
|
@ -326,7 +327,7 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
|
|||
/*
|
||||
* call radix_tree_preload() while we can wait.
|
||||
*/
|
||||
err = radix_tree_preload(gfp_mask & GFP_KERNEL);
|
||||
err = radix_tree_maybe_preload(gfp_mask & GFP_KERNEL);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
|
|
Loading…
Reference in a new issue