mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-11-18 15:44:02 +08:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (38 commits) direct I/O fallback sync simplification ocfs: stop using do_sync_mapping_range cleanup blockdev_direct_IO locking make generic_acl slightly more generic sanitize xattr handler prototypes libfs: move EXPORT_SYMBOL for d_alloc_name vfs: force reval of target when following LAST_BIND symlinks (try #7) ima: limit imbalance msg Untangling ima mess, part 3: kill dead code in ima Untangling ima mess, part 2: deal with counters Untangling ima mess, part 1: alloc_file() O_TRUNC open shouldn't fail after file truncation ima: call ima_inode_free ima_inode_free IMA: clean up the IMA counts updating code ima: only insert at inode creation time ima: valid return code from ima_inode_alloc fs: move get_empty_filp() deffinition to internal.h Sanitize exec_permission_lite() Kill cached_lookup() and real_lookup() Kill path_lookup_open() ... Trivial conflicts in fs/direct-io.c
This commit is contained in:
commit
bac5e54c29
@ -2200,7 +2200,7 @@ pfm_alloc_file(pfm_context_t *ctx)
|
||||
{
|
||||
struct file *file;
|
||||
struct inode *inode;
|
||||
struct dentry *dentry;
|
||||
struct path path;
|
||||
char name[32];
|
||||
struct qstr this;
|
||||
|
||||
@ -2225,18 +2225,19 @@ pfm_alloc_file(pfm_context_t *ctx)
|
||||
/*
|
||||
* allocate a new dcache entry
|
||||
*/
|
||||
dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this);
|
||||
if (!dentry) {
|
||||
path.dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this);
|
||||
if (!path.dentry) {
|
||||
iput(inode);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
path.mnt = mntget(pfmfs_mnt);
|
||||
|
||||
dentry->d_op = &pfmfs_dentry_operations;
|
||||
d_add(dentry, inode);
|
||||
path.dentry->d_op = &pfmfs_dentry_operations;
|
||||
d_add(path.dentry, inode);
|
||||
|
||||
file = alloc_file(pfmfs_mnt, dentry, FMODE_READ, &pfm_file_ops);
|
||||
file = alloc_file(&path, FMODE_READ, &pfm_file_ops);
|
||||
if (!file) {
|
||||
dput(dentry);
|
||||
path_put(&path);
|
||||
return ERR_PTR(-ENFILE);
|
||||
}
|
||||
|
||||
|
@ -445,12 +445,7 @@ done:
|
||||
|
||||
int hpux_pipe(int *kstack_fildes)
|
||||
{
|
||||
int error;
|
||||
|
||||
lock_kernel();
|
||||
error = do_pipe_flags(kstack_fildes, 0);
|
||||
unlock_kernel();
|
||||
return error;
|
||||
return do_pipe_flags(kstack_fildes, 0);
|
||||
}
|
||||
|
||||
/* lies - says it works, but it really didn't lock anything */
|
||||
|
@ -30,7 +30,6 @@ struct mmap_arg_struct;
|
||||
asmlinkage long sys32_mmap(struct mmap_arg_struct __user *);
|
||||
asmlinkage long sys32_mprotect(unsigned long, size_t, unsigned long);
|
||||
|
||||
asmlinkage long sys32_pipe(int __user *);
|
||||
struct sigaction32;
|
||||
struct old_sigaction32;
|
||||
asmlinkage long sys32_rt_sigaction(int, struct sigaction32 __user *,
|
||||
|
@ -12,7 +12,6 @@ struct pt_regs;
|
||||
struct sigaction;
|
||||
asmlinkage long xtensa_execve(char*, char**, char**, struct pt_regs*);
|
||||
asmlinkage long xtensa_clone(unsigned long, unsigned long, struct pt_regs*);
|
||||
asmlinkage long xtensa_pipe(int __user *);
|
||||
asmlinkage long xtensa_ptrace(long, long, long, long);
|
||||
asmlinkage long xtensa_sigreturn(struct pt_regs*);
|
||||
asmlinkage long xtensa_rt_sigreturn(struct pt_regs*);
|
||||
|
@ -94,7 +94,7 @@ __SYSCALL( 35, sys_readlink, 3)
|
||||
#define __NR_mknod 36
|
||||
__SYSCALL( 36, sys_mknod, 3)
|
||||
#define __NR_pipe 37
|
||||
__SYSCALL( 37, xtensa_pipe, 1)
|
||||
__SYSCALL( 37, sys_pipe, 1)
|
||||
#define __NR_unlink 38
|
||||
__SYSCALL( 38, sys_unlink, 1)
|
||||
#define __NR_rmdir 39
|
||||
|
@ -39,24 +39,6 @@ syscall_t sys_call_table[__NR_syscall_count] /* FIXME __cacheline_aligned */= {
|
||||
#include <asm/unistd.h>
|
||||
};
|
||||
|
||||
/*
|
||||
* xtensa_pipe() is the normal C calling standard for creating a pipe. It's not
|
||||
* the way unix traditional does this, though.
|
||||
*/
|
||||
|
||||
asmlinkage long xtensa_pipe(int __user *userfds)
|
||||
{
|
||||
int fd[2];
|
||||
int error;
|
||||
|
||||
error = do_pipe_flags(fd, 0);
|
||||
if (!error) {
|
||||
if (copy_to_user(userfds, fd, 2 * sizeof(int)))
|
||||
error = -EFAULT;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
@ -492,6 +492,7 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
|
||||
int is_async, int *fd)
|
||||
{
|
||||
struct ib_uverbs_event_file *ev_file;
|
||||
struct path path;
|
||||
struct file *filp;
|
||||
int ret;
|
||||
|
||||
@ -519,8 +520,10 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
|
||||
* system call on a uverbs file, which will already have a
|
||||
* module reference.
|
||||
*/
|
||||
filp = alloc_file(uverbs_event_mnt, dget(uverbs_event_mnt->mnt_root),
|
||||
FMODE_READ, fops_get(&uverbs_event_fops));
|
||||
path.mnt = uverbs_event_mnt;
|
||||
path.dentry = uverbs_event_mnt->mnt_root;
|
||||
path_get(&path);
|
||||
filp = alloc_file(&path, FMODE_READ, fops_get(&uverbs_event_fops));
|
||||
if (!filp) {
|
||||
ret = -ENFILE;
|
||||
goto err_fd;
|
||||
@ -531,6 +534,8 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
|
||||
return filp;
|
||||
|
||||
err_fd:
|
||||
fops_put(&uverbs_event_fops);
|
||||
path_put(&path);
|
||||
put_unused_fd(*fd);
|
||||
|
||||
err:
|
||||
|
@ -403,7 +403,7 @@ static void dst_node_cleanup(struct dst_node *n)
|
||||
|
||||
if (n->bdev) {
|
||||
sync_blockdev(n->bdev);
|
||||
blkdev_put(n->bdev, FMODE_READ|FMODE_WRITE);
|
||||
close_bdev_exclusive(n->bdev, FMODE_READ|FMODE_WRITE);
|
||||
}
|
||||
|
||||
dst_state_lock(st);
|
||||
@ -463,37 +463,6 @@ void dst_node_put(struct dst_node *n)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function finds devices major/minor numbers for given pathname.
|
||||
*/
|
||||
static int dst_lookup_device(const char *path, dev_t *dev)
|
||||
{
|
||||
int err;
|
||||
struct nameidata nd;
|
||||
struct inode *inode;
|
||||
|
||||
err = path_lookup(path, LOOKUP_FOLLOW, &nd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
inode = nd.path.dentry->d_inode;
|
||||
if (!inode) {
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!S_ISBLK(inode->i_mode)) {
|
||||
err = -ENOTBLK;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*dev = inode->i_rdev;
|
||||
|
||||
out:
|
||||
path_put(&nd.path);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setting up export device: lookup by the name, get its size
|
||||
* and setup listening socket, which will accept clients, which
|
||||
@ -503,17 +472,12 @@ static int dst_setup_export(struct dst_node *n, struct dst_ctl *ctl,
|
||||
struct dst_export_ctl *le)
|
||||
{
|
||||
int err;
|
||||
dev_t dev = 0; /* gcc likes to scream here */
|
||||
|
||||
snprintf(n->info->local, sizeof(n->info->local), "%s", le->device);
|
||||
|
||||
err = dst_lookup_device(le->device, &dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
n->bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE);
|
||||
if (!n->bdev)
|
||||
return -ENODEV;
|
||||
n->bdev = open_bdev_exclusive(le->device, FMODE_READ|FMODE_WRITE, NULL);
|
||||
if (IS_ERR(n->bdev))
|
||||
return PTR_ERR(n->bdev);
|
||||
|
||||
if (n->size != 0)
|
||||
n->size = min_t(loff_t, n->bdev->bd_inode->i_size, n->size);
|
||||
@ -528,7 +492,7 @@ static int dst_setup_export(struct dst_node *n, struct dst_ctl *ctl,
|
||||
return 0;
|
||||
|
||||
err_out_cleanup:
|
||||
blkdev_put(n->bdev, FMODE_READ|FMODE_WRITE);
|
||||
close_bdev_exclusive(n->bdev, FMODE_READ|FMODE_WRITE);
|
||||
n->bdev = NULL;
|
||||
|
||||
return err;
|
||||
|
@ -88,7 +88,7 @@ struct file *anon_inode_getfile(const char *name,
|
||||
void *priv, int flags)
|
||||
{
|
||||
struct qstr this;
|
||||
struct dentry *dentry;
|
||||
struct path path;
|
||||
struct file *file;
|
||||
int error;
|
||||
|
||||
@ -106,10 +106,11 @@ struct file *anon_inode_getfile(const char *name,
|
||||
this.name = name;
|
||||
this.len = strlen(name);
|
||||
this.hash = 0;
|
||||
dentry = d_alloc(anon_inode_mnt->mnt_sb->s_root, &this);
|
||||
if (!dentry)
|
||||
path.dentry = d_alloc(anon_inode_mnt->mnt_sb->s_root, &this);
|
||||
if (!path.dentry)
|
||||
goto err_module;
|
||||
|
||||
path.mnt = mntget(anon_inode_mnt);
|
||||
/*
|
||||
* We know the anon_inode inode count is always greater than zero,
|
||||
* so we can avoid doing an igrab() and we can use an open-coded
|
||||
@ -117,14 +118,13 @@ struct file *anon_inode_getfile(const char *name,
|
||||
*/
|
||||
atomic_inc(&anon_inode_inode->i_count);
|
||||
|
||||
dentry->d_op = &anon_inodefs_dentry_operations;
|
||||
path.dentry->d_op = &anon_inodefs_dentry_operations;
|
||||
/* Do not publish this dentry inside the global dentry hash table */
|
||||
dentry->d_flags &= ~DCACHE_UNHASHED;
|
||||
d_instantiate(dentry, anon_inode_inode);
|
||||
path.dentry->d_flags &= ~DCACHE_UNHASHED;
|
||||
d_instantiate(path.dentry, anon_inode_inode);
|
||||
|
||||
error = -ENFILE;
|
||||
file = alloc_file(anon_inode_mnt, dentry,
|
||||
FMODE_READ | FMODE_WRITE, fops);
|
||||
file = alloc_file(&path, FMODE_READ | FMODE_WRITE, fops);
|
||||
if (!file)
|
||||
goto err_dput;
|
||||
file->f_mapping = anon_inode_inode->i_mapping;
|
||||
@ -137,7 +137,7 @@ struct file *anon_inode_getfile(const char *name,
|
||||
return file;
|
||||
|
||||
err_dput:
|
||||
dput(dentry);
|
||||
path_put(&path);
|
||||
err_module:
|
||||
module_put(fops->owner);
|
||||
return ERR_PTR(error);
|
||||
|
@ -73,13 +73,13 @@ static struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
|
||||
return acl;
|
||||
}
|
||||
|
||||
static int btrfs_xattr_get_acl(struct inode *inode, int type,
|
||||
void *value, size_t size)
|
||||
static int btrfs_xattr_acl_get(struct dentry *dentry, const char *name,
|
||||
void *value, size_t size, int type)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int ret = 0;
|
||||
|
||||
acl = btrfs_get_acl(inode, type);
|
||||
acl = btrfs_get_acl(dentry->d_inode, type);
|
||||
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
@ -151,8 +151,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int btrfs_xattr_set_acl(struct inode *inode, int type,
|
||||
const void *value, size_t size)
|
||||
static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags, int type)
|
||||
{
|
||||
int ret = 0;
|
||||
struct posix_acl *acl = NULL;
|
||||
@ -167,38 +167,13 @@ static int btrfs_xattr_set_acl(struct inode *inode, int type,
|
||||
}
|
||||
}
|
||||
|
||||
ret = btrfs_set_acl(inode, acl, type);
|
||||
ret = btrfs_set_acl(dentry->d_inode, acl, type);
|
||||
|
||||
posix_acl_release(acl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int btrfs_xattr_acl_access_get(struct inode *inode, const char *name,
|
||||
void *value, size_t size)
|
||||
{
|
||||
return btrfs_xattr_get_acl(inode, ACL_TYPE_ACCESS, value, size);
|
||||
}
|
||||
|
||||
static int btrfs_xattr_acl_access_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
return btrfs_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
|
||||
}
|
||||
|
||||
static int btrfs_xattr_acl_default_get(struct inode *inode, const char *name,
|
||||
void *value, size_t size)
|
||||
{
|
||||
return btrfs_xattr_get_acl(inode, ACL_TYPE_DEFAULT, value, size);
|
||||
}
|
||||
|
||||
static int btrfs_xattr_acl_default_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
return btrfs_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
|
||||
}
|
||||
|
||||
int btrfs_check_acl(struct inode *inode, int mask)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
@ -303,14 +278,16 @@ int btrfs_acl_chmod(struct inode *inode)
|
||||
|
||||
struct xattr_handler btrfs_xattr_acl_default_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_DEFAULT,
|
||||
.get = btrfs_xattr_acl_default_get,
|
||||
.set = btrfs_xattr_acl_default_set,
|
||||
.flags = ACL_TYPE_DEFAULT,
|
||||
.get = btrfs_xattr_acl_get,
|
||||
.set = btrfs_xattr_acl_set,
|
||||
};
|
||||
|
||||
struct xattr_handler btrfs_xattr_acl_access_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_ACCESS,
|
||||
.get = btrfs_xattr_acl_access_get,
|
||||
.set = btrfs_xattr_acl_access_set,
|
||||
.flags = ACL_TYPE_ACCESS,
|
||||
.get = btrfs_xattr_acl_get,
|
||||
.set = btrfs_xattr_acl_set,
|
||||
};
|
||||
|
||||
#else /* CONFIG_BTRFS_FS_POSIX_ACL */
|
||||
|
@ -84,7 +84,7 @@ int cachefiles_daemon_bind(struct cachefiles_cache *cache, char *args)
|
||||
static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache)
|
||||
{
|
||||
struct cachefiles_object *fsdef;
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
struct kstatfs stats;
|
||||
struct dentry *graveyard, *cachedir, *root;
|
||||
const struct cred *saved_cred;
|
||||
@ -114,15 +114,12 @@ static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache)
|
||||
_debug("- fsdef %p", fsdef);
|
||||
|
||||
/* look up the directory at the root of the cache */
|
||||
memset(&nd, 0, sizeof(nd));
|
||||
|
||||
ret = path_lookup(cache->rootdirname, LOOKUP_DIRECTORY, &nd);
|
||||
ret = kern_path(cache->rootdirname, LOOKUP_DIRECTORY, &path);
|
||||
if (ret < 0)
|
||||
goto error_open_root;
|
||||
|
||||
cache->mnt = mntget(nd.path.mnt);
|
||||
root = dget(nd.path.dentry);
|
||||
path_put(&nd.path);
|
||||
cache->mnt = path.mnt;
|
||||
root = path.dentry;
|
||||
|
||||
/* check parameters */
|
||||
ret = -EOPNOTSUPP;
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
#include <linux/mount.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/ima.h>
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
@ -923,7 +922,6 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)
|
||||
if (IS_ERR(file)) {
|
||||
ret = PTR_ERR(file);
|
||||
} else {
|
||||
ima_counts_get(file);
|
||||
ret = -EIO;
|
||||
if (file->f_op->write) {
|
||||
pos = (loff_t) page->index << PAGE_SHIFT;
|
||||
|
@ -978,6 +978,7 @@ struct dentry *d_alloc_name(struct dentry *parent, const char *name)
|
||||
q.hash = full_name_hash(q.name, q.len);
|
||||
return d_alloc(parent, &q);
|
||||
}
|
||||
EXPORT_SYMBOL(d_alloc_name);
|
||||
|
||||
/* the caller must hold dcache_lock */
|
||||
static void __d_instantiate(struct dentry *dentry, struct inode *inode)
|
||||
|
@ -35,7 +35,6 @@
|
||||
#include <linux/key.h>
|
||||
#include <linux/parser.h>
|
||||
#include <linux/fs_stack.h>
|
||||
#include <linux/ima.h>
|
||||
#include "ecryptfs_kernel.h"
|
||||
|
||||
/**
|
||||
@ -119,7 +118,6 @@ int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)
|
||||
const struct cred *cred = current_cred();
|
||||
struct ecryptfs_inode_info *inode_info =
|
||||
ecryptfs_inode_to_private(ecryptfs_dentry->d_inode);
|
||||
int opened_lower_file = 0;
|
||||
int rc = 0;
|
||||
|
||||
mutex_lock(&inode_info->lower_file_mutex);
|
||||
@ -136,12 +134,9 @@ int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)
|
||||
"for lower_dentry [0x%p] and lower_mnt [0x%p]; "
|
||||
"rc = [%d]\n", lower_dentry, lower_mnt, rc);
|
||||
inode_info->lower_file = NULL;
|
||||
} else
|
||||
opened_lower_file = 1;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&inode_info->lower_file_mutex);
|
||||
if (opened_lower_file)
|
||||
ima_counts_get(inode_info->lower_file);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -339,12 +339,12 @@ ext2_acl_chmod(struct inode *inode)
|
||||
* Extended attribut handlers
|
||||
*/
|
||||
static size_t
|
||||
ext2_xattr_list_acl_access(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
ext2_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_size,
|
||||
const char *name, size_t name_len, int type)
|
||||
{
|
||||
const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
|
||||
|
||||
if (!test_opt(inode->i_sb, POSIX_ACL))
|
||||
if (!test_opt(dentry->d_sb, POSIX_ACL))
|
||||
return 0;
|
||||
if (list && size <= list_size)
|
||||
memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
|
||||
@ -352,12 +352,12 @@ ext2_xattr_list_acl_access(struct inode *inode, char *list, size_t list_size,
|
||||
}
|
||||
|
||||
static size_t
|
||||
ext2_xattr_list_acl_default(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
ext2_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_size,
|
||||
const char *name, size_t name_len, int type)
|
||||
{
|
||||
const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
|
||||
|
||||
if (!test_opt(inode->i_sb, POSIX_ACL))
|
||||
if (!test_opt(dentry->d_sb, POSIX_ACL))
|
||||
return 0;
|
||||
if (list && size <= list_size)
|
||||
memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
|
||||
@ -365,15 +365,18 @@ ext2_xattr_list_acl_default(struct inode *inode, char *list, size_t list_size,
|
||||
}
|
||||
|
||||
static int
|
||||
ext2_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
|
||||
ext2_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer,
|
||||
size_t size, int type)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int error;
|
||||
|
||||
if (!test_opt(inode->i_sb, POSIX_ACL))
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
if (!test_opt(dentry->d_sb, POSIX_ACL))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
acl = ext2_get_acl(inode, type);
|
||||
acl = ext2_get_acl(dentry->d_inode, type);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
if (acl == NULL)
|
||||
@ -385,33 +388,17 @@ ext2_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
|
||||
}
|
||||
|
||||
static int
|
||||
ext2_xattr_get_acl_access(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return ext2_xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
ext2_xattr_get_acl_default(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return ext2_xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
ext2_xattr_set_acl(struct inode *inode, int type, const void *value,
|
||||
size_t size)
|
||||
ext2_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
|
||||
size_t size, int flags, int type)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int error;
|
||||
|
||||
if (!test_opt(inode->i_sb, POSIX_ACL))
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
if (!test_opt(dentry->d_sb, POSIX_ACL))
|
||||
return -EOPNOTSUPP;
|
||||
if (!is_owner_or_cap(inode))
|
||||
if (!is_owner_or_cap(dentry->d_inode))
|
||||
return -EPERM;
|
||||
|
||||
if (value) {
|
||||
@ -426,41 +413,25 @@ ext2_xattr_set_acl(struct inode *inode, int type, const void *value,
|
||||
} else
|
||||
acl = NULL;
|
||||
|
||||
error = ext2_set_acl(inode, type, acl);
|
||||
error = ext2_set_acl(dentry->d_inode, type, acl);
|
||||
|
||||
release_and_out:
|
||||
posix_acl_release(acl);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
ext2_xattr_set_acl_access(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return ext2_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
|
||||
}
|
||||
|
||||
static int
|
||||
ext2_xattr_set_acl_default(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return ext2_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
|
||||
}
|
||||
|
||||
struct xattr_handler ext2_xattr_acl_access_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_ACCESS,
|
||||
.flags = ACL_TYPE_ACCESS,
|
||||
.list = ext2_xattr_list_acl_access,
|
||||
.get = ext2_xattr_get_acl_access,
|
||||
.set = ext2_xattr_set_acl_access,
|
||||
.get = ext2_xattr_get_acl,
|
||||
.set = ext2_xattr_set_acl,
|
||||
};
|
||||
|
||||
struct xattr_handler ext2_xattr_acl_default_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_DEFAULT,
|
||||
.flags = ACL_TYPE_DEFAULT,
|
||||
.list = ext2_xattr_list_acl_default,
|
||||
.get = ext2_xattr_get_acl_default,
|
||||
.set = ext2_xattr_set_acl_default,
|
||||
.get = ext2_xattr_get_acl,
|
||||
.set = ext2_xattr_set_acl,
|
||||
};
|
||||
|
@ -60,6 +60,7 @@
|
||||
#include <linux/mbcache.h>
|
||||
#include <linux/quotaops.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/security.h>
|
||||
#include "ext2.h"
|
||||
#include "xattr.h"
|
||||
#include "acl.h"
|
||||
@ -249,8 +250,9 @@ cleanup:
|
||||
* used / required on success.
|
||||
*/
|
||||
static int
|
||||
ext2_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
|
||||
ext2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct buffer_head *bh = NULL;
|
||||
struct ext2_xattr_entry *entry;
|
||||
char *end;
|
||||
@ -300,9 +302,10 @@ bad_block: ext2_error(inode->i_sb, "ext2_xattr_list",
|
||||
ext2_xattr_handler(entry->e_name_index);
|
||||
|
||||
if (handler) {
|
||||
size_t size = handler->list(inode, buffer, rest,
|
||||
size_t size = handler->list(dentry, buffer, rest,
|
||||
entry->e_name,
|
||||
entry->e_name_len);
|
||||
entry->e_name_len,
|
||||
handler->flags);
|
||||
if (buffer) {
|
||||
if (size > rest) {
|
||||
error = -ERANGE;
|
||||
@ -330,7 +333,7 @@ cleanup:
|
||||
ssize_t
|
||||
ext2_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
||||
{
|
||||
return ext2_xattr_list(dentry->d_inode, buffer, size);
|
||||
return ext2_xattr_list(dentry, buffer, size);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -11,8 +11,8 @@
|
||||
#include "xattr.h"
|
||||
|
||||
static size_t
|
||||
ext2_xattr_security_list(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
ext2_xattr_security_list(struct dentry *dentry, char *list, size_t list_size,
|
||||
const char *name, size_t name_len, int type)
|
||||
{
|
||||
const int prefix_len = XATTR_SECURITY_PREFIX_LEN;
|
||||
const size_t total_len = prefix_len + name_len + 1;
|
||||
@ -26,22 +26,22 @@ ext2_xattr_security_list(struct inode *inode, char *list, size_t list_size,
|
||||
}
|
||||
|
||||
static int
|
||||
ext2_xattr_security_get(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
ext2_xattr_security_get(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
return ext2_xattr_get(inode, EXT2_XATTR_INDEX_SECURITY, name,
|
||||
return ext2_xattr_get(dentry->d_inode, EXT2_XATTR_INDEX_SECURITY, name,
|
||||
buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
ext2_xattr_security_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
ext2_xattr_security_set(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
return ext2_xattr_set(inode, EXT2_XATTR_INDEX_SECURITY, name,
|
||||
return ext2_xattr_set(dentry->d_inode, EXT2_XATTR_INDEX_SECURITY, name,
|
||||
value, size, flags);
|
||||
}
|
||||
|
||||
|
@ -13,8 +13,8 @@
|
||||
#include "xattr.h"
|
||||
|
||||
static size_t
|
||||
ext2_xattr_trusted_list(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
ext2_xattr_trusted_list(struct dentry *dentry, char *list, size_t list_size,
|
||||
const char *name, size_t name_len, int type)
|
||||
{
|
||||
const int prefix_len = XATTR_TRUSTED_PREFIX_LEN;
|
||||
const size_t total_len = prefix_len + name_len + 1;
|
||||
@ -31,22 +31,22 @@ ext2_xattr_trusted_list(struct inode *inode, char *list, size_t list_size,
|
||||
}
|
||||
|
||||
static int
|
||||
ext2_xattr_trusted_get(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
ext2_xattr_trusted_get(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
return ext2_xattr_get(inode, EXT2_XATTR_INDEX_TRUSTED, name,
|
||||
return ext2_xattr_get(dentry->d_inode, EXT2_XATTR_INDEX_TRUSTED, name,
|
||||
buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
ext2_xattr_trusted_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
ext2_xattr_trusted_set(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
return ext2_xattr_set(inode, EXT2_XATTR_INDEX_TRUSTED, name,
|
||||
return ext2_xattr_set(dentry->d_inode, EXT2_XATTR_INDEX_TRUSTED, name,
|
||||
value, size, flags);
|
||||
}
|
||||
|
||||
|
@ -12,13 +12,13 @@
|
||||
#include "xattr.h"
|
||||
|
||||
static size_t
|
||||
ext2_xattr_user_list(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
ext2_xattr_user_list(struct dentry *dentry, char *list, size_t list_size,
|
||||
const char *name, size_t name_len, int type)
|
||||
{
|
||||
const size_t prefix_len = XATTR_USER_PREFIX_LEN;
|
||||
const size_t total_len = prefix_len + name_len + 1;
|
||||
|
||||
if (!test_opt(inode->i_sb, XATTR_USER))
|
||||
if (!test_opt(dentry->d_sb, XATTR_USER))
|
||||
return 0;
|
||||
|
||||
if (list && total_len <= list_size) {
|
||||
@ -30,27 +30,28 @@ ext2_xattr_user_list(struct inode *inode, char *list, size_t list_size,
|
||||
}
|
||||
|
||||
static int
|
||||
ext2_xattr_user_get(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
ext2_xattr_user_get(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
if (!test_opt(inode->i_sb, XATTR_USER))
|
||||
if (!test_opt(dentry->d_sb, XATTR_USER))
|
||||
return -EOPNOTSUPP;
|
||||
return ext2_xattr_get(inode, EXT2_XATTR_INDEX_USER, name, buffer, size);
|
||||
return ext2_xattr_get(dentry->d_inode, EXT2_XATTR_INDEX_USER,
|
||||
name, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
ext2_xattr_user_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
ext2_xattr_user_set(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
if (!test_opt(inode->i_sb, XATTR_USER))
|
||||
if (!test_opt(dentry->d_sb, XATTR_USER))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return ext2_xattr_set(inode, EXT2_XATTR_INDEX_USER, name,
|
||||
value, size, flags);
|
||||
return ext2_xattr_set(dentry->d_inode, EXT2_XATTR_INDEX_USER,
|
||||
name, value, size, flags);
|
||||
}
|
||||
|
||||
struct xattr_handler ext2_xattr_user_handler = {
|
||||
|
@ -366,12 +366,12 @@ out:
|
||||
* Extended attribute handlers
|
||||
*/
|
||||
static size_t
|
||||
ext3_xattr_list_acl_access(struct inode *inode, char *list, size_t list_len,
|
||||
const char *name, size_t name_len)
|
||||
ext3_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_len,
|
||||
const char *name, size_t name_len, int type)
|
||||
{
|
||||
const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
|
||||
|
||||
if (!test_opt(inode->i_sb, POSIX_ACL))
|
||||
if (!test_opt(dentry->d_sb, POSIX_ACL))
|
||||
return 0;
|
||||
if (list && size <= list_len)
|
||||
memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
|
||||
@ -379,12 +379,12 @@ ext3_xattr_list_acl_access(struct inode *inode, char *list, size_t list_len,
|
||||
}
|
||||
|
||||
static size_t
|
||||
ext3_xattr_list_acl_default(struct inode *inode, char *list, size_t list_len,
|
||||
const char *name, size_t name_len)
|
||||
ext3_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_len,
|
||||
const char *name, size_t name_len, int type)
|
||||
{
|
||||
const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
|
||||
|
||||
if (!test_opt(inode->i_sb, POSIX_ACL))
|
||||
if (!test_opt(dentry->d_sb, POSIX_ACL))
|
||||
return 0;
|
||||
if (list && size <= list_len)
|
||||
memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
|
||||
@ -392,15 +392,18 @@ ext3_xattr_list_acl_default(struct inode *inode, char *list, size_t list_len,
|
||||
}
|
||||
|
||||
static int
|
||||
ext3_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
|
||||
ext3_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer,
|
||||
size_t size, int type)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int error;
|
||||
|
||||
if (!test_opt(inode->i_sb, POSIX_ACL))
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
if (!test_opt(dentry->d_sb, POSIX_ACL))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
acl = ext3_get_acl(inode, type);
|
||||
acl = ext3_get_acl(dentry->d_inode, type);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
if (acl == NULL)
|
||||
@ -412,31 +415,16 @@ ext3_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
|
||||
}
|
||||
|
||||
static int
|
||||
ext3_xattr_get_acl_access(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return ext3_xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
ext3_xattr_get_acl_default(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return ext3_xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
ext3_xattr_set_acl(struct inode *inode, int type, const void *value,
|
||||
size_t size)
|
||||
ext3_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
|
||||
size_t size, int flags, int type)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
handle_t *handle;
|
||||
struct posix_acl *acl;
|
||||
int error, retries = 0;
|
||||
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
if (!test_opt(inode->i_sb, POSIX_ACL))
|
||||
return -EOPNOTSUPP;
|
||||
if (!is_owner_or_cap(inode))
|
||||
@ -468,34 +456,18 @@ release_and_out:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
ext3_xattr_set_acl_access(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return ext3_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
|
||||
}
|
||||
|
||||
static int
|
||||
ext3_xattr_set_acl_default(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return ext3_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
|
||||
}
|
||||
|
||||
struct xattr_handler ext3_xattr_acl_access_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_ACCESS,
|
||||
.flags = ACL_TYPE_ACCESS,
|
||||
.list = ext3_xattr_list_acl_access,
|
||||
.get = ext3_xattr_get_acl_access,
|
||||
.set = ext3_xattr_set_acl_access,
|
||||
.get = ext3_xattr_get_acl,
|
||||
.set = ext3_xattr_set_acl,
|
||||
};
|
||||
|
||||
struct xattr_handler ext3_xattr_acl_default_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_DEFAULT,
|
||||
.flags = ACL_TYPE_DEFAULT,
|
||||
.list = ext3_xattr_list_acl_default,
|
||||
.get = ext3_xattr_get_acl_default,
|
||||
.set = ext3_xattr_set_acl_default,
|
||||
.get = ext3_xattr_get_acl,
|
||||
.set = ext3_xattr_set_acl,
|
||||
};
|
||||
|
@ -99,7 +99,7 @@ static struct buffer_head *ext3_xattr_cache_find(struct inode *,
|
||||
struct mb_cache_entry **);
|
||||
static void ext3_xattr_rehash(struct ext3_xattr_header *,
|
||||
struct ext3_xattr_entry *);
|
||||
static int ext3_xattr_list(struct inode *inode, char *buffer,
|
||||
static int ext3_xattr_list(struct dentry *dentry, char *buffer,
|
||||
size_t buffer_size);
|
||||
|
||||
static struct mb_cache *ext3_xattr_cache;
|
||||
@ -147,7 +147,7 @@ ext3_xattr_handler(int name_index)
|
||||
ssize_t
|
||||
ext3_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
||||
{
|
||||
return ext3_xattr_list(dentry->d_inode, buffer, size);
|
||||
return ext3_xattr_list(dentry, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -332,7 +332,7 @@ ext3_xattr_get(struct inode *inode, int name_index, const char *name,
|
||||
}
|
||||
|
||||
static int
|
||||
ext3_xattr_list_entries(struct inode *inode, struct ext3_xattr_entry *entry,
|
||||
ext3_xattr_list_entries(struct dentry *dentry, struct ext3_xattr_entry *entry,
|
||||
char *buffer, size_t buffer_size)
|
||||
{
|
||||
size_t rest = buffer_size;
|
||||
@ -342,9 +342,10 @@ ext3_xattr_list_entries(struct inode *inode, struct ext3_xattr_entry *entry,
|
||||
ext3_xattr_handler(entry->e_name_index);
|
||||
|
||||
if (handler) {
|
||||
size_t size = handler->list(inode, buffer, rest,
|
||||
size_t size = handler->list(dentry, buffer, rest,
|
||||
entry->e_name,
|
||||
entry->e_name_len);
|
||||
entry->e_name_len,
|
||||
handler->flags);
|
||||
if (buffer) {
|
||||
if (size > rest)
|
||||
return -ERANGE;
|
||||
@ -357,8 +358,9 @@ ext3_xattr_list_entries(struct inode *inode, struct ext3_xattr_entry *entry,
|
||||
}
|
||||
|
||||
static int
|
||||
ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
|
||||
ext3_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct buffer_head *bh = NULL;
|
||||
int error;
|
||||
|
||||
@ -383,7 +385,7 @@ ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
|
||||
goto cleanup;
|
||||
}
|
||||
ext3_xattr_cache_insert(bh);
|
||||
error = ext3_xattr_list_entries(inode, BFIRST(bh), buffer, buffer_size);
|
||||
error = ext3_xattr_list_entries(dentry, BFIRST(bh), buffer, buffer_size);
|
||||
|
||||
cleanup:
|
||||
brelse(bh);
|
||||
@ -392,8 +394,9 @@ cleanup:
|
||||
}
|
||||
|
||||
static int
|
||||
ext3_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size)
|
||||
ext3_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct ext3_xattr_ibody_header *header;
|
||||
struct ext3_inode *raw_inode;
|
||||
struct ext3_iloc iloc;
|
||||
@ -411,7 +414,7 @@ ext3_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size)
|
||||
error = ext3_xattr_check_names(IFIRST(header), end);
|
||||
if (error)
|
||||
goto cleanup;
|
||||
error = ext3_xattr_list_entries(inode, IFIRST(header),
|
||||
error = ext3_xattr_list_entries(dentry, IFIRST(header),
|
||||
buffer, buffer_size);
|
||||
|
||||
cleanup:
|
||||
@ -430,12 +433,12 @@ cleanup:
|
||||
* used / required on success.
|
||||
*/
|
||||
static int
|
||||
ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
|
||||
ext3_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
|
||||
{
|
||||
int i_error, b_error;
|
||||
|
||||
down_read(&EXT3_I(inode)->xattr_sem);
|
||||
i_error = ext3_xattr_ibody_list(inode, buffer, buffer_size);
|
||||
down_read(&EXT3_I(dentry->d_inode)->xattr_sem);
|
||||
i_error = ext3_xattr_ibody_list(dentry, buffer, buffer_size);
|
||||
if (i_error < 0) {
|
||||
b_error = 0;
|
||||
} else {
|
||||
@ -443,11 +446,11 @@ ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
|
||||
buffer += i_error;
|
||||
buffer_size -= i_error;
|
||||
}
|
||||
b_error = ext3_xattr_block_list(inode, buffer, buffer_size);
|
||||
b_error = ext3_xattr_block_list(dentry, buffer, buffer_size);
|
||||
if (b_error < 0)
|
||||
i_error = 0;
|
||||
}
|
||||
up_read(&EXT3_I(inode)->xattr_sem);
|
||||
up_read(&EXT3_I(dentry->d_inode)->xattr_sem);
|
||||
return i_error + b_error;
|
||||
}
|
||||
|
||||
|
@ -12,8 +12,8 @@
|
||||
#include "xattr.h"
|
||||
|
||||
static size_t
|
||||
ext3_xattr_security_list(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
ext3_xattr_security_list(struct dentry *dentry, char *list, size_t list_size,
|
||||
const char *name, size_t name_len, int type)
|
||||
{
|
||||
const size_t prefix_len = XATTR_SECURITY_PREFIX_LEN;
|
||||
const size_t total_len = prefix_len + name_len + 1;
|
||||
@ -28,23 +28,23 @@ ext3_xattr_security_list(struct inode *inode, char *list, size_t list_size,
|
||||
}
|
||||
|
||||
static int
|
||||
ext3_xattr_security_get(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
ext3_xattr_security_get(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
return ext3_xattr_get(inode, EXT3_XATTR_INDEX_SECURITY, name,
|
||||
buffer, size);
|
||||
return ext3_xattr_get(dentry->d_inode, EXT3_XATTR_INDEX_SECURITY,
|
||||
name, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
ext3_xattr_security_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
ext3_xattr_security_set(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
return ext3_xattr_set(inode, EXT3_XATTR_INDEX_SECURITY, name,
|
||||
value, size, flags);
|
||||
return ext3_xattr_set(dentry->d_inode, EXT3_XATTR_INDEX_SECURITY,
|
||||
name, value, size, flags);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -14,8 +14,8 @@
|
||||
#include "xattr.h"
|
||||
|
||||
static size_t
|
||||
ext3_xattr_trusted_list(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
ext3_xattr_trusted_list(struct dentry *dentry, char *list, size_t list_size,
|
||||
const char *name, size_t name_len, int type)
|
||||
{
|
||||
const size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN;
|
||||
const size_t total_len = prefix_len + name_len + 1;
|
||||
@ -32,22 +32,22 @@ ext3_xattr_trusted_list(struct inode *inode, char *list, size_t list_size,
|
||||
}
|
||||
|
||||
static int
|
||||
ext3_xattr_trusted_get(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
ext3_xattr_trusted_get(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
return ext3_xattr_get(inode, EXT3_XATTR_INDEX_TRUSTED, name,
|
||||
buffer, size);
|
||||
return ext3_xattr_get(dentry->d_inode, EXT3_XATTR_INDEX_TRUSTED,
|
||||
name, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
ext3_xattr_trusted_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
ext3_xattr_trusted_set(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
return ext3_xattr_set(inode, EXT3_XATTR_INDEX_TRUSTED, name,
|
||||
return ext3_xattr_set(dentry->d_inode, EXT3_XATTR_INDEX_TRUSTED, name,
|
||||
value, size, flags);
|
||||
}
|
||||
|
||||
|
@ -13,13 +13,13 @@
|
||||
#include "xattr.h"
|
||||
|
||||
static size_t
|
||||
ext3_xattr_user_list(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
ext3_xattr_user_list(struct dentry *dentry, char *list, size_t list_size,
|
||||
const char *name, size_t name_len, int type)
|
||||
{
|
||||
const size_t prefix_len = XATTR_USER_PREFIX_LEN;
|
||||
const size_t total_len = prefix_len + name_len + 1;
|
||||
|
||||
if (!test_opt(inode->i_sb, XATTR_USER))
|
||||
if (!test_opt(dentry->d_sb, XATTR_USER))
|
||||
return 0;
|
||||
|
||||
if (list && total_len <= list_size) {
|
||||
@ -31,26 +31,27 @@ ext3_xattr_user_list(struct inode *inode, char *list, size_t list_size,
|
||||
}
|
||||
|
||||
static int
|
||||
ext3_xattr_user_get(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
ext3_xattr_user_get(struct dentry *dentry, const char *name, void *buffer,
|
||||
size_t size, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
if (!test_opt(inode->i_sb, XATTR_USER))
|
||||
if (!test_opt(dentry->d_sb, XATTR_USER))
|
||||
return -EOPNOTSUPP;
|
||||
return ext3_xattr_get(inode, EXT3_XATTR_INDEX_USER, name, buffer, size);
|
||||
return ext3_xattr_get(dentry->d_inode, EXT3_XATTR_INDEX_USER,
|
||||
name, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
ext3_xattr_user_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
ext3_xattr_user_set(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
if (!test_opt(inode->i_sb, XATTR_USER))
|
||||
if (!test_opt(dentry->d_sb, XATTR_USER))
|
||||
return -EOPNOTSUPP;
|
||||
return ext3_xattr_set(inode, EXT3_XATTR_INDEX_USER, name,
|
||||
value, size, flags);
|
||||
return ext3_xattr_set(dentry->d_inode, EXT3_XATTR_INDEX_USER,
|
||||
name, value, size, flags);
|
||||
}
|
||||
|
||||
struct xattr_handler ext3_xattr_user_handler = {
|
||||
|
@ -364,12 +364,12 @@ out:
|
||||
* Extended attribute handlers
|
||||
*/
|
||||
static size_t
|
||||
ext4_xattr_list_acl_access(struct inode *inode, char *list, size_t list_len,
|
||||
const char *name, size_t name_len)
|
||||
ext4_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_len,
|
||||
const char *name, size_t name_len, int type)
|
||||
{
|
||||
const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
|
||||
|
||||
if (!test_opt(inode->i_sb, POSIX_ACL))
|
||||
if (!test_opt(dentry->d_sb, POSIX_ACL))
|
||||
return 0;
|
||||
if (list && size <= list_len)
|
||||
memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
|
||||
@ -377,12 +377,12 @@ ext4_xattr_list_acl_access(struct inode *inode, char *list, size_t list_len,
|
||||
}
|
||||
|
||||
static size_t
|
||||
ext4_xattr_list_acl_default(struct inode *inode, char *list, size_t list_len,
|
||||
const char *name, size_t name_len)
|
||||
ext4_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_len,
|
||||
const char *name, size_t name_len, int type)
|
||||
{
|
||||
const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
|
||||
|
||||
if (!test_opt(inode->i_sb, POSIX_ACL))
|
||||
if (!test_opt(dentry->d_sb, POSIX_ACL))
|
||||
return 0;
|
||||
if (list && size <= list_len)
|
||||
memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
|
||||
@ -390,15 +390,18 @@ ext4_xattr_list_acl_default(struct inode *inode, char *list, size_t list_len,
|
||||
}
|
||||
|
||||
static int
|
||||
ext4_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
|
||||
ext4_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer,
|
||||
size_t size, int type)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int error;
|
||||
|
||||
if (!test_opt(inode->i_sb, POSIX_ACL))
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
if (!test_opt(dentry->d_sb, POSIX_ACL))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
acl = ext4_get_acl(inode, type);
|
||||
acl = ext4_get_acl(dentry->d_inode, type);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
if (acl == NULL)
|
||||
@ -410,31 +413,16 @@ ext4_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
|
||||
}
|
||||
|
||||
static int
|
||||
ext4_xattr_get_acl_access(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return ext4_xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
ext4_xattr_get_acl_default(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return ext4_xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
ext4_xattr_set_acl(struct inode *inode, int type, const void *value,
|
||||
size_t size)
|
||||
ext4_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
|
||||
size_t size, int flags, int type)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
handle_t *handle;
|
||||
struct posix_acl *acl;
|
||||
int error, retries = 0;
|
||||
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
if (!test_opt(inode->i_sb, POSIX_ACL))
|
||||
return -EOPNOTSUPP;
|
||||
if (!is_owner_or_cap(inode))
|
||||
@ -466,34 +454,18 @@ release_and_out:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
ext4_xattr_set_acl_access(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return ext4_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
|
||||
}
|
||||
|
||||
static int
|
||||
ext4_xattr_set_acl_default(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return ext4_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
|
||||
}
|
||||
|
||||
struct xattr_handler ext4_xattr_acl_access_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_ACCESS,
|
||||
.flags = ACL_TYPE_ACCESS,
|
||||
.list = ext4_xattr_list_acl_access,
|
||||
.get = ext4_xattr_get_acl_access,
|
||||
.set = ext4_xattr_set_acl_access,
|
||||
.get = ext4_xattr_get_acl,
|
||||
.set = ext4_xattr_set_acl,
|
||||
};
|
||||
|
||||
struct xattr_handler ext4_xattr_acl_default_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_DEFAULT,
|
||||
.flags = ACL_TYPE_DEFAULT,
|
||||
.list = ext4_xattr_list_acl_default,
|
||||
.get = ext4_xattr_get_acl_default,
|
||||
.set = ext4_xattr_set_acl_default,
|
||||
.get = ext4_xattr_get_acl,
|
||||
.set = ext4_xattr_set_acl,
|
||||
};
|
||||
|
@ -92,7 +92,7 @@ static struct buffer_head *ext4_xattr_cache_find(struct inode *,
|
||||
struct mb_cache_entry **);
|
||||
static void ext4_xattr_rehash(struct ext4_xattr_header *,
|
||||
struct ext4_xattr_entry *);
|
||||
static int ext4_xattr_list(struct inode *inode, char *buffer,
|
||||
static int ext4_xattr_list(struct dentry *dentry, char *buffer,
|
||||
size_t buffer_size);
|
||||
|
||||
static struct mb_cache *ext4_xattr_cache;
|
||||
@ -140,7 +140,7 @@ ext4_xattr_handler(int name_index)
|
||||
ssize_t
|
||||
ext4_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
||||
{
|
||||
return ext4_xattr_list(dentry->d_inode, buffer, size);
|
||||
return ext4_xattr_list(dentry, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -325,7 +325,7 @@ ext4_xattr_get(struct inode *inode, int name_index, const char *name,
|
||||
}
|
||||
|
||||
static int
|
||||
ext4_xattr_list_entries(struct inode *inode, struct ext4_xattr_entry *entry,
|
||||
ext4_xattr_list_entries(struct dentry *dentry, struct ext4_xattr_entry *entry,
|
||||
char *buffer, size_t buffer_size)
|
||||
{
|
||||
size_t rest = buffer_size;
|
||||
@ -335,9 +335,10 @@ ext4_xattr_list_entries(struct inode *inode, struct ext4_xattr_entry *entry,
|
||||
ext4_xattr_handler(entry->e_name_index);
|
||||
|
||||
if (handler) {
|
||||
size_t size = handler->list(inode, buffer, rest,
|
||||
size_t size = handler->list(dentry, buffer, rest,
|
||||
entry->e_name,
|
||||
entry->e_name_len);
|
||||
entry->e_name_len,
|
||||
handler->flags);
|
||||
if (buffer) {
|
||||
if (size > rest)
|
||||
return -ERANGE;
|
||||
@ -350,8 +351,9 @@ ext4_xattr_list_entries(struct inode *inode, struct ext4_xattr_entry *entry,
|
||||
}
|
||||
|
||||
static int
|
||||
ext4_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
|
||||
ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct buffer_head *bh = NULL;
|
||||
int error;
|
||||
|
||||
@ -376,7 +378,7 @@ ext4_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
|
||||
goto cleanup;
|
||||
}
|
||||
ext4_xattr_cache_insert(bh);
|
||||
error = ext4_xattr_list_entries(inode, BFIRST(bh), buffer, buffer_size);
|
||||
error = ext4_xattr_list_entries(dentry, BFIRST(bh), buffer, buffer_size);
|
||||
|
||||
cleanup:
|
||||
brelse(bh);
|
||||
@ -385,8 +387,9 @@ cleanup:
|
||||
}
|
||||
|
||||
static int
|
||||
ext4_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size)
|
||||
ext4_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct ext4_xattr_ibody_header *header;
|
||||
struct ext4_inode *raw_inode;
|
||||
struct ext4_iloc iloc;
|
||||
@ -404,7 +407,7 @@ ext4_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size)
|
||||
error = ext4_xattr_check_names(IFIRST(header), end);
|
||||
if (error)
|
||||
goto cleanup;
|
||||
error = ext4_xattr_list_entries(inode, IFIRST(header),
|
||||
error = ext4_xattr_list_entries(dentry, IFIRST(header),
|
||||
buffer, buffer_size);
|
||||
|
||||
cleanup:
|
||||
@ -423,12 +426,12 @@ cleanup:
|
||||
* used / required on success.
|
||||
*/
|
||||
static int
|
||||
ext4_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
|
||||
ext4_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
|
||||
{
|
||||
int i_error, b_error;
|
||||
|
||||
down_read(&EXT4_I(inode)->xattr_sem);
|
||||
i_error = ext4_xattr_ibody_list(inode, buffer, buffer_size);
|
||||
down_read(&EXT4_I(dentry->d_inode)->xattr_sem);
|
||||
i_error = ext4_xattr_ibody_list(dentry, buffer, buffer_size);
|
||||
if (i_error < 0) {
|
||||
b_error = 0;
|
||||
} else {
|
||||
@ -436,11 +439,11 @@ ext4_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
|
||||
buffer += i_error;
|
||||
buffer_size -= i_error;
|
||||
}
|
||||
b_error = ext4_xattr_block_list(inode, buffer, buffer_size);
|
||||
b_error = ext4_xattr_block_list(dentry, buffer, buffer_size);
|
||||
if (b_error < 0)
|
||||
i_error = 0;
|
||||
}
|
||||
up_read(&EXT4_I(inode)->xattr_sem);
|
||||
up_read(&EXT4_I(dentry->d_inode)->xattr_sem);
|
||||
return i_error + b_error;
|
||||
}
|
||||
|
||||
|
@ -12,8 +12,8 @@
|
||||
#include "xattr.h"
|
||||
|
||||
static size_t
|
||||
ext4_xattr_security_list(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
ext4_xattr_security_list(struct dentry *dentry, char *list, size_t list_size,
|
||||
const char *name, size_t name_len, int type)
|
||||
{
|
||||
const size_t prefix_len = sizeof(XATTR_SECURITY_PREFIX)-1;
|
||||
const size_t total_len = prefix_len + name_len + 1;
|
||||
@ -28,23 +28,23 @@ ext4_xattr_security_list(struct inode *inode, char *list, size_t list_size,
|
||||
}
|
||||
|
||||
static int
|
||||
ext4_xattr_security_get(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
ext4_xattr_security_get(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
return ext4_xattr_get(inode, EXT4_XATTR_INDEX_SECURITY, name,
|
||||
buffer, size);
|
||||
return ext4_xattr_get(dentry->d_inode, EXT4_XATTR_INDEX_SECURITY,
|
||||
name, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
ext4_xattr_security_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
ext4_xattr_security_set(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
return ext4_xattr_set(inode, EXT4_XATTR_INDEX_SECURITY, name,
|
||||
value, size, flags);
|
||||
return ext4_xattr_set(dentry->d_inode, EXT4_XATTR_INDEX_SECURITY,
|
||||
name, value, size, flags);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -14,8 +14,8 @@
|
||||
#include "xattr.h"
|
||||
|
||||
static size_t
|
||||
ext4_xattr_trusted_list(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
ext4_xattr_trusted_list(struct dentry *dentry, char *list, size_t list_size,
|
||||
const char *name, size_t name_len, int type)
|
||||
{
|
||||
const size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN;
|
||||
const size_t total_len = prefix_len + name_len + 1;
|
||||
@ -32,23 +32,23 @@ ext4_xattr_trusted_list(struct inode *inode, char *list, size_t list_size,
|
||||
}
|
||||
|
||||
static int
|
||||
ext4_xattr_trusted_get(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
ext4_xattr_trusted_get(struct dentry *dentry, const char *name, void *buffer,
|
||||
size_t size, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
return ext4_xattr_get(inode, EXT4_XATTR_INDEX_TRUSTED, name,
|
||||
buffer, size);
|
||||
return ext4_xattr_get(dentry->d_inode, EXT4_XATTR_INDEX_TRUSTED,
|
||||
name, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
ext4_xattr_trusted_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
ext4_xattr_trusted_set(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
return ext4_xattr_set(inode, EXT4_XATTR_INDEX_TRUSTED, name,
|
||||
value, size, flags);
|
||||
return ext4_xattr_set(dentry->d_inode, EXT4_XATTR_INDEX_TRUSTED,
|
||||
name, value, size, flags);
|
||||
}
|
||||
|
||||
struct xattr_handler ext4_xattr_trusted_handler = {
|
||||
|
@ -13,13 +13,13 @@
|
||||
#include "xattr.h"
|
||||
|
||||
static size_t
|
||||
ext4_xattr_user_list(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
ext4_xattr_user_list(struct dentry *dentry, char *list, size_t list_size,
|
||||
const char *name, size_t name_len, int type)
|
||||
{
|
||||
const size_t prefix_len = XATTR_USER_PREFIX_LEN;
|
||||
const size_t total_len = prefix_len + name_len + 1;
|
||||
|
||||
if (!test_opt(inode->i_sb, XATTR_USER))
|
||||
if (!test_opt(dentry->d_sb, XATTR_USER))
|
||||
return 0;
|
||||
|
||||
if (list && total_len <= list_size) {
|
||||
@ -31,26 +31,27 @@ ext4_xattr_user_list(struct inode *inode, char *list, size_t list_size,
|
||||
}
|
||||
|
||||
static int
|
||||
ext4_xattr_user_get(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
ext4_xattr_user_get(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
if (!test_opt(inode->i_sb, XATTR_USER))
|
||||
if (!test_opt(dentry->d_sb, XATTR_USER))
|
||||
return -EOPNOTSUPP;
|
||||
return ext4_xattr_get(inode, EXT4_XATTR_INDEX_USER, name, buffer, size);
|
||||
return ext4_xattr_get(dentry->d_inode, EXT4_XATTR_INDEX_USER,
|
||||
name, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
ext4_xattr_user_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
ext4_xattr_user_set(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
if (!test_opt(inode->i_sb, XATTR_USER))
|
||||
if (!test_opt(dentry->d_sb, XATTR_USER))
|
||||
return -EOPNOTSUPP;
|
||||
return ext4_xattr_set(inode, EXT4_XATTR_INDEX_USER, name,
|
||||
value, size, flags);
|
||||
return ext4_xattr_set(dentry->d_inode, EXT4_XATTR_INDEX_USER,
|
||||
name, value, size, flags);
|
||||
}
|
||||
|
||||
struct xattr_handler ext4_xattr_user_handler = {
|
||||
|
@ -21,9 +21,12 @@
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/percpu_counter.h>
|
||||
#include <linux/ima.h>
|
||||
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
/* sysctl tunables... */
|
||||
struct files_stat_struct files_stat = {
|
||||
.max_files = NR_FILE
|
||||
@ -147,8 +150,6 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(get_empty_filp);
|
||||
|
||||
/**
|
||||
* alloc_file - allocate and initialize a 'struct file'
|
||||
* @mnt: the vfsmount on which the file will reside
|
||||
@ -164,8 +165,8 @@ EXPORT_SYMBOL(get_empty_filp);
|
||||
* If all the callers of init_file() are eliminated, its
|
||||
* code should be moved into this function.
|
||||
*/
|
||||
struct file *alloc_file(struct vfsmount *mnt, struct dentry *dentry,
|
||||
fmode_t mode, const struct file_operations *fop)
|
||||
struct file *alloc_file(struct path *path, fmode_t mode,
|
||||
const struct file_operations *fop)
|
||||
{
|
||||
struct file *file;
|
||||
|
||||
@ -173,35 +174,8 @@ struct file *alloc_file(struct vfsmount *mnt, struct dentry *dentry,
|
||||
if (!file)
|
||||
return NULL;
|
||||
|
||||
init_file(file, mnt, dentry, mode, fop);
|
||||
return file;
|
||||
}
|
||||
EXPORT_SYMBOL(alloc_file);
|
||||
|
||||
/**
|
||||
* init_file - initialize a 'struct file'
|
||||
* @file: the already allocated 'struct file' to initialized
|
||||
* @mnt: the vfsmount on which the file resides
|
||||
* @dentry: the dentry representing this file
|
||||
* @mode: the mode the file is opened with
|
||||
* @fop: the 'struct file_operations' for this file
|
||||
*
|
||||
* Use this instead of setting the members directly. Doing so
|
||||
* avoids making mistakes like forgetting the mntget() or
|
||||
* forgetting to take a write on the mnt.
|
||||
*
|
||||
* Note: This is a crappy interface. It is here to make
|
||||
* merging with the existing users of get_empty_filp()
|
||||
* who have complex failure logic easier. All users
|
||||
* of this should be moving to alloc_file().
|
||||
*/
|
||||
int init_file(struct file *file, struct vfsmount *mnt, struct dentry *dentry,
|
||||
fmode_t mode, const struct file_operations *fop)
|
||||
{
|
||||
int error = 0;
|
||||
file->f_path.dentry = dentry;
|
||||
file->f_path.mnt = mntget(mnt);
|
||||
file->f_mapping = dentry->d_inode->i_mapping;
|
||||
file->f_path = *path;
|
||||
file->f_mapping = path->dentry->d_inode->i_mapping;
|
||||
file->f_mode = mode;
|
||||
file->f_op = fop;
|
||||
|
||||
@ -211,14 +185,15 @@ int init_file(struct file *file, struct vfsmount *mnt, struct dentry *dentry,
|
||||
* visible. We do this for consistency, and so
|
||||
* that we can do debugging checks at __fput()
|
||||
*/
|
||||
if ((mode & FMODE_WRITE) && !special_file(dentry->d_inode->i_mode)) {
|
||||
if ((mode & FMODE_WRITE) && !special_file(path->dentry->d_inode->i_mode)) {
|
||||
int error = 0;
|
||||
file_take_write(file);
|
||||
error = mnt_clone_write(mnt);
|
||||
error = mnt_clone_write(path->mnt);
|
||||
WARN_ON(error);
|
||||
}
|
||||
return error;
|
||||
ima_counts_get(file);
|
||||
return file;
|
||||
}
|
||||
EXPORT_SYMBOL(init_file);
|
||||
|
||||
void fput(struct file *file)
|
||||
{
|
||||
|
158
fs/generic_acl.c
158
fs/generic_acl.c
@ -1,62 +1,58 @@
|
||||
/*
|
||||
* fs/generic_acl.c
|
||||
*
|
||||
* (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/fs.h>
|
||||
#include <linux/generic_acl.h>
|
||||
#include <linux/posix_acl.h>
|
||||
#include <linux/posix_acl_xattr.h>
|
||||
|
||||
/**
|
||||
* generic_acl_list - Generic xattr_handler->list() operation
|
||||
* @ops: Filesystem specific getacl and setacl callbacks
|
||||
*/
|
||||
size_t
|
||||
generic_acl_list(struct inode *inode, struct generic_acl_operations *ops,
|
||||
int type, char *list, size_t list_size)
|
||||
|
||||
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 *name;
|
||||
const char *xname;
|
||||
size_t size;
|
||||
|
||||
acl = ops->getacl(inode, type);
|
||||
acl = get_cached_acl(dentry->d_inode, type);
|
||||
if (!acl)
|
||||
return 0;
|
||||
posix_acl_release(acl);
|
||||
|
||||
switch(type) {
|
||||
case ACL_TYPE_ACCESS:
|
||||
name = POSIX_ACL_XATTR_ACCESS;
|
||||
break;
|
||||
|
||||
case ACL_TYPE_DEFAULT:
|
||||
name = POSIX_ACL_XATTR_DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
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(name) + 1;
|
||||
size = strlen(xname) + 1;
|
||||
if (list && size <= list_size)
|
||||
memcpy(list, name, size);
|
||||
memcpy(list, xname, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* generic_acl_get - Generic xattr_handler->get() operation
|
||||
* @ops: Filesystem specific getacl and setacl callbacks
|
||||
*/
|
||||
int
|
||||
generic_acl_get(struct inode *inode, struct generic_acl_operations *ops,
|
||||
int type, void *buffer, size_t 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;
|
||||
|
||||
acl = ops->getacl(inode, type);
|
||||
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);
|
||||
@ -65,17 +61,16 @@ generic_acl_get(struct inode *inode, struct generic_acl_operations *ops,
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* generic_acl_set - Generic xattr_handler->set() operation
|
||||
* @ops: Filesystem specific getacl and setacl callbacks
|
||||
*/
|
||||
int
|
||||
generic_acl_set(struct inode *inode, struct generic_acl_operations *ops,
|
||||
int type, const void *value, size_t size)
|
||||
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 (!is_owner_or_cap(inode))
|
||||
@ -91,28 +86,27 @@ generic_acl_set(struct inode *inode, struct generic_acl_operations *ops,
|
||||
error = posix_acl_valid(acl);
|
||||
if (error)
|
||||
goto failed;
|
||||
switch(type) {
|
||||
case ACL_TYPE_ACCESS:
|
||||
mode = inode->i_mode;
|
||||
error = posix_acl_equiv_mode(acl, &mode);
|
||||
if (error < 0)
|
||||
goto failed;
|
||||
inode->i_mode = mode;
|
||||
if (error == 0) {
|
||||
posix_acl_release(acl);
|
||||
acl = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACL_TYPE_DEFAULT:
|
||||
if (!S_ISDIR(inode->i_mode)) {
|
||||
error = -EINVAL;
|
||||
goto failed;
|
||||
}
|
||||
break;
|
||||
switch (type) {
|
||||
case ACL_TYPE_ACCESS:
|
||||
mode = inode->i_mode;
|
||||
error = posix_acl_equiv_mode(acl, &mode);
|
||||
if (error < 0)
|
||||
goto failed;
|
||||
inode->i_mode = mode;
|
||||
if (error == 0) {
|
||||
posix_acl_release(acl);
|
||||
acl = NULL;
|
||||
}
|
||||
break;
|
||||
case ACL_TYPE_DEFAULT:
|
||||
if (!S_ISDIR(inode->i_mode)) {
|
||||
error = -EINVAL;
|
||||
goto failed;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ops->setacl(inode, type, acl);
|
||||
set_cached_acl(inode, type, acl);
|
||||
error = 0;
|
||||
failed:
|
||||
posix_acl_release(acl);
|
||||
@ -121,14 +115,12 @@ failed:
|
||||
|
||||
/**
|
||||
* generic_acl_init - Take care of acl inheritance at @inode create time
|
||||
* @ops: Filesystem specific getacl and setacl callbacks
|
||||
*
|
||||
* 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 generic_acl_operations *ops)
|
||||
generic_acl_init(struct inode *inode, struct inode *dir)
|
||||
{
|
||||
struct posix_acl *acl = NULL;
|
||||
mode_t mode = inode->i_mode;
|
||||
@ -136,7 +128,7 @@ generic_acl_init(struct inode *inode, struct inode *dir,
|
||||
|
||||
inode->i_mode = mode & ~current_umask();
|
||||
if (!S_ISLNK(inode->i_mode))
|
||||
acl = ops->getacl(dir, ACL_TYPE_DEFAULT);
|
||||
acl = get_cached_acl(dir, ACL_TYPE_DEFAULT);
|
||||
if (acl) {
|
||||
struct posix_acl *clone;
|
||||
|
||||
@ -145,7 +137,7 @@ generic_acl_init(struct inode *inode, struct inode *dir,
|
||||
error = -ENOMEM;
|
||||
if (!clone)
|
||||
goto cleanup;
|
||||
ops->setacl(inode, ACL_TYPE_DEFAULT, clone);
|
||||
set_cached_acl(inode, ACL_TYPE_DEFAULT, clone);
|
||||
posix_acl_release(clone);
|
||||
}
|
||||
clone = posix_acl_clone(acl, GFP_KERNEL);
|
||||
@ -156,7 +148,7 @@ generic_acl_init(struct inode *inode, struct inode *dir,
|
||||
if (error >= 0) {
|
||||
inode->i_mode = mode;
|
||||
if (error > 0)
|
||||
ops->setacl(inode, ACL_TYPE_ACCESS, clone);
|
||||
set_cached_acl(inode, ACL_TYPE_ACCESS, clone);
|
||||
}
|
||||
posix_acl_release(clone);
|
||||
}
|
||||
@ -169,20 +161,19 @@ cleanup:
|
||||
|
||||
/**
|
||||
* generic_acl_chmod - change the access acl of @inode upon chmod()
|
||||
* @ops: FIlesystem specific getacl and setacl callbacks
|
||||
*
|
||||
* A chmod also changes the permissions of the owner, group/mask, and
|
||||
* other ACL entries.
|
||||
*/
|
||||
int
|
||||
generic_acl_chmod(struct inode *inode, struct generic_acl_operations *ops)
|
||||
generic_acl_chmod(struct inode *inode)
|
||||
{
|
||||
struct posix_acl *acl, *clone;
|
||||
int error = 0;
|
||||
|
||||
if (S_ISLNK(inode->i_mode))
|
||||
return -EOPNOTSUPP;
|
||||
acl = ops->getacl(inode, ACL_TYPE_ACCESS);
|
||||
acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
|
||||
if (acl) {
|
||||
clone = posix_acl_clone(acl, GFP_KERNEL);
|
||||
posix_acl_release(acl);
|
||||
@ -190,8 +181,37 @@ generic_acl_chmod(struct inode *inode, struct generic_acl_operations *ops)
|
||||
return -ENOMEM;
|
||||
error = posix_acl_chmod_masq(clone, inode->i_mode);
|
||||
if (!error)
|
||||
ops->setacl(inode, ACL_TYPE_ACCESS, clone);
|
||||
set_cached_acl(inode, ACL_TYPE_ACCESS, clone);
|
||||
posix_acl_release(clone);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
generic_check_acl(struct inode *inode, int mask)
|
||||
{
|
||||
struct posix_acl *acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
|
||||
|
||||
if (acl) {
|
||||
int error = posix_acl_permission(inode, acl, mask);
|
||||
posix_acl_release(acl);
|
||||
return error;
|
||||
}
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
@ -126,7 +126,7 @@ static int gfs2_acl_set(struct inode *inode, int type, struct posix_acl *acl)
|
||||
error = posix_acl_to_xattr(acl, data, len);
|
||||
if (error < 0)
|
||||
goto out;
|
||||
error = gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, data, len, 0);
|
||||
error = __gfs2_xattr_set(inode, name, data, len, 0, GFS2_EATYPE_SYS);
|
||||
if (!error)
|
||||
set_cached_acl(inode, type, acl);
|
||||
out:
|
||||
@ -232,9 +232,10 @@ static int gfs2_acl_type(const char *name)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int gfs2_xattr_system_get(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
static int gfs2_xattr_system_get(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size, int xtype)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct posix_acl *acl;
|
||||
int type;
|
||||
int error;
|
||||
@ -255,9 +256,11 @@ static int gfs2_xattr_system_get(struct inode *inode, const char *name,
|
||||
return error;
|
||||
}
|
||||
|
||||
static int gfs2_xattr_system_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
static int gfs2_xattr_system_set(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags,
|
||||
int xtype)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
||||
struct posix_acl *acl = NULL;
|
||||
int error = 0, type;
|
||||
@ -319,7 +322,7 @@ static int gfs2_xattr_system_set(struct inode *inode, const char *name,
|
||||
}
|
||||
|
||||
set_acl:
|
||||
error = gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, value, size, 0);
|
||||
error = __gfs2_xattr_set(inode, name, value, size, 0, GFS2_EATYPE_SYS);
|
||||
if (!error) {
|
||||
if (acl)
|
||||
set_cached_acl(inode, type, acl);
|
||||
@ -334,6 +337,7 @@ out:
|
||||
|
||||
struct xattr_handler gfs2_xattr_system_handler = {
|
||||
.prefix = XATTR_SYSTEM_PREFIX,
|
||||
.flags = GFS2_EATYPE_SYS,
|
||||
.get = gfs2_xattr_system_get,
|
||||
.set = gfs2_xattr_system_set,
|
||||
};
|
||||
|
@ -801,7 +801,8 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SECURITY, name, value, len, 0);
|
||||
err = __gfs2_xattr_set(&ip->i_inode, name, value, len, 0,
|
||||
GFS2_EATYPE_SECURITY);
|
||||
kfree(value);
|
||||
kfree(name);
|
||||
|
||||
|
@ -567,18 +567,17 @@ out:
|
||||
/**
|
||||
* gfs2_xattr_get - Get a GFS2 extended attribute
|
||||
* @inode: The inode
|
||||
* @type: The type of extended attribute
|
||||
* @name: The name of the extended attribute
|
||||
* @buffer: The buffer to write the result into
|
||||
* @size: The size of the buffer
|
||||
* @type: The type of extended attribute
|
||||
*
|
||||
* Returns: actual size of data on success, -errno on error
|
||||
*/
|
||||
|
||||
int gfs2_xattr_get(struct inode *inode, int type, const char *name,
|
||||
void *buffer, size_t size)
|
||||
static int gfs2_xattr_get(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size, int type)
|
||||
{
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
|
||||
struct gfs2_ea_location el;
|
||||
int error;
|
||||
|
||||
@ -1119,7 +1118,7 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el)
|
||||
|
||||
/**
|
||||
* gfs2_xattr_remove - Remove a GFS2 extended attribute
|
||||
* @inode: The inode
|
||||
* @ip: The inode
|
||||
* @type: The type of the extended attribute
|
||||
* @name: The name of the extended attribute
|
||||
*
|
||||
@ -1130,9 +1129,8 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el)
|
||||
* Returns: 0, or errno on failure
|
||||
*/
|
||||
|
||||
static int gfs2_xattr_remove(struct inode *inode, int type, const char *name)
|
||||
static int gfs2_xattr_remove(struct gfs2_inode *ip, int type, const char *name)
|
||||
{
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct gfs2_ea_location el;
|
||||
int error;
|
||||
|
||||
@ -1156,24 +1154,24 @@ static int gfs2_xattr_remove(struct inode *inode, int type, const char *name)
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_xattr_set - Set (or remove) a GFS2 extended attribute
|
||||
* @inode: The inode
|
||||
* @type: The type of the extended attribute
|
||||
* __gfs2_xattr_set - Set (or remove) a GFS2 extended attribute
|
||||
* @ip: The inode
|
||||
* @name: The name of the extended attribute
|
||||
* @value: The value of the extended attribute (NULL for remove)
|
||||
* @size: The size of the @value argument
|
||||
* @flags: Create or Replace
|
||||
* @type: The type of the extended attribute
|
||||
*
|
||||
* See gfs2_xattr_remove() for details of the removal of xattrs.
|
||||
*
|
||||
* Returns: 0 or errno on failure
|
||||
*/
|
||||
|
||||
int gfs2_xattr_set(struct inode *inode, int type, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
int __gfs2_xattr_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags, int type)
|
||||
{
|
||||
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
||||
struct gfs2_ea_location el;
|
||||
unsigned int namel = strlen(name);
|
||||
int error;
|
||||
@ -1184,7 +1182,7 @@ int gfs2_xattr_set(struct inode *inode, int type, const char *name,
|
||||
return -ERANGE;
|
||||
|
||||
if (value == NULL)
|
||||
return gfs2_xattr_remove(inode, type, name);
|
||||
return gfs2_xattr_remove(ip, type, name);
|
||||
|
||||
if (ea_check_size(sdp, namel, size))
|
||||
return -ERANGE;
|
||||
@ -1224,6 +1222,13 @@ int gfs2_xattr_set(struct inode *inode, int type, const char *name,
|
||||
return error;
|
||||
}
|
||||
|
||||
static int gfs2_xattr_set(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags, int type)
|
||||
{
|
||||
return __gfs2_xattr_set(dentry->d_inode, name, value,
|
||||
size, flags, type);
|
||||
}
|
||||
|
||||
static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip,
|
||||
struct gfs2_ea_header *ea, char *data)
|
||||
{
|
||||
@ -1529,40 +1534,18 @@ out_alloc:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int gfs2_xattr_user_get(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
return gfs2_xattr_get(inode, GFS2_EATYPE_USR, name, buffer, size);
|
||||
}
|
||||
|
||||
static int gfs2_xattr_user_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
return gfs2_xattr_set(inode, GFS2_EATYPE_USR, name, value, size, flags);
|
||||
}
|
||||
|
||||
static int gfs2_xattr_security_get(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
return gfs2_xattr_get(inode, GFS2_EATYPE_SECURITY, name, buffer, size);
|
||||
}
|
||||
|
||||
static int gfs2_xattr_security_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
return gfs2_xattr_set(inode, GFS2_EATYPE_SECURITY, name, value, size, flags);
|
||||
}
|
||||
|
||||
static struct xattr_handler gfs2_xattr_user_handler = {
|
||||
.prefix = XATTR_USER_PREFIX,
|
||||
.get = gfs2_xattr_user_get,
|
||||
.set = gfs2_xattr_user_set,
|
||||
.flags = GFS2_EATYPE_USR,
|
||||
.get = gfs2_xattr_get,
|
||||
.set = gfs2_xattr_set,
|
||||
};
|
||||
|
||||
static struct xattr_handler gfs2_xattr_security_handler = {
|
||||
.prefix = XATTR_SECURITY_PREFIX,
|
||||
.get = gfs2_xattr_security_get,
|
||||
.set = gfs2_xattr_security_set,
|
||||
.flags = GFS2_EATYPE_SECURITY,
|
||||
.get = gfs2_xattr_get,
|
||||
.set = gfs2_xattr_set,
|
||||
};
|
||||
|
||||
struct xattr_handler *gfs2_xattr_handlers[] = {
|
||||
|
@ -53,10 +53,9 @@ struct gfs2_ea_location {
|
||||
struct gfs2_ea_header *el_prev;
|
||||
};
|
||||
|
||||
extern int gfs2_xattr_get(struct inode *inode, int type, const char *name,
|
||||
void *buffer, size_t size);
|
||||
extern int gfs2_xattr_set(struct inode *inode, int type, const char *name,
|
||||
const void *value, size_t size, int flags);
|
||||
extern int __gfs2_xattr_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size,
|
||||
int flags, int type);
|
||||
extern ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size);
|
||||
extern int gfs2_ea_dealloc(struct gfs2_inode *ip);
|
||||
|
||||
|
@ -30,7 +30,6 @@
|
||||
#include <linux/dnotify.h>
|
||||
#include <linux/statfs.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/ima.h>
|
||||
#include <linux/magic.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
@ -922,7 +921,8 @@ struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag,
|
||||
int error = -ENOMEM;
|
||||
struct file *file;
|
||||
struct inode *inode;
|
||||
struct dentry *dentry, *root;
|
||||
struct path path;
|
||||
struct dentry *root;
|
||||
struct qstr quick_string;
|
||||
|
||||
*user = NULL;
|
||||
@ -944,10 +944,11 @@ struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag,
|
||||
quick_string.name = name;
|
||||
quick_string.len = strlen(quick_string.name);
|
||||
quick_string.hash = 0;
|
||||
dentry = d_alloc(root, &quick_string);
|
||||
if (!dentry)
|
||||
path.dentry = d_alloc(root, &quick_string);
|
||||
if (!path.dentry)
|
||||
goto out_shm_unlock;
|
||||
|
||||
path.mnt = mntget(hugetlbfs_vfsmount);
|
||||
error = -ENOSPC;
|
||||
inode = hugetlbfs_get_inode(root->d_sb, current_fsuid(),
|
||||
current_fsgid(), S_IFREG | S_IRWXUGO, 0);
|
||||
@ -960,24 +961,22 @@ struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag,
|
||||
acctflag))
|
||||
goto out_inode;
|
||||
|
||||
d_instantiate(dentry, inode);
|
||||
d_instantiate(path.dentry, inode);
|
||||
inode->i_size = size;
|
||||
inode->i_nlink = 0;
|
||||
|
||||
error = -ENFILE;
|
||||
file = alloc_file(hugetlbfs_vfsmount, dentry,
|
||||
FMODE_WRITE | FMODE_READ,
|
||||
file = alloc_file(&path, FMODE_WRITE | FMODE_READ,
|
||||
&hugetlbfs_file_operations);
|
||||
if (!file)
|
||||
goto out_dentry; /* inode is already attached */
|
||||
ima_counts_get(file);
|
||||
|
||||
return file;
|
||||
|
||||
out_inode:
|
||||
iput(inode);
|
||||
out_dentry:
|
||||
dput(dentry);
|
||||
path_put(&path);
|
||||
out_shm_unlock:
|
||||
if (*user) {
|
||||
user_shm_unlock(size, *user);
|
||||
|
@ -79,6 +79,7 @@ extern void chroot_fs_refs(struct path *, struct path *);
|
||||
* file_table.c
|
||||
*/
|
||||
extern void mark_files_ro(struct super_block *);
|
||||
extern struct file *get_empty_filp(void);
|
||||
|
||||
/*
|
||||
* super.c
|
||||
|
@ -350,8 +350,8 @@ int jffs2_acl_chmod(struct inode *inode)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static size_t jffs2_acl_access_listxattr(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
static size_t jffs2_acl_access_listxattr(struct dentry *dentry, char *list,
|
||||
size_t list_size, const char *name, size_t name_len, int type)
|
||||
{
|
||||
const int retlen = sizeof(POSIX_ACL_XATTR_ACCESS);
|
||||
|
||||
@ -360,8 +360,8 @@ static size_t jffs2_acl_access_listxattr(struct inode *inode, char *list, size_t
|
||||
return retlen;
|
||||
}
|
||||
|
||||
static size_t jffs2_acl_default_listxattr(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
static size_t jffs2_acl_default_listxattr(struct dentry *dentry, char *list,
|
||||
size_t list_size, const char *name, size_t name_len, int type)
|
||||
{
|
||||
const int retlen = sizeof(POSIX_ACL_XATTR_DEFAULT);
|
||||
|
||||
@ -370,12 +370,16 @@ static size_t jffs2_acl_default_listxattr(struct inode *inode, char *list, size_
|
||||
return retlen;
|
||||
}
|
||||
|
||||
static int jffs2_acl_getxattr(struct inode *inode, int type, void *buffer, size_t size)
|
||||
static int jffs2_acl_getxattr(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size, int type)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int rc;
|
||||
|
||||
acl = jffs2_get_acl(inode, type);
|
||||
if (name[0] != '\0')
|
||||
return -EINVAL;
|
||||
|
||||
acl = jffs2_get_acl(dentry->d_inode, type);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
if (!acl)
|
||||
@ -386,26 +390,15 @@ static int jffs2_acl_getxattr(struct inode *inode, int type, void *buffer, size_
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int jffs2_acl_access_getxattr(struct inode *inode, const char *name, void *buffer, size_t size)
|
||||
{
|
||||
if (name[0] != '\0')
|
||||
return -EINVAL;
|
||||
return jffs2_acl_getxattr(inode, ACL_TYPE_ACCESS, buffer, size);
|
||||
}
|
||||
|
||||
static int jffs2_acl_default_getxattr(struct inode *inode, const char *name, void *buffer, size_t size)
|
||||
{
|
||||
if (name[0] != '\0')
|
||||
return -EINVAL;
|
||||
return jffs2_acl_getxattr(inode, ACL_TYPE_DEFAULT, buffer, size);
|
||||
}
|
||||
|
||||
static int jffs2_acl_setxattr(struct inode *inode, int type, const void *value, size_t size)
|
||||
static int jffs2_acl_setxattr(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags, int type)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int rc;
|
||||
|
||||
if (!is_owner_or_cap(inode))
|
||||
if (name[0] != '\0')
|
||||
return -EINVAL;
|
||||
if (!is_owner_or_cap(dentry->d_inode))
|
||||
return -EPERM;
|
||||
|
||||
if (value) {
|
||||
@ -420,38 +413,24 @@ static int jffs2_acl_setxattr(struct inode *inode, int type, const void *value,
|
||||
} else {
|
||||
acl = NULL;
|
||||
}
|
||||
rc = jffs2_set_acl(inode, type, acl);
|
||||
rc = jffs2_set_acl(dentry->d_inode, type, acl);
|
||||
out:
|
||||
posix_acl_release(acl);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int jffs2_acl_access_setxattr(struct inode *inode, const char *name,
|
||||
const void *buffer, size_t size, int flags)
|
||||
{
|
||||
if (name[0] != '\0')
|
||||
return -EINVAL;
|
||||
return jffs2_acl_setxattr(inode, ACL_TYPE_ACCESS, buffer, size);
|
||||
}
|
||||
|
||||
static int jffs2_acl_default_setxattr(struct inode *inode, const char *name,
|
||||
const void *buffer, size_t size, int flags)
|
||||
{
|
||||
if (name[0] != '\0')
|
||||
return -EINVAL;
|
||||
return jffs2_acl_setxattr(inode, ACL_TYPE_DEFAULT, buffer, size);
|
||||
}
|
||||
|
||||
struct xattr_handler jffs2_acl_access_xattr_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_ACCESS,
|
||||
.flags = ACL_TYPE_DEFAULT,
|
||||
.list = jffs2_acl_access_listxattr,
|
||||
.get = jffs2_acl_access_getxattr,
|
||||
.set = jffs2_acl_access_setxattr,
|
||||
.get = jffs2_acl_getxattr,
|
||||
.set = jffs2_acl_setxattr,
|
||||
};
|
||||
|
||||
struct xattr_handler jffs2_acl_default_xattr_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_DEFAULT,
|
||||
.flags = ACL_TYPE_DEFAULT,
|
||||
.list = jffs2_acl_default_listxattr,
|
||||
.get = jffs2_acl_default_getxattr,
|
||||
.set = jffs2_acl_default_setxattr,
|
||||
.get = jffs2_acl_getxattr,
|
||||
.set = jffs2_acl_setxattr,
|
||||
};
|
||||
|
@ -44,26 +44,28 @@ int jffs2_init_security(struct inode *inode, struct inode *dir)
|
||||
}
|
||||
|
||||
/* ---- XATTR Handler for "security.*" ----------------- */
|
||||
static int jffs2_security_getxattr(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
static int jffs2_security_getxattr(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size, int type)
|
||||
{
|
||||
if (!strcmp(name, ""))
|
||||
return -EINVAL;
|
||||
|
||||
return do_jffs2_getxattr(inode, JFFS2_XPREFIX_SECURITY, name, buffer, size);
|
||||
return do_jffs2_getxattr(dentry->d_inode, JFFS2_XPREFIX_SECURITY,
|
||||
name, buffer, size);
|
||||
}
|
||||
|
||||
static int jffs2_security_setxattr(struct inode *inode, const char *name, const void *buffer,
|
||||
size_t size, int flags)
|
||||
static int jffs2_security_setxattr(struct dentry *dentry, const char *name,
|
||||
const void *buffer, size_t size, int flags, int type)
|
||||
{
|
||||
if (!strcmp(name, ""))
|
||||
return -EINVAL;
|
||||
|
||||
return do_jffs2_setxattr(inode, JFFS2_XPREFIX_SECURITY, name, buffer, size, flags);
|
||||
return do_jffs2_setxattr(dentry->d_inode, JFFS2_XPREFIX_SECURITY,
|
||||
name, buffer, size, flags);
|
||||
}
|
||||
|
||||
static size_t jffs2_security_listxattr(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
static size_t jffs2_security_listxattr(struct dentry *dentry, char *list,
|
||||
size_t list_size, const char *name, size_t name_len, int type)
|
||||
{
|
||||
size_t retlen = XATTR_SECURITY_PREFIX_LEN + name_len + 1;
|
||||
|
||||
|
@ -990,9 +990,11 @@ ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
||||
if (!xhandle)
|
||||
continue;
|
||||
if (buffer) {
|
||||
rc = xhandle->list(inode, buffer+len, size-len, xd->xname, xd->name_len);
|
||||
rc = xhandle->list(dentry, buffer+len, size-len,
|
||||
xd->xname, xd->name_len, xd->flags);
|
||||
} else {
|
||||
rc = xhandle->list(inode, NULL, 0, xd->xname, xd->name_len);
|
||||
rc = xhandle->list(dentry, NULL, 0, xd->xname,
|
||||
xd->name_len, xd->flags);
|
||||
}
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
@ -16,24 +16,26 @@
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include "nodelist.h"
|
||||
|
||||
static int jffs2_trusted_getxattr(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
static int jffs2_trusted_getxattr(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size, int type)
|
||||
{
|
||||
if (!strcmp(name, ""))
|
||||
return -EINVAL;
|
||||
return do_jffs2_getxattr(inode, JFFS2_XPREFIX_TRUSTED, name, buffer, size);
|
||||
return do_jffs2_getxattr(dentry->d_inode, JFFS2_XPREFIX_TRUSTED,
|
||||
name, buffer, size);
|
||||
}
|
||||
|
||||
static int jffs2_trusted_setxattr(struct inode *inode, const char *name, const void *buffer,
|
||||
size_t size, int flags)
|
||||
static int jffs2_trusted_setxattr(struct dentry *dentry, const char *name,
|
||||
const void *buffer, size_t size, int flags, int type)
|
||||
{
|
||||
if (!strcmp(name, ""))
|
||||
return -EINVAL;
|
||||
return do_jffs2_setxattr(inode, JFFS2_XPREFIX_TRUSTED, name, buffer, size, flags);
|
||||
return do_jffs2_setxattr(dentry->d_inode, JFFS2_XPREFIX_TRUSTED,
|
||||
name, buffer, size, flags);
|
||||
}
|
||||
|
||||
static size_t jffs2_trusted_listxattr(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
static size_t jffs2_trusted_listxattr(struct dentry *dentry, char *list,
|
||||
size_t list_size, const char *name, size_t name_len, int type)
|
||||
{
|
||||
size_t retlen = XATTR_TRUSTED_PREFIX_LEN + name_len + 1;
|
||||
|
||||
|
@ -16,24 +16,26 @@
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include "nodelist.h"
|
||||
|
||||
static int jffs2_user_getxattr(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
static int jffs2_user_getxattr(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size, int type)
|
||||
{
|
||||
if (!strcmp(name, ""))
|
||||
return -EINVAL;
|
||||
return do_jffs2_getxattr(inode, JFFS2_XPREFIX_USER, name, buffer, size);
|
||||
return do_jffs2_getxattr(dentry->d_inode, JFFS2_XPREFIX_USER,
|
||||
name, buffer, size);
|
||||
}
|
||||
|
||||
static int jffs2_user_setxattr(struct inode *inode, const char *name, const void *buffer,
|
||||
size_t size, int flags)
|
||||
static int jffs2_user_setxattr(struct dentry *dentry, const char *name,
|
||||
const void *buffer, size_t size, int flags, int type)
|
||||
{
|
||||
if (!strcmp(name, ""))
|
||||
return -EINVAL;
|
||||
return do_jffs2_setxattr(inode, JFFS2_XPREFIX_USER, name, buffer, size, flags);
|
||||
return do_jffs2_setxattr(dentry->d_inode, JFFS2_XPREFIX_USER,
|
||||
name, buffer, size, flags);
|
||||
}
|
||||
|
||||
static size_t jffs2_user_listxattr(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
static size_t jffs2_user_listxattr(struct dentry *dentry, char *list,
|
||||
size_t list_size, const char *name, size_t name_len, int type)
|
||||
{
|
||||
size_t retlen = XATTR_USER_PREFIX_LEN + name_len + 1;
|
||||
|
||||
|
@ -848,7 +848,6 @@ EXPORT_SYMBOL(simple_write_end);
|
||||
EXPORT_SYMBOL(simple_dir_inode_operations);
|
||||
EXPORT_SYMBOL(simple_dir_operations);
|
||||
EXPORT_SYMBOL(simple_empty);
|
||||
EXPORT_SYMBOL(d_alloc_name);
|
||||
EXPORT_SYMBOL(simple_fill_super);
|
||||
EXPORT_SYMBOL(simple_getattr);
|
||||
EXPORT_SYMBOL(simple_link);
|
||||
|
466
fs/namei.c
466
fs/namei.c
@ -35,6 +35,8 @@
|
||||
#include <linux/fs_struct.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
|
||||
|
||||
/* [Feb-1997 T. Schoebel-Theuer]
|
||||
@ -108,8 +110,6 @@
|
||||
* any extra contention...
|
||||
*/
|
||||
|
||||
static int __link_path_walk(const char *name, struct nameidata *nd);
|
||||
|
||||
/* In order to reduce some races, while at the same time doing additional
|
||||
* checking and hopefully speeding things up, we copy filenames to the
|
||||
* kernel data space before using them..
|
||||
@ -414,36 +414,55 @@ do_revalidate(struct dentry *dentry, struct nameidata *nd)
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal lookup() using the new generic dcache.
|
||||
* SMP-safe
|
||||
* force_reval_path - force revalidation of a dentry
|
||||
*
|
||||
* In some situations the path walking code will trust dentries without
|
||||
* revalidating them. This causes problems for filesystems that depend on
|
||||
* d_revalidate to handle file opens (e.g. NFSv4). When FS_REVAL_DOT is set
|
||||
* (which indicates that it's possible for the dentry to go stale), force
|
||||
* a d_revalidate call before proceeding.
|
||||
*
|
||||
* Returns 0 if the revalidation was successful. If the revalidation fails,
|
||||
* either return the error returned by d_revalidate or -ESTALE if the
|
||||
* revalidation it just returned 0. If d_revalidate returns 0, we attempt to
|
||||
* invalidate the dentry. It's up to the caller to handle putting references
|
||||
* to the path if necessary.
|
||||
*/
|
||||
static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, struct nameidata *nd)
|
||||
static int
|
||||
force_reval_path(struct path *path, struct nameidata *nd)
|
||||
{
|
||||
struct dentry * dentry = __d_lookup(parent, name);
|
||||
int status;
|
||||
struct dentry *dentry = path->dentry;
|
||||
|
||||
/* lockess __d_lookup may fail due to concurrent d_move()
|
||||
* in some unrelated directory, so try with d_lookup
|
||||
/*
|
||||
* only check on filesystems where it's possible for the dentry to
|
||||
* become stale. It's assumed that if this flag is set then the
|
||||
* d_revalidate op will also be defined.
|
||||
*/
|
||||
if (!dentry)
|
||||
dentry = d_lookup(parent, name);
|
||||
if (!(dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT))
|
||||
return 0;
|
||||
|
||||
if (dentry && dentry->d_op && dentry->d_op->d_revalidate)
|
||||
dentry = do_revalidate(dentry, nd);
|
||||
status = dentry->d_op->d_revalidate(dentry, nd);
|
||||
if (status > 0)
|
||||
return 0;
|
||||
|
||||
return dentry;
|
||||
if (!status) {
|
||||
d_invalidate(dentry);
|
||||
status = -ESTALE;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Short-cut version of permission(), for calling by
|
||||
* path_walk(), when dcache lock is held. Combines parts
|
||||
* of permission() and generic_permission(), and tests ONLY for
|
||||
* MAY_EXEC permission.
|
||||
* Short-cut version of permission(), for calling on directories
|
||||
* during pathname resolution. Combines parts of permission()
|
||||
* and generic_permission(), and tests ONLY for MAY_EXEC permission.
|
||||
*
|
||||
* If appropriate, check DAC only. If not appropriate, or
|
||||
* short-cut DAC fails, then call permission() to do more
|
||||
* short-cut DAC fails, then call ->permission() to do more
|
||||
* complete permission check.
|
||||
*/
|
||||
static int exec_permission_lite(struct inode *inode)
|
||||
static int exec_permission(struct inode *inode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -465,99 +484,6 @@ ok:
|
||||
return security_inode_permission(inode, MAY_EXEC);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called when everything else fails, and we actually have
|
||||
* to go to the low-level filesystem to find out what we should do..
|
||||
*
|
||||
* We get the directory semaphore, and after getting that we also
|
||||
* make sure that nobody added the entry to the dcache in the meantime..
|
||||
* SMP-safe
|
||||
*/
|
||||
static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, struct nameidata *nd)
|
||||
{
|
||||
struct dentry * result;
|
||||
struct inode *dir = parent->d_inode;
|
||||
|
||||
mutex_lock(&dir->i_mutex);
|
||||
/*
|
||||
* First re-do the cached lookup just in case it was created
|
||||
* while we waited for the directory semaphore..
|
||||
*
|
||||
* FIXME! This could use version numbering or similar to
|
||||
* avoid unnecessary cache lookups.
|
||||
*
|
||||
* The "dcache_lock" is purely to protect the RCU list walker
|
||||
* from concurrent renames at this point (we mustn't get false
|
||||
* negatives from the RCU list walk here, unlike the optimistic
|
||||
* fast walk).
|
||||
*
|
||||
* so doing d_lookup() (with seqlock), instead of lockfree __d_lookup
|
||||
*/
|
||||
result = d_lookup(parent, name);
|
||||
if (!result) {
|
||||
struct dentry *dentry;
|
||||
|
||||
/* Don't create child dentry for a dead directory. */
|
||||
result = ERR_PTR(-ENOENT);
|
||||
if (IS_DEADDIR(dir))
|
||||
goto out_unlock;
|
||||
|
||||
dentry = d_alloc(parent, name);
|
||||
result = ERR_PTR(-ENOMEM);
|
||||
if (dentry) {
|
||||
result = dir->i_op->lookup(dir, dentry, nd);
|
||||
if (result)
|
||||
dput(dentry);
|
||||
else
|
||||
result = dentry;
|
||||
}
|
||||
out_unlock:
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Uhhuh! Nasty case: the cache was re-populated while
|
||||
* we waited on the semaphore. Need to revalidate.
|
||||
*/
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
if (result->d_op && result->d_op->d_revalidate) {
|
||||
result = do_revalidate(result, nd);
|
||||
if (!result)
|
||||
result = ERR_PTR(-ENOENT);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper to retry pathname resolution whenever the underlying
|
||||
* file system returns an ESTALE.
|
||||
*
|
||||
* Retry the whole path once, forcing real lookup requests
|
||||
* instead of relying on the dcache.
|
||||
*/
|
||||
static __always_inline int link_path_walk(const char *name, struct nameidata *nd)
|
||||
{
|
||||
struct path save = nd->path;
|
||||
int result;
|
||||
|
||||
/* make sure the stuff we saved doesn't go away */
|
||||
path_get(&save);
|
||||
|
||||
result = __link_path_walk(name, nd);
|
||||
if (result == -ESTALE) {
|
||||
/* nd->path had been dropped */
|
||||
nd->path = save;
|
||||
path_get(&nd->path);
|
||||
nd->flags |= LOOKUP_REVAL;
|
||||
result = __link_path_walk(name, nd);
|
||||
}
|
||||
|
||||
path_put(&save);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static __always_inline void set_root(struct nameidata *nd)
|
||||
{
|
||||
if (!nd->root.mnt) {
|
||||
@ -569,6 +495,8 @@ static __always_inline void set_root(struct nameidata *nd)
|
||||
}
|
||||
}
|
||||
|
||||
static int link_path_walk(const char *, struct nameidata *);
|
||||
|
||||
static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
|
||||
{
|
||||
int res = 0;
|
||||
@ -641,11 +569,14 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata
|
||||
error = 0;
|
||||
if (s)
|
||||
error = __vfs_follow_link(nd, s);
|
||||
else if (nd->last_type == LAST_BIND) {
|
||||
error = force_reval_path(&nd->path, nd);
|
||||
if (error)
|
||||
path_put(&nd->path);
|
||||
}
|
||||
if (dentry->d_inode->i_op->put_link)
|
||||
dentry->d_inode->i_op->put_link(dentry, nd, cookie);
|
||||
}
|
||||
path_put(path);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -672,6 +603,7 @@ static inline int do_follow_link(struct path *path, struct nameidata *nd)
|
||||
current->total_link_count++;
|
||||
nd->depth++;
|
||||
err = __do_follow_link(path, nd);
|
||||
path_put(path);
|
||||
current->link_count--;
|
||||
nd->depth--;
|
||||
return err;
|
||||
@ -797,8 +729,19 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
|
||||
struct path *path)
|
||||
{
|
||||
struct vfsmount *mnt = nd->path.mnt;
|
||||
struct dentry *dentry = __d_lookup(nd->path.dentry, name);
|
||||
struct dentry *dentry, *parent;
|
||||
struct inode *dir;
|
||||
/*
|
||||
* See if the low-level filesystem might want
|
||||
* to use its own hash..
|
||||
*/
|
||||
if (nd->path.dentry->d_op && nd->path.dentry->d_op->d_hash) {
|
||||
int err = nd->path.dentry->d_op->d_hash(nd->path.dentry, name);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
dentry = __d_lookup(nd->path.dentry, name);
|
||||
if (!dentry)
|
||||
goto need_lookup;
|
||||
if (dentry->d_op && dentry->d_op->d_revalidate)
|
||||
@ -810,7 +753,59 @@ done:
|
||||
return 0;
|
||||
|
||||
need_lookup:
|
||||
dentry = real_lookup(nd->path.dentry, name, nd);
|
||||
parent = nd->path.dentry;
|
||||
dir = parent->d_inode;
|
||||
|
||||
mutex_lock(&dir->i_mutex);
|
||||
/*
|
||||
* First re-do the cached lookup just in case it was created
|
||||
* while we waited for the directory semaphore..
|
||||
*
|
||||
* FIXME! This could use version numbering or similar to
|
||||
* avoid unnecessary cache lookups.
|
||||
*
|
||||
* The "dcache_lock" is purely to protect the RCU list walker
|
||||
* from concurrent renames at this point (we mustn't get false
|
||||
* negatives from the RCU list walk here, unlike the optimistic
|
||||
* fast walk).
|
||||
*
|
||||
* so doing d_lookup() (with seqlock), instead of lockfree __d_lookup
|
||||
*/
|
||||
dentry = d_lookup(parent, name);
|
||||
if (!dentry) {
|
||||
struct dentry *new;
|
||||
|
||||
/* Don't create child dentry for a dead directory. */
|
||||
dentry = ERR_PTR(-ENOENT);
|
||||
if (IS_DEADDIR(dir))
|
||||
goto out_unlock;
|
||||
|
||||
new = d_alloc(parent, name);
|
||||
dentry = ERR_PTR(-ENOMEM);
|
||||
if (new) {
|
||||
dentry = dir->i_op->lookup(dir, new, nd);
|
||||
if (dentry)
|
||||
dput(new);
|
||||
else
|
||||
dentry = new;
|
||||
}
|
||||
out_unlock:
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
if (IS_ERR(dentry))
|
||||
goto fail;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Uhhuh! Nasty case: the cache was re-populated while
|
||||
* we waited on the semaphore. Need to revalidate.
|
||||
*/
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
if (dentry->d_op && dentry->d_op->d_revalidate) {
|
||||
dentry = do_revalidate(dentry, nd);
|
||||
if (!dentry)
|
||||
dentry = ERR_PTR(-ENOENT);
|
||||
}
|
||||
if (IS_ERR(dentry))
|
||||
goto fail;
|
||||
goto done;
|
||||
@ -835,7 +830,7 @@ fail:
|
||||
* Returns 0 and nd will have valid dentry and mnt on success.
|
||||
* Returns error and drops reference to input namei data on failure.
|
||||
*/
|
||||
static int __link_path_walk(const char *name, struct nameidata *nd)
|
||||
static int link_path_walk(const char *name, struct nameidata *nd)
|
||||
{
|
||||
struct path next;
|
||||
struct inode *inode;
|
||||
@ -858,7 +853,7 @@ static int __link_path_walk(const char *name, struct nameidata *nd)
|
||||
unsigned int c;
|
||||
|
||||
nd->flags |= LOOKUP_CONTINUE;
|
||||
err = exec_permission_lite(inode);
|
||||
err = exec_permission(inode);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -898,16 +893,6 @@ static int __link_path_walk(const char *name, struct nameidata *nd)
|
||||
case 1:
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* See if the low-level filesystem might want
|
||||
* to use its own hash..
|
||||
*/
|
||||
if (nd->path.dentry->d_op && nd->path.dentry->d_op->d_hash) {
|
||||
err = nd->path.dentry->d_op->d_hash(nd->path.dentry,
|
||||
&this);
|
||||
if (err < 0)
|
||||
break;
|
||||
}
|
||||
/* This does the actual lookups.. */
|
||||
err = do_lookup(nd, &this, &next);
|
||||
if (err)
|
||||
@ -953,12 +938,6 @@ last_component:
|
||||
case 1:
|
||||
goto return_reval;
|
||||
}
|
||||
if (nd->path.dentry->d_op && nd->path.dentry->d_op->d_hash) {
|
||||
err = nd->path.dentry->d_op->d_hash(nd->path.dentry,
|
||||
&this);
|
||||
if (err < 0)
|
||||
break;
|
||||
}
|
||||
err = do_lookup(nd, &this, &next);
|
||||
if (err)
|
||||
break;
|
||||
@ -1017,8 +996,27 @@ return_err:
|
||||
|
||||
static int path_walk(const char *name, struct nameidata *nd)
|
||||
{
|
||||
struct path save = nd->path;
|
||||
int result;
|
||||
|
||||
current->total_link_count = 0;
|
||||
return link_path_walk(name, nd);
|
||||
|
||||
/* make sure the stuff we saved doesn't go away */
|
||||
path_get(&save);
|
||||
|
||||
result = link_path_walk(name, nd);
|
||||
if (result == -ESTALE) {
|
||||
/* nd->path had been dropped */
|
||||
current->total_link_count = 0;
|
||||
nd->path = save;
|
||||
path_get(&nd->path);
|
||||
nd->flags |= LOOKUP_REVAL;
|
||||
result = link_path_walk(name, nd);
|
||||
}
|
||||
|
||||
path_put(&save);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int path_init(int dfd, const char *name, unsigned int flags, struct nameidata *nd)
|
||||
@ -1141,36 +1139,6 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* path_lookup_open - lookup a file path with open intent
|
||||
* @dfd: the directory to use as base, or AT_FDCWD
|
||||
* @name: pointer to file name
|
||||
* @lookup_flags: lookup intent flags
|
||||
* @nd: pointer to nameidata
|
||||
* @open_flags: open intent flags
|
||||
*/
|
||||
static int path_lookup_open(int dfd, const char *name,
|
||||
unsigned int lookup_flags, struct nameidata *nd, int open_flags)
|
||||
{
|
||||
struct file *filp = get_empty_filp();
|
||||
int err;
|
||||
|
||||
if (filp == NULL)
|
||||
return -ENFILE;
|
||||
nd->intent.open.file = filp;
|
||||
nd->intent.open.flags = open_flags;
|
||||
nd->intent.open.create_mode = 0;
|
||||
err = do_path_lookup(dfd, name, lookup_flags|LOOKUP_OPEN, nd);
|
||||
if (IS_ERR(nd->intent.open.file)) {
|
||||
if (err == 0) {
|
||||
err = PTR_ERR(nd->intent.open.file);
|
||||
path_put(&nd->path);
|
||||
}
|
||||
} else if (err != 0)
|
||||
release_open_intent(nd);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct dentry *__lookup_hash(struct qstr *name,
|
||||
struct dentry *base, struct nameidata *nd)
|
||||
{
|
||||
@ -1191,7 +1159,17 @@ static struct dentry *__lookup_hash(struct qstr *name,
|
||||
goto out;
|
||||
}
|
||||
|
||||
dentry = cached_lookup(base, name, nd);
|
||||
dentry = __d_lookup(base, name);
|
||||
|
||||
/* lockess __d_lookup may fail due to concurrent d_move()
|
||||
* in some unrelated directory, so try with d_lookup
|
||||
*/
|
||||
if (!dentry)
|
||||
dentry = d_lookup(base, name);
|
||||
|
||||
if (dentry && dentry->d_op && dentry->d_op->d_revalidate)
|
||||
dentry = do_revalidate(dentry, nd);
|
||||
|
||||
if (!dentry) {
|
||||
struct dentry *new;
|
||||
|
||||
@ -1223,7 +1201,7 @@ static struct dentry *lookup_hash(struct nameidata *nd)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = inode_permission(nd->path.dentry->d_inode, MAY_EXEC);
|
||||
err = exec_permission(nd->path.dentry->d_inode);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
return __lookup_hash(&nd->last, nd->path.dentry, nd);
|
||||
@ -1273,7 +1251,7 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
err = inode_permission(base->d_inode, MAY_EXEC);
|
||||
err = exec_permission(base->d_inode);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
return __lookup_hash(&this, base, NULL);
|
||||
@ -1511,69 +1489,45 @@ int may_open(struct path *path, int acc_mode, int flag)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = ima_path_check(path, acc_mode ?
|
||||
acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC) :
|
||||
ACC_MODE(flag) & (MAY_READ | MAY_WRITE),
|
||||
IMA_COUNT_UPDATE);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
/*
|
||||
* An append-only file must be opened in append mode for writing.
|
||||
*/
|
||||
if (IS_APPEND(inode)) {
|
||||
error = -EPERM;
|
||||
if ((flag & FMODE_WRITE) && !(flag & O_APPEND))
|
||||
goto err_out;
|
||||
return -EPERM;
|
||||
if (flag & O_TRUNC)
|
||||
goto err_out;
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/* O_NOATIME can only be set by the owner or superuser */
|
||||
if (flag & O_NOATIME)
|
||||
if (!is_owner_or_cap(inode)) {
|
||||
error = -EPERM;
|
||||
goto err_out;
|
||||
}
|
||||
if (flag & O_NOATIME && !is_owner_or_cap(inode))
|
||||
return -EPERM;
|
||||
|
||||
/*
|
||||
* Ensure there are no outstanding leases on the file.
|
||||
*/
|
||||
error = break_lease(inode, flag);
|
||||
return break_lease(inode, flag);
|
||||
}
|
||||
|
||||
static int handle_truncate(struct path *path)
|
||||
{
|
||||
struct inode *inode = path->dentry->d_inode;
|
||||
int error = get_write_access(inode);
|
||||
if (error)
|
||||
goto err_out;
|
||||
|
||||
if (flag & O_TRUNC) {
|
||||
error = get_write_access(inode);
|
||||
if (error)
|
||||
goto err_out;
|
||||
|
||||
/*
|
||||
* Refuse to truncate files with mandatory locks held on them.
|
||||
*/
|
||||
error = locks_verify_locked(inode);
|
||||
if (!error)
|
||||
error = security_path_truncate(path, 0,
|
||||
ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
|
||||
if (!error) {
|
||||
vfs_dq_init(inode);
|
||||
|
||||
error = do_truncate(dentry, 0,
|
||||
ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
|
||||
NULL);
|
||||
}
|
||||
put_write_access(inode);
|
||||
if (error)
|
||||
goto err_out;
|
||||
} else
|
||||
if (flag & FMODE_WRITE)
|
||||
vfs_dq_init(inode);
|
||||
|
||||
return 0;
|
||||
err_out:
|
||||
ima_counts_put(path, acc_mode ?
|
||||
acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC) :
|
||||
ACC_MODE(flag) & (MAY_READ | MAY_WRITE));
|
||||
return error;
|
||||
/*
|
||||
* Refuse to truncate files with mandatory locks held on them.
|
||||
*/
|
||||
error = locks_verify_locked(inode);
|
||||
if (!error)
|
||||
error = security_path_truncate(path, 0,
|
||||
ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
|
||||
if (!error) {
|
||||
error = do_truncate(path->dentry, 0,
|
||||
ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
|
||||
NULL);
|
||||
}
|
||||
put_write_access(inode);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -1628,7 +1582,7 @@ static inline int open_to_namei_flags(int flag)
|
||||
return flag;
|
||||
}
|
||||
|
||||
static int open_will_write_to_fs(int flag, struct inode *inode)
|
||||
static int open_will_truncate(int flag, struct inode *inode)
|
||||
{
|
||||
/*
|
||||
* We'll never write to the fs underlying
|
||||
@ -1650,10 +1604,10 @@ struct file *do_filp_open(int dfd, const char *pathname,
|
||||
struct file *filp;
|
||||
struct nameidata nd;
|
||||
int error;
|
||||
struct path path;
|
||||
struct path path, save;
|
||||
struct dentry *dir;
|
||||
int count = 0;
|
||||
int will_write;
|
||||
int will_truncate;
|
||||
int flag = open_to_namei_flags(open_flag);
|
||||
|
||||
/*
|
||||
@ -1681,8 +1635,22 @@ struct file *do_filp_open(int dfd, const char *pathname,
|
||||
* The simplest case - just a plain lookup.
|
||||
*/
|
||||
if (!(flag & O_CREAT)) {
|
||||
error = path_lookup_open(dfd, pathname, lookup_flags(flag),
|
||||
&nd, flag);
|
||||
filp = get_empty_filp();
|
||||
|
||||
if (filp == NULL)
|
||||
return ERR_PTR(-ENFILE);
|
||||
nd.intent.open.file = filp;
|
||||
nd.intent.open.flags = flag;
|
||||
nd.intent.open.create_mode = 0;
|
||||
error = do_path_lookup(dfd, pathname,
|
||||
lookup_flags(flag)|LOOKUP_OPEN, &nd);
|
||||
if (IS_ERR(nd.intent.open.file)) {
|
||||
if (error == 0) {
|
||||
error = PTR_ERR(nd.intent.open.file);
|
||||
path_put(&nd.path);
|
||||
}
|
||||
} else if (error)
|
||||
release_open_intent(&nd);
|
||||
if (error)
|
||||
return ERR_PTR(error);
|
||||
goto ok;
|
||||
@ -1758,13 +1726,17 @@ do_last:
|
||||
goto exit;
|
||||
}
|
||||
filp = nameidata_to_filp(&nd, open_flag);
|
||||
if (IS_ERR(filp))
|
||||
ima_counts_put(&nd.path,
|
||||
acc_mode & (MAY_READ | MAY_WRITE |
|
||||
MAY_EXEC));
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
if (nd.root.mnt)
|
||||
path_put(&nd.root);
|
||||
if (!IS_ERR(filp)) {
|
||||
error = ima_path_check(&filp->f_path, filp->f_mode &
|
||||
(MAY_READ | MAY_WRITE | MAY_EXEC));
|
||||
if (error) {
|
||||
fput(filp);
|
||||
filp = ERR_PTR(error);
|
||||
}
|
||||
}
|
||||
return filp;
|
||||
}
|
||||
|
||||
@ -1805,28 +1777,45 @@ ok:
|
||||
* be avoided. Taking this mnt write here
|
||||
* ensures that (2) can not occur.
|
||||
*/
|
||||
will_write = open_will_write_to_fs(flag, nd.path.dentry->d_inode);
|
||||
if (will_write) {
|
||||
will_truncate = open_will_truncate(flag, nd.path.dentry->d_inode);
|
||||
if (will_truncate) {
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto exit;
|
||||
}
|
||||
error = may_open(&nd.path, acc_mode, flag);
|
||||
if (error) {
|
||||
if (will_write)
|
||||
if (will_truncate)
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
goto exit;
|
||||
}
|
||||
filp = nameidata_to_filp(&nd, open_flag);
|
||||
if (IS_ERR(filp))
|
||||
ima_counts_put(&nd.path,
|
||||
acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC));
|
||||
if (!IS_ERR(filp)) {
|
||||
error = ima_path_check(&filp->f_path, filp->f_mode &
|
||||
(MAY_READ | MAY_WRITE | MAY_EXEC));
|
||||
if (error) {
|
||||
fput(filp);
|
||||
filp = ERR_PTR(error);
|
||||
}
|
||||
}
|
||||
if (!IS_ERR(filp)) {
|
||||
if (acc_mode & MAY_WRITE)
|
||||
vfs_dq_init(nd.path.dentry->d_inode);
|
||||
|
||||
if (will_truncate) {
|
||||
error = handle_truncate(&nd.path);
|
||||
if (error) {
|
||||
fput(filp);
|
||||
filp = ERR_PTR(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* It is now safe to drop the mnt write
|
||||
* because the filp has had a write taken
|
||||
* on its behalf.
|
||||
*/
|
||||
if (will_write)
|
||||
if (will_truncate)
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
if (nd.root.mnt)
|
||||
path_put(&nd.root);
|
||||
@ -1863,7 +1852,18 @@ do_link:
|
||||
error = security_inode_follow_link(path.dentry, &nd);
|
||||
if (error)
|
||||
goto exit_dput;
|
||||
save = nd.path;
|
||||
path_get(&save);
|
||||
error = __do_follow_link(&path, &nd);
|
||||
if (error == -ESTALE) {
|
||||
/* nd.path had been dropped */
|
||||
nd.path = save;
|
||||
path_get(&nd.path);
|
||||
nd.flags |= LOOKUP_REVAL;
|
||||
error = __do_follow_link(&path, &nd);
|
||||
}
|
||||
path_put(&save);
|
||||
path_put(&path);
|
||||
if (error) {
|
||||
/* Does someone understand code flow here? Or it is only
|
||||
* me so stupid? Anathema to whoever designed this non-sense
|
||||
|
@ -2068,7 +2068,7 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
|
||||
* create_mnt_ns - creates a private namespace and adds a root filesystem
|
||||
* @mnt: pointer to the new root filesystem mountpoint
|
||||
*/
|
||||
struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt)
|
||||
static struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt)
|
||||
{
|
||||
struct mnt_namespace *new_ns;
|
||||
|
||||
@ -2080,7 +2080,6 @@ struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt)
|
||||
}
|
||||
return new_ns;
|
||||
}
|
||||
EXPORT_SYMBOL(create_mnt_ns);
|
||||
|
||||
SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
|
||||
char __user *, type, unsigned long, flags, void __user *, data)
|
||||
|
@ -2648,21 +2648,13 @@ out_freepage:
|
||||
static int nfs_follow_remote_path(struct vfsmount *root_mnt,
|
||||
const char *export_path, struct vfsmount *mnt_target)
|
||||
{
|
||||
struct mnt_namespace *ns_private;
|
||||
struct nameidata nd;
|
||||
struct super_block *s;
|
||||
int ret;
|
||||
|
||||
ns_private = create_mnt_ns(root_mnt);
|
||||
ret = PTR_ERR(ns_private);
|
||||
if (IS_ERR(ns_private))
|
||||
goto out_mntput;
|
||||
|
||||
ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt,
|
||||
export_path, LOOKUP_FOLLOW, &nd);
|
||||
|
||||
put_mnt_ns(ns_private);
|
||||
|
||||
if (ret != 0)
|
||||
goto out_err;
|
||||
|
||||
|
@ -752,8 +752,6 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
|
||||
flags, current_cred());
|
||||
if (IS_ERR(*filp))
|
||||
host_err = PTR_ERR(*filp);
|
||||
else
|
||||
ima_counts_get(*filp);
|
||||
out_nfserr:
|
||||
err = nfserrno(host_err);
|
||||
out:
|
||||
@ -2132,8 +2130,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
|
||||
*/
|
||||
path.mnt = exp->ex_path.mnt;
|
||||
path.dentry = dentry;
|
||||
err = ima_path_check(&path, acc & (MAY_READ | MAY_WRITE | MAY_EXEC),
|
||||
IMA_COUNT_LEAVE);
|
||||
err = ima_path_check(&path, acc & (MAY_READ | MAY_WRITE | MAY_EXEC));
|
||||
nfsd_out:
|
||||
return err? nfserrno(err) : 0;
|
||||
}
|
||||
|
@ -1118,8 +1118,7 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
|
||||
/* Abandoning the newly allocated superblock */
|
||||
mutex_unlock(&nilfs->ns_mount_mutex);
|
||||
put_nilfs(nilfs);
|
||||
up_write(&s->s_umount);
|
||||
deactivate_super(s);
|
||||
deactivate_locked_super(s);
|
||||
/*
|
||||
* deactivate_super() invokes close_bdev_exclusive().
|
||||
* We must finish all post-cleaning before this call;
|
||||
|
@ -646,6 +646,7 @@ SYSCALL_DEFINE1(inotify_init1, int, flags)
|
||||
struct fsnotify_group *group;
|
||||
struct user_struct *user;
|
||||
struct file *filp;
|
||||
struct path path;
|
||||
int fd, ret;
|
||||
|
||||
/* Check the IN_* constants for consistency. */
|
||||
@ -659,12 +660,6 @@ SYSCALL_DEFINE1(inotify_init1, int, flags)
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
filp = get_empty_filp();
|
||||
if (!filp) {
|
||||
ret = -ENFILE;
|
||||
goto out_put_fd;
|
||||
}
|
||||
|
||||
user = get_current_user();
|
||||
if (unlikely(atomic_read(&user->inotify_devs) >=
|
||||
inotify_max_user_instances)) {
|
||||
@ -679,24 +674,28 @@ SYSCALL_DEFINE1(inotify_init1, int, flags)
|
||||
goto out_free_uid;
|
||||
}
|
||||
|
||||
filp->f_op = &inotify_fops;
|
||||
filp->f_path.mnt = mntget(inotify_mnt);
|
||||
filp->f_path.dentry = dget(inotify_mnt->mnt_root);
|
||||
filp->f_mapping = filp->f_path.dentry->d_inode->i_mapping;
|
||||
filp->f_mode = FMODE_READ;
|
||||
atomic_inc(&user->inotify_devs);
|
||||
|
||||
path.mnt = inotify_mnt;
|
||||
path.dentry = inotify_mnt->mnt_root;
|
||||
path_get(&path);
|
||||
filp = alloc_file(&path, FMODE_READ, &inotify_fops);
|
||||
if (!filp)
|
||||
goto Enfile;
|
||||
|
||||
filp->f_flags = O_RDONLY | (flags & O_NONBLOCK);
|
||||
filp->private_data = group;
|
||||
|
||||
atomic_inc(&user->inotify_devs);
|
||||
|
||||
fd_install(fd, filp);
|
||||
|
||||
return fd;
|
||||
|
||||
Enfile:
|
||||
ret = -ENFILE;
|
||||
path_put(&path);
|
||||
atomic_dec(&user->inotify_devs);
|
||||
out_free_uid:
|
||||
free_uid(user);
|
||||
put_filp(filp);
|
||||
out_put_fd:
|
||||
put_unused_fd(fd);
|
||||
return ret;
|
||||
}
|
||||
|
@ -331,13 +331,14 @@ cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t ocfs2_xattr_list_acl_access(struct inode *inode,
|
||||
static size_t ocfs2_xattr_list_acl_access(struct dentry *dentry,
|
||||
char *list,
|
||||
size_t list_len,
|
||||
const char *name,
|
||||
size_t name_len)
|
||||
size_t name_len,
|
||||
int type)
|
||||
{
|
||||
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||||
struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
|
||||
const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
|
||||
|
||||
if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
|
||||
@ -348,13 +349,14 @@ static size_t ocfs2_xattr_list_acl_access(struct inode *inode,
|
||||
return size;
|
||||
}
|
||||
|
||||
static size_t ocfs2_xattr_list_acl_default(struct inode *inode,
|
||||
static size_t ocfs2_xattr_list_acl_default(struct dentry *dentry,
|
||||
char *list,
|
||||
size_t list_len,
|
||||
const char *name,
|
||||
size_t name_len)
|
||||
size_t name_len,
|
||||
int type)
|
||||
{
|
||||
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||||
struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
|
||||
const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
|
||||
|
||||
if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
|
||||
@ -365,19 +367,19 @@ static size_t ocfs2_xattr_list_acl_default(struct inode *inode,
|
||||
return size;
|
||||
}
|
||||
|
||||
static int ocfs2_xattr_get_acl(struct inode *inode,
|
||||
int type,
|
||||
void *buffer,
|
||||
size_t size)
|
||||
static int ocfs2_xattr_get_acl(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size, int type)
|
||||
{
|
||||
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||||
struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
|
||||
struct posix_acl *acl;
|
||||
int ret;
|
||||
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
acl = ocfs2_get_acl(inode, type);
|
||||
acl = ocfs2_get_acl(dentry->d_inode, type);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
if (acl == NULL)
|
||||
@ -388,35 +390,16 @@ static int ocfs2_xattr_get_acl(struct inode *inode,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ocfs2_xattr_get_acl_access(struct inode *inode,
|
||||
const char *name,
|
||||
void *buffer,
|
||||
size_t size)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return ocfs2_xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size);
|
||||
}
|
||||
|
||||
static int ocfs2_xattr_get_acl_default(struct inode *inode,
|
||||
const char *name,
|
||||
void *buffer,
|
||||
size_t size)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return ocfs2_xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size);
|
||||
}
|
||||
|
||||
static int ocfs2_xattr_set_acl(struct inode *inode,
|
||||
int type,
|
||||
const void *value,
|
||||
size_t size)
|
||||
static int ocfs2_xattr_set_acl(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags, int type)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||||
struct posix_acl *acl;
|
||||
int ret = 0;
|
||||
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
@ -442,38 +425,18 @@ cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ocfs2_xattr_set_acl_access(struct inode *inode,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size,
|
||||
int flags)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return ocfs2_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
|
||||
}
|
||||
|
||||
static int ocfs2_xattr_set_acl_default(struct inode *inode,
|
||||
const char *name,
|
||||
const void *value,
|
||||
size_t size,
|
||||
int flags)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return ocfs2_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
|
||||
}
|
||||
|
||||
struct xattr_handler ocfs2_xattr_acl_access_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_ACCESS,
|
||||
.flags = ACL_TYPE_ACCESS,
|
||||
.list = ocfs2_xattr_list_acl_access,
|
||||
.get = ocfs2_xattr_get_acl_access,
|
||||
.set = ocfs2_xattr_set_acl_access,
|
||||
.get = ocfs2_xattr_get_acl,
|
||||
.set = ocfs2_xattr_set_acl,
|
||||
};
|
||||
|
||||
struct xattr_handler ocfs2_xattr_acl_default_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_DEFAULT,
|
||||
.flags = ACL_TYPE_DEFAULT,
|
||||
.list = ocfs2_xattr_list_acl_default,
|
||||
.get = ocfs2_xattr_get_acl_default,
|
||||
.set = ocfs2_xattr_set_acl_default,
|
||||
.get = ocfs2_xattr_get_acl,
|
||||
.set = ocfs2_xattr_set_acl,
|
||||
};
|
||||
|
@ -7190,8 +7190,8 @@ int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle,
|
||||
* wait on them - the truncate_inode_pages() call later will
|
||||
* do that for us.
|
||||
*/
|
||||
ret = do_sync_mapping_range(inode->i_mapping, range_start,
|
||||
range_end - 1, SYNC_FILE_RANGE_WRITE);
|
||||
ret = filemap_fdatawrite_range(inode->i_mapping, range_start,
|
||||
range_end - 1);
|
||||
if (ret)
|
||||
mlog_errno(ret);
|
||||
|
||||
|
@ -205,8 +205,6 @@ static int ocfs2_get_xattr_tree_value_root(struct super_block *sb,
|
||||
int offset,
|
||||
struct ocfs2_xattr_value_root **xv,
|
||||
struct buffer_head **bh);
|
||||
static int ocfs2_xattr_security_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags);
|
||||
|
||||
static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb)
|
||||
{
|
||||
@ -6978,9 +6976,9 @@ int ocfs2_init_security_and_acl(struct inode *dir,
|
||||
|
||||
ret = ocfs2_init_security_get(inode, dir, &si);
|
||||
if (!ret) {
|
||||
ret = ocfs2_xattr_security_set(inode, si.name,
|
||||
si.value, si.value_len,
|
||||
XATTR_CREATE);
|
||||
ret = ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_SECURITY,
|
||||
si.name, si.value, si.value_len,
|
||||
XATTR_CREATE);
|
||||
if (ret) {
|
||||
mlog_errno(ret);
|
||||
goto leave;
|
||||
@ -7008,9 +7006,9 @@ leave:
|
||||
/*
|
||||
* 'security' attributes support
|
||||
*/
|
||||
static size_t ocfs2_xattr_security_list(struct inode *inode, char *list,
|
||||
static size_t ocfs2_xattr_security_list(struct dentry *dentry, char *list,
|
||||
size_t list_size, const char *name,
|
||||
size_t name_len)
|
||||
size_t name_len, int type)
|
||||
{
|
||||
const size_t prefix_len = XATTR_SECURITY_PREFIX_LEN;
|
||||
const size_t total_len = prefix_len + name_len + 1;
|
||||
@ -7023,23 +7021,23 @@ static size_t ocfs2_xattr_security_list(struct inode *inode, char *list,
|
||||
return total_len;
|
||||
}
|
||||
|
||||
static int ocfs2_xattr_security_get(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
static int ocfs2_xattr_security_get(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_SECURITY, name,
|
||||
buffer, size);
|
||||
return ocfs2_xattr_get(dentry->d_inode, OCFS2_XATTR_INDEX_SECURITY,
|
||||
name, buffer, size);
|
||||
}
|
||||
|
||||
static int ocfs2_xattr_security_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
static int ocfs2_xattr_security_set(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_SECURITY, name, value,
|
||||
size, flags);
|
||||
return ocfs2_xattr_set(dentry->d_inode, OCFS2_XATTR_INDEX_SECURITY,
|
||||
name, value, size, flags);
|
||||
}
|
||||
|
||||
int ocfs2_init_security_get(struct inode *inode,
|
||||
@ -7076,9 +7074,9 @@ struct xattr_handler ocfs2_xattr_security_handler = {
|
||||
/*
|
||||
* 'trusted' attributes support
|
||||
*/
|
||||
static size_t ocfs2_xattr_trusted_list(struct inode *inode, char *list,
|
||||
static size_t ocfs2_xattr_trusted_list(struct dentry *dentry, char *list,
|
||||
size_t list_size, const char *name,
|
||||
size_t name_len)
|
||||
size_t name_len, int type)
|
||||
{
|
||||
const size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN;
|
||||
const size_t total_len = prefix_len + name_len + 1;
|
||||
@ -7091,23 +7089,23 @@ static size_t ocfs2_xattr_trusted_list(struct inode *inode, char *list,
|
||||
return total_len;
|
||||
}
|
||||
|
||||
static int ocfs2_xattr_trusted_get(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
static int ocfs2_xattr_trusted_get(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_TRUSTED, name,
|
||||
buffer, size);
|
||||
return ocfs2_xattr_get(dentry->d_inode, OCFS2_XATTR_INDEX_TRUSTED,
|
||||
name, buffer, size);
|
||||
}
|
||||
|
||||
static int ocfs2_xattr_trusted_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
static int ocfs2_xattr_trusted_set(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags, int type)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_TRUSTED, name, value,
|
||||
size, flags);
|
||||
return ocfs2_xattr_set(dentry->d_inode, OCFS2_XATTR_INDEX_TRUSTED,
|
||||
name, value, size, flags);
|
||||
}
|
||||
|
||||
struct xattr_handler ocfs2_xattr_trusted_handler = {
|
||||
@ -7120,13 +7118,13 @@ struct xattr_handler ocfs2_xattr_trusted_handler = {
|
||||
/*
|
||||
* 'user' attributes support
|
||||
*/
|
||||
static size_t ocfs2_xattr_user_list(struct inode *inode, char *list,
|
||||
static size_t ocfs2_xattr_user_list(struct dentry *dentry, char *list,
|
||||
size_t list_size, const char *name,
|
||||
size_t name_len)
|
||||
size_t name_len, int type)
|
||||
{
|
||||
const size_t prefix_len = XATTR_USER_PREFIX_LEN;
|
||||
const size_t total_len = prefix_len + name_len + 1;
|
||||
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||||
struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
|
||||
|
||||
if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
|
||||
return 0;
|
||||
@ -7139,31 +7137,31 @@ static size_t ocfs2_xattr_user_list(struct inode *inode, char *list,
|
||||
return total_len;
|
||||
}
|
||||
|
||||
static int ocfs2_xattr_user_get(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
static int ocfs2_xattr_user_get(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size, int type)
|
||||
{
|
||||
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||||
struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
|
||||
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
|
||||
return -EOPNOTSUPP;
|
||||
return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_USER, name,
|
||||
return ocfs2_xattr_get(dentry->d_inode, OCFS2_XATTR_INDEX_USER, name,
|
||||
buffer, size);
|
||||
}
|
||||
|
||||
static int ocfs2_xattr_user_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
static int ocfs2_xattr_user_set(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags, int type)
|
||||
{
|
||||
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||||
struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
|
||||
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_USER, name, value,
|
||||
size, flags);
|
||||
return ocfs2_xattr_set(dentry->d_inode, OCFS2_XATTR_INDEX_USER,
|
||||
name, value, size, flags);
|
||||
}
|
||||
|
||||
struct xattr_handler ocfs2_xattr_user_handler = {
|
||||
|
@ -30,6 +30,9 @@
|
||||
#include <linux/audit.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/fs_struct.h>
|
||||
#include <linux/ima.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
||||
{
|
||||
@ -855,6 +858,7 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
|
||||
if (error)
|
||||
goto cleanup_all;
|
||||
}
|
||||
ima_counts_get(f);
|
||||
|
||||
f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
|
||||
|
||||
|
29
fs/pipe.c
29
fs/pipe.c
@ -974,7 +974,7 @@ struct file *create_write_pipe(int flags)
|
||||
int err;
|
||||
struct inode *inode;
|
||||
struct file *f;
|
||||
struct dentry *dentry;
|
||||
struct path path;
|
||||
struct qstr name = { .name = "" };
|
||||
|
||||
err = -ENFILE;
|
||||
@ -983,21 +983,22 @@ struct file *create_write_pipe(int flags)
|
||||
goto err;
|
||||
|
||||
err = -ENOMEM;
|
||||
dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &name);
|
||||
if (!dentry)
|
||||
path.dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &name);
|
||||
if (!path.dentry)
|
||||
goto err_inode;
|
||||
path.mnt = mntget(pipe_mnt);
|
||||
|
||||
dentry->d_op = &pipefs_dentry_operations;
|
||||
path.dentry->d_op = &pipefs_dentry_operations;
|
||||
/*
|
||||
* We dont want to publish this dentry into global dentry hash table.
|
||||
* We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED
|
||||
* This permits a working /proc/$pid/fd/XXX on pipes
|
||||
*/
|
||||
dentry->d_flags &= ~DCACHE_UNHASHED;
|
||||
d_instantiate(dentry, inode);
|
||||
path.dentry->d_flags &= ~DCACHE_UNHASHED;
|
||||
d_instantiate(path.dentry, inode);
|
||||
|
||||
err = -ENFILE;
|
||||
f = alloc_file(pipe_mnt, dentry, FMODE_WRITE, &write_pipefifo_fops);
|
||||
f = alloc_file(&path, FMODE_WRITE, &write_pipefifo_fops);
|
||||
if (!f)
|
||||
goto err_dentry;
|
||||
f->f_mapping = inode->i_mapping;
|
||||
@ -1009,7 +1010,7 @@ struct file *create_write_pipe(int flags)
|
||||
|
||||
err_dentry:
|
||||
free_pipe_info(inode);
|
||||
dput(dentry);
|
||||
path_put(&path);
|
||||
return ERR_PTR(err);
|
||||
|
||||
err_inode:
|
||||
@ -1028,20 +1029,14 @@ void free_write_pipe(struct file *f)
|
||||
|
||||
struct file *create_read_pipe(struct file *wrf, int flags)
|
||||
{
|
||||
struct file *f = get_empty_filp();
|
||||
/* Grab pipe from the writer */
|
||||
struct file *f = alloc_file(&wrf->f_path, FMODE_READ,
|
||||
&read_pipefifo_fops);
|
||||
if (!f)
|
||||
return ERR_PTR(-ENFILE);
|
||||
|
||||
/* Grab pipe from the writer */
|
||||
f->f_path = wrf->f_path;
|
||||
path_get(&wrf->f_path);
|
||||
f->f_mapping = wrf->f_path.dentry->d_inode->i_mapping;
|
||||
|
||||
f->f_pos = 0;
|
||||
f->f_flags = O_RDONLY | (flags & O_NONBLOCK);
|
||||
f->f_op = &read_pipefifo_fops;
|
||||
f->f_mode = FMODE_READ;
|
||||
f->f_version = 0;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include <net/checksum.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/quotaops.h>
|
||||
#include <linux/security.h>
|
||||
|
||||
#define PRIVROOT_NAME ".reiserfs_priv"
|
||||
#define XAROOT_NAME "xattrs"
|
||||
@ -726,15 +727,14 @@ ssize_t
|
||||
reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer,
|
||||
size_t size)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct xattr_handler *handler;
|
||||
|
||||
handler = find_xattr_handler_prefix(inode->i_sb->s_xattr, name);
|
||||
handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name);
|
||||
|
||||
if (!handler || get_inode_sd_version(inode) == STAT_DATA_V1)
|
||||
if (!handler || get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return handler->get(inode, name, buffer, size);
|
||||
return handler->get(dentry, name, buffer, size, handler->flags);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -746,15 +746,14 @@ int
|
||||
reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct xattr_handler *handler;
|
||||
|
||||
handler = find_xattr_handler_prefix(inode->i_sb->s_xattr, name);
|
||||
handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name);
|
||||
|
||||
if (!handler || get_inode_sd_version(inode) == STAT_DATA_V1)
|
||||
if (!handler || get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return handler->set(inode, name, value, size, flags);
|
||||
return handler->set(dentry, name, value, size, flags, handler->flags);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -764,21 +763,20 @@ reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value,
|
||||
*/
|
||||
int reiserfs_removexattr(struct dentry *dentry, const char *name)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct xattr_handler *handler;
|
||||
handler = find_xattr_handler_prefix(inode->i_sb->s_xattr, name);
|
||||
handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name);
|
||||
|
||||
if (!handler || get_inode_sd_version(inode) == STAT_DATA_V1)
|
||||
if (!handler || get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return handler->set(inode, name, NULL, 0, XATTR_REPLACE);
|
||||
return handler->set(dentry, name, NULL, 0, XATTR_REPLACE, handler->flags);
|
||||
}
|
||||
|
||||
struct listxattr_buf {
|
||||
size_t size;
|
||||
size_t pos;
|
||||
char *buf;
|
||||
struct inode *inode;
|
||||
struct dentry *dentry;
|
||||
};
|
||||
|
||||
static int listxattr_filler(void *buf, const char *name, int namelen,
|
||||
@ -789,17 +787,19 @@ static int listxattr_filler(void *buf, const char *name, int namelen,
|
||||
if (name[0] != '.' ||
|
||||
(namelen != 1 && (name[1] != '.' || namelen != 2))) {
|
||||
struct xattr_handler *handler;
|
||||
handler = find_xattr_handler_prefix(b->inode->i_sb->s_xattr,
|
||||
handler = find_xattr_handler_prefix(b->dentry->d_sb->s_xattr,
|
||||
name);
|
||||
if (!handler) /* Unsupported xattr name */
|
||||
return 0;
|
||||
if (b->buf) {
|
||||
size = handler->list(b->inode, b->buf + b->pos,
|
||||
b->size, name, namelen);
|
||||
size = handler->list(b->dentry, b->buf + b->pos,
|
||||
b->size, name, namelen,
|
||||
handler->flags);
|
||||
if (size > b->size)
|
||||
return -ERANGE;
|
||||
} else {
|
||||
size = handler->list(b->inode, NULL, 0, name, namelen);
|
||||
size = handler->list(b->dentry, NULL, 0, name,
|
||||
namelen, handler->flags);
|
||||
}
|
||||
|
||||
b->pos += size;
|
||||
@ -820,7 +820,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size)
|
||||
int err = 0;
|
||||
loff_t pos = 0;
|
||||
struct listxattr_buf buf = {
|
||||
.inode = dentry->d_inode,
|
||||
.dentry = dentry,
|
||||
.buf = buffer,
|
||||
.size = buffer ? size : 0,
|
||||
};
|
||||
|
@ -15,8 +15,10 @@ static int reiserfs_set_acl(struct reiserfs_transaction_handle *th,
|
||||
struct posix_acl *acl);
|
||||
|
||||
static int
|
||||
xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
|
||||
posix_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;
|
||||
int error, error2;
|
||||
struct reiserfs_transaction_handle th;
|
||||
@ -60,15 +62,16 @@ xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
|
||||
}
|
||||
|
||||
static int
|
||||
xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
|
||||
posix_acl_get(struct dentry *dentry, const char *name, void *buffer,
|
||||
size_t size, int type)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int error;
|
||||
|
||||
if (!reiserfs_posixacl(inode->i_sb))
|
||||
if (!reiserfs_posixacl(dentry->d_sb))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
acl = reiserfs_get_acl(inode, type);
|
||||
acl = reiserfs_get_acl(dentry->d_inode, type);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
if (acl == NULL)
|
||||
@ -482,30 +485,12 @@ int reiserfs_acl_chmod(struct inode *inode)
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
posix_acl_access_get(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1)
|
||||
return -EINVAL;
|
||||
return xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
posix_acl_access_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1)
|
||||
return -EINVAL;
|
||||
return xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
|
||||
}
|
||||
|
||||
static size_t posix_acl_access_list(struct inode *inode, char *list,
|
||||
static size_t posix_acl_access_list(struct dentry *dentry, char *list,
|
||||
size_t list_size, const char *name,
|
||||
size_t name_len)
|
||||
size_t name_len, int type)
|
||||
{
|
||||
const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
|
||||
if (!reiserfs_posixacl(inode->i_sb))
|
||||
if (!reiserfs_posixacl(dentry->d_sb))
|
||||
return 0;
|
||||
if (list && size <= list_size)
|
||||
memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
|
||||
@ -514,35 +499,18 @@ static size_t posix_acl_access_list(struct inode *inode, char *list,
|
||||
|
||||
struct xattr_handler reiserfs_posix_acl_access_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_ACCESS,
|
||||
.get = posix_acl_access_get,
|
||||
.set = posix_acl_access_set,
|
||||
.flags = ACL_TYPE_ACCESS,
|
||||
.get = posix_acl_get,
|
||||
.set = posix_acl_set,
|
||||
.list = posix_acl_access_list,
|
||||
};
|
||||
|
||||
static int
|
||||
posix_acl_default_get(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1)
|
||||
return -EINVAL;
|
||||
return xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
posix_acl_default_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1)
|
||||
return -EINVAL;
|
||||
return xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
|
||||
}
|
||||
|
||||
static size_t posix_acl_default_list(struct inode *inode, char *list,
|
||||
static size_t posix_acl_default_list(struct dentry *dentry, char *list,
|
||||
size_t list_size, const char *name,
|
||||
size_t name_len)
|
||||
size_t name_len, int type)
|
||||
{
|
||||
const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
|
||||
if (!reiserfs_posixacl(inode->i_sb))
|
||||
if (!reiserfs_posixacl(dentry->d_sb))
|
||||
return 0;
|
||||
if (list && size <= list_size)
|
||||
memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
|
||||
@ -551,7 +519,8 @@ static size_t posix_acl_default_list(struct inode *inode, char *list,
|
||||
|
||||
struct xattr_handler reiserfs_posix_acl_default_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_DEFAULT,
|
||||
.get = posix_acl_default_get,
|
||||
.set = posix_acl_default_set,
|
||||
.flags = ACL_TYPE_DEFAULT,
|
||||
.get = posix_acl_get,
|
||||
.set = posix_acl_set,
|
||||
.list = posix_acl_default_list,
|
||||
};
|
||||
|
@ -8,36 +8,37 @@
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
static int
|
||||
security_get(struct inode *inode, const char *name, void *buffer, size_t size)
|
||||
security_get(struct dentry *dentry, const char *name, void *buffer, size_t size,
|
||||
int handler_flags)
|
||||
{
|
||||
if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
|
||||
return -EINVAL;
|
||||
|
||||
if (IS_PRIVATE(inode))
|
||||
if (IS_PRIVATE(dentry->d_inode))
|
||||
return -EPERM;
|
||||
|
||||
return reiserfs_xattr_get(inode, name, buffer, size);
|
||||
return reiserfs_xattr_get(dentry->d_inode, name, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
security_set(struct inode *inode, const char *name, const void *buffer,
|
||||
size_t size, int flags)
|
||||
security_set(struct dentry *dentry, const char *name, const void *buffer,
|
||||
size_t size, int flags, int handler_flags)
|
||||
{
|
||||
if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
|
||||
return -EINVAL;
|
||||
|
||||
if (IS_PRIVATE(inode))
|
||||
if (IS_PRIVATE(dentry->d_inode))
|
||||
return -EPERM;
|
||||
|
||||
return reiserfs_xattr_set(inode, name, buffer, size, flags);
|
||||
return reiserfs_xattr_set(dentry->d_inode, name, buffer, size, flags);
|
||||
}
|
||||
|
||||
static size_t security_list(struct inode *inode, char *list, size_t list_len,
|
||||
const char *name, size_t namelen)
|
||||
static size_t security_list(struct dentry *dentry, char *list, size_t list_len,
|
||||
const char *name, size_t namelen, int handler_flags)
|
||||
{
|
||||
const size_t len = namelen + 1;
|
||||
|
||||
if (IS_PRIVATE(inode))
|
||||
if (IS_PRIVATE(dentry->d_inode))
|
||||
return 0;
|
||||
|
||||
if (list && len <= list_len) {
|
||||
|
@ -8,36 +8,37 @@
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
static int
|
||||
trusted_get(struct inode *inode, const char *name, void *buffer, size_t size)
|
||||
trusted_get(struct dentry *dentry, const char *name, void *buffer, size_t size,
|
||||
int handler_flags)
|
||||
{
|
||||
if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
|
||||
return -EINVAL;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode))
|
||||
if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(dentry->d_inode))
|
||||
return -EPERM;
|
||||
|
||||
return reiserfs_xattr_get(inode, name, buffer, size);
|
||||
return reiserfs_xattr_get(dentry->d_inode, name, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
trusted_set(struct inode *inode, const char *name, const void *buffer,
|
||||
size_t size, int flags)
|
||||
trusted_set(struct dentry *dentry, const char *name, const void *buffer,
|
||||
size_t size, int flags, int handler_flags)
|
||||
{
|
||||
if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
|
||||
return -EINVAL;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode))
|
||||
if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(dentry->d_inode))
|
||||
return -EPERM;
|
||||
|
||||
return reiserfs_xattr_set(inode, name, buffer, size, flags);
|
||||
return reiserfs_xattr_set(dentry->d_inode, name, buffer, size, flags);
|
||||
}
|
||||
|
||||
static size_t trusted_list(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
static size_t trusted_list(struct dentry *dentry, char *list, size_t list_size,
|
||||
const char *name, size_t name_len, int handler_flags)
|
||||
{
|
||||
const size_t len = name_len + 1;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode))
|
||||
if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(dentry->d_inode))
|
||||
return 0;
|
||||
|
||||
if (list && len <= list_size) {
|
||||
|
@ -7,34 +7,35 @@
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
static int
|
||||
user_get(struct inode *inode, const char *name, void *buffer, size_t size)
|
||||
user_get(struct dentry *dentry, const char *name, void *buffer, size_t size,
|
||||
int handler_flags)
|
||||
{
|
||||
|
||||
if (strlen(name) < sizeof(XATTR_USER_PREFIX))
|
||||
return -EINVAL;
|
||||
if (!reiserfs_xattrs_user(inode->i_sb))
|
||||
if (!reiserfs_xattrs_user(dentry->d_sb))
|
||||
return -EOPNOTSUPP;
|
||||
return reiserfs_xattr_get(inode, name, buffer, size);
|
||||
return reiserfs_xattr_get(dentry->d_inode, name, buffer, size);
|
||||
}
|
||||
|
||||
static int
|
||||
user_set(struct inode *inode, const char *name, const void *buffer,
|
||||
size_t size, int flags)
|
||||
user_set(struct dentry *dentry, const char *name, const void *buffer,
|
||||
size_t size, int flags, int handler_flags)
|
||||
{
|
||||
if (strlen(name) < sizeof(XATTR_USER_PREFIX))
|
||||
return -EINVAL;
|
||||
|
||||
if (!reiserfs_xattrs_user(inode->i_sb))
|
||||
if (!reiserfs_xattrs_user(dentry->d_sb))
|
||||
return -EOPNOTSUPP;
|
||||
return reiserfs_xattr_set(inode, name, buffer, size, flags);
|
||||
return reiserfs_xattr_set(dentry->d_inode, name, buffer, size, flags);
|
||||
}
|
||||
|
||||
static size_t user_list(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
static size_t user_list(struct dentry *dentry, char *list, size_t list_size,
|
||||
const char *name, size_t name_len, int handler_flags)
|
||||
{
|
||||
const size_t len = name_len + 1;
|
||||
|
||||
if (!reiserfs_xattrs_user(inode->i_sb))
|
||||
if (!reiserfs_xattrs_user(dentry->d_sb))
|
||||
return 0;
|
||||
if (list && len <= list_size) {
|
||||
memcpy(list, name, name_len);
|
||||
|
28
fs/xattr.c
28
fs/xattr.c
@ -615,12 +615,11 @@ ssize_t
|
||||
generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size)
|
||||
{
|
||||
struct xattr_handler *handler;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
|
||||
handler = xattr_resolve_name(inode->i_sb->s_xattr, &name);
|
||||
handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
|
||||
if (!handler)
|
||||
return -EOPNOTSUPP;
|
||||
return handler->get(inode, name, buffer, size);
|
||||
return handler->get(dentry, name, buffer, size, handler->flags);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -630,18 +629,20 @@ generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t s
|
||||
ssize_t
|
||||
generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct xattr_handler *handler, **handlers = inode->i_sb->s_xattr;
|
||||
struct xattr_handler *handler, **handlers = dentry->d_sb->s_xattr;
|
||||
unsigned int size = 0;
|
||||
|
||||
if (!buffer) {
|
||||
for_each_xattr_handler(handlers, handler)
|
||||
size += handler->list(inode, NULL, 0, NULL, 0);
|
||||
for_each_xattr_handler(handlers, handler) {
|
||||
size += handler->list(dentry, NULL, 0, NULL, 0,
|
||||
handler->flags);
|
||||
}
|
||||
} else {
|
||||
char *buf = buffer;
|
||||
|
||||
for_each_xattr_handler(handlers, handler) {
|
||||
size = handler->list(inode, buf, buffer_size, NULL, 0);
|
||||
size = handler->list(dentry, buf, buffer_size,
|
||||
NULL, 0, handler->flags);
|
||||
if (size > buffer_size)
|
||||
return -ERANGE;
|
||||
buf += size;
|
||||
@ -659,14 +660,13 @@ int
|
||||
generic_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags)
|
||||
{
|
||||
struct xattr_handler *handler;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
|
||||
if (size == 0)
|
||||
value = ""; /* empty EA, do not remove */
|
||||
handler = xattr_resolve_name(inode->i_sb->s_xattr, &name);
|
||||
handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
|
||||
if (!handler)
|
||||
return -EOPNOTSUPP;
|
||||
return handler->set(inode, name, value, size, flags);
|
||||
return handler->set(dentry, name, value, size, 0, handler->flags);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -677,12 +677,12 @@ int
|
||||
generic_removexattr(struct dentry *dentry, const char *name)
|
||||
{
|
||||
struct xattr_handler *handler;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
|
||||
handler = xattr_resolve_name(inode->i_sb->s_xattr, &name);
|
||||
handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
|
||||
if (!handler)
|
||||
return -EOPNOTSUPP;
|
||||
return handler->set(inode, name, NULL, 0, XATTR_REPLACE);
|
||||
return handler->set(dentry, name, NULL, 0,
|
||||
XATTR_REPLACE, handler->flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(generic_getxattr);
|
||||
|
@ -354,37 +354,14 @@ xfs_acl_chmod(struct inode *inode)
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* System xattr handlers.
|
||||
*
|
||||
* Currently Posix ACLs are the only system namespace extended attribute
|
||||
* handlers supported by XFS, so we just implement the handlers here.
|
||||
* If we ever support other system extended attributes this will need
|
||||
* some refactoring.
|
||||
*/
|
||||
|
||||
static int
|
||||
xfs_decode_acl(const char *name)
|
||||
{
|
||||
if (strcmp(name, "posix_acl_access") == 0)
|
||||
return ACL_TYPE_ACCESS;
|
||||
else if (strcmp(name, "posix_acl_default") == 0)
|
||||
return ACL_TYPE_DEFAULT;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
xfs_xattr_system_get(struct inode *inode, const char *name,
|
||||
void *value, size_t size)
|
||||
xfs_xattr_acl_get(struct dentry *dentry, const char *name,
|
||||
void *value, size_t size, int type)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int type, error;
|
||||
int error;
|
||||
|
||||
type = xfs_decode_acl(name);
|
||||
if (type < 0)
|
||||
return type;
|
||||
|
||||
acl = xfs_get_acl(inode, type);
|
||||
acl = xfs_get_acl(dentry->d_inode, type);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
if (acl == NULL)
|
||||
@ -397,15 +374,13 @@ xfs_xattr_system_get(struct inode *inode, const char *name,
|
||||
}
|
||||
|
||||
static int
|
||||
xfs_xattr_system_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
xfs_xattr_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 = 0, type;
|
||||
int error = 0;
|
||||
|
||||
type = xfs_decode_acl(name);
|
||||
if (type < 0)
|
||||
return type;
|
||||
if (flags & XATTR_CREATE)
|
||||
return -EINVAL;
|
||||
if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
|
||||
@ -462,8 +437,16 @@ xfs_xattr_system_set(struct inode *inode, const char *name,
|
||||
return error;
|
||||
}
|
||||
|
||||
struct xattr_handler xfs_xattr_system_handler = {
|
||||
.prefix = XATTR_SYSTEM_PREFIX,
|
||||
.get = xfs_xattr_system_get,
|
||||
.set = xfs_xattr_system_set,
|
||||
struct xattr_handler xfs_xattr_acl_access_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_ACCESS,
|
||||
.flags = ACL_TYPE_ACCESS,
|
||||
.get = xfs_xattr_acl_get,
|
||||
.set = xfs_xattr_acl_set,
|
||||
};
|
||||
|
||||
struct xattr_handler xfs_xattr_acl_default_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_DEFAULT,
|
||||
.flags = ACL_TYPE_DEFAULT,
|
||||
.get = xfs_xattr_acl_get,
|
||||
.set = xfs_xattr_acl_set,
|
||||
};
|
||||
|
@ -30,10 +30,10 @@
|
||||
|
||||
|
||||
static int
|
||||
__xfs_xattr_get(struct inode *inode, const char *name,
|
||||
xfs_xattr_get(struct dentry *dentry, const char *name,
|
||||
void *value, size_t size, int xflags)
|
||||
{
|
||||
struct xfs_inode *ip = XFS_I(inode);
|
||||
struct xfs_inode *ip = XFS_I(dentry->d_inode);
|
||||
int error, asize = size;
|
||||
|
||||
if (strcmp(name, "") == 0)
|
||||
@ -52,10 +52,10 @@ __xfs_xattr_get(struct inode *inode, const char *name,
|
||||
}
|
||||
|
||||
static int
|
||||
__xfs_xattr_set(struct inode *inode, const char *name, const void *value,
|
||||
xfs_xattr_set(struct dentry *dentry, const char *name, const void *value,
|
||||
size_t size, int flags, int xflags)
|
||||
{
|
||||
struct xfs_inode *ip = XFS_I(inode);
|
||||
struct xfs_inode *ip = XFS_I(dentry->d_inode);
|
||||
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
@ -71,75 +71,34 @@ __xfs_xattr_set(struct inode *inode, const char *name, const void *value,
|
||||
return -xfs_attr_set(ip, name, (void *)value, size, xflags);
|
||||
}
|
||||
|
||||
static int
|
||||
xfs_xattr_user_get(struct inode *inode, const char *name,
|
||||
void *value, size_t size)
|
||||
{
|
||||
return __xfs_xattr_get(inode, name, value, size, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
xfs_xattr_user_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
return __xfs_xattr_set(inode, name, value, size, flags, 0);
|
||||
}
|
||||
|
||||
static struct xattr_handler xfs_xattr_user_handler = {
|
||||
.prefix = XATTR_USER_PREFIX,
|
||||
.get = xfs_xattr_user_get,
|
||||
.set = xfs_xattr_user_set,
|
||||
.flags = 0, /* no flags implies user namespace */
|
||||
.get = xfs_xattr_get,
|
||||
.set = xfs_xattr_set,
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
xfs_xattr_trusted_get(struct inode *inode, const char *name,
|
||||
void *value, size_t size)
|
||||
{
|
||||
return __xfs_xattr_get(inode, name, value, size, ATTR_ROOT);
|
||||
}
|
||||
|
||||
static int
|
||||
xfs_xattr_trusted_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
return __xfs_xattr_set(inode, name, value, size, flags, ATTR_ROOT);
|
||||
}
|
||||
|
||||
static struct xattr_handler xfs_xattr_trusted_handler = {
|
||||
.prefix = XATTR_TRUSTED_PREFIX,
|
||||
.get = xfs_xattr_trusted_get,
|
||||
.set = xfs_xattr_trusted_set,
|
||||
.flags = ATTR_ROOT,
|
||||
.get = xfs_xattr_get,
|
||||
.set = xfs_xattr_set,
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
xfs_xattr_secure_get(struct inode *inode, const char *name,
|
||||
void *value, size_t size)
|
||||
{
|
||||
return __xfs_xattr_get(inode, name, value, size, ATTR_SECURE);
|
||||
}
|
||||
|
||||
static int
|
||||
xfs_xattr_secure_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
return __xfs_xattr_set(inode, name, value, size, flags, ATTR_SECURE);
|
||||
}
|
||||
|
||||
static struct xattr_handler xfs_xattr_security_handler = {
|
||||
.prefix = XATTR_SECURITY_PREFIX,
|
||||
.get = xfs_xattr_secure_get,
|
||||
.set = xfs_xattr_secure_set,
|
||||
.flags = ATTR_SECURE,
|
||||
.get = xfs_xattr_get,
|
||||
.set = xfs_xattr_set,
|
||||
};
|
||||
|
||||
|
||||
struct xattr_handler *xfs_xattr_handlers[] = {
|
||||
&xfs_xattr_user_handler,
|
||||
&xfs_xattr_trusted_handler,
|
||||
&xfs_xattr_security_handler,
|
||||
#ifdef CONFIG_XFS_POSIX_ACL
|
||||
&xfs_xattr_system_handler,
|
||||
&xfs_xattr_acl_access_handler,
|
||||
&xfs_xattr_acl_default_handler,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
@ -49,7 +49,8 @@ extern int xfs_acl_chmod(struct inode *inode);
|
||||
extern int posix_acl_access_exists(struct inode *inode);
|
||||
extern int posix_acl_default_exists(struct inode *inode);
|
||||
|
||||
extern struct xattr_handler xfs_xattr_system_handler;
|
||||
extern struct xattr_handler xfs_xattr_acl_access_handler;
|
||||
extern struct xattr_handler xfs_xattr_acl_default_handler;
|
||||
#else
|
||||
# define xfs_check_acl NULL
|
||||
# define xfs_get_acl(inode, type) NULL
|
||||
|
@ -18,11 +18,9 @@ extern void drop_file_write_access(struct file *file);
|
||||
struct file_operations;
|
||||
struct vfsmount;
|
||||
struct dentry;
|
||||
extern int init_file(struct file *, struct vfsmount *mnt,
|
||||
struct dentry *dentry, fmode_t mode,
|
||||
const struct file_operations *fop);
|
||||
extern struct file *alloc_file(struct vfsmount *, struct dentry *dentry,
|
||||
fmode_t mode, const struct file_operations *fop);
|
||||
struct path;
|
||||
extern struct file *alloc_file(struct path *, fmode_t mode,
|
||||
const struct file_operations *fop);
|
||||
|
||||
static inline void fput_light(struct file *file, int fput_needed)
|
||||
{
|
||||
|
@ -2189,7 +2189,6 @@ static inline void insert_inode_hash(struct inode *inode) {
|
||||
__insert_inode_hash(inode, inode->i_ino);
|
||||
}
|
||||
|
||||
extern struct file * get_empty_filp(void);
|
||||
extern void file_move(struct file *f, struct list_head *list);
|
||||
extern void file_kill(struct file *f);
|
||||
#ifdef CONFIG_BLOCK
|
||||
|
@ -1,36 +1,15 @@
|
||||
/*
|
||||
* include/linux/generic_acl.h
|
||||
*
|
||||
* (C) 2005 Andreas Gruenbacher <agruen@suse.de>
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
#ifndef LINUX_GENERIC_ACL_H
|
||||
#define LINUX_GENERIC_ACL_H
|
||||
|
||||
#ifndef GENERIC_ACL_H
|
||||
#define GENERIC_ACL_H
|
||||
#include <linux/xattr.h>
|
||||
|
||||
#include <linux/posix_acl.h>
|
||||
#include <linux/posix_acl_xattr.h>
|
||||
struct inode;
|
||||
|
||||
/**
|
||||
* struct generic_acl_operations - filesystem operations
|
||||
*
|
||||
* Filesystems must make these operations available to the generic
|
||||
* operations.
|
||||
*/
|
||||
struct generic_acl_operations {
|
||||
struct posix_acl *(*getacl)(struct inode *, int);
|
||||
void (*setacl)(struct inode *, int, struct posix_acl *);
|
||||
};
|
||||
extern struct xattr_handler generic_acl_access_handler;
|
||||
extern struct xattr_handler generic_acl_default_handler;
|
||||
|
||||
size_t generic_acl_list(struct inode *, struct generic_acl_operations *, int,
|
||||
char *, size_t);
|
||||
int generic_acl_get(struct inode *, struct generic_acl_operations *, int,
|
||||
void *, size_t);
|
||||
int generic_acl_set(struct inode *, struct generic_acl_operations *, int,
|
||||
const void *, size_t);
|
||||
int generic_acl_init(struct inode *, struct inode *,
|
||||
struct generic_acl_operations *);
|
||||
int generic_acl_chmod(struct inode *, struct generic_acl_operations *);
|
||||
int generic_acl_init(struct inode *, struct inode *);
|
||||
int generic_acl_chmod(struct inode *);
|
||||
int generic_check_acl(struct inode *inode, int mask);
|
||||
|
||||
#endif
|
||||
#endif /* LINUX_GENERIC_ACL_H */
|
||||
|
@ -13,18 +13,14 @@
|
||||
#include <linux/fs.h>
|
||||
struct linux_binprm;
|
||||
|
||||
#define IMA_COUNT_UPDATE 1
|
||||
#define IMA_COUNT_LEAVE 0
|
||||
|
||||
#ifdef CONFIG_IMA
|
||||
extern int ima_bprm_check(struct linux_binprm *bprm);
|
||||
extern int ima_inode_alloc(struct inode *inode);
|
||||
extern void ima_inode_free(struct inode *inode);
|
||||
extern int ima_path_check(struct path *path, int mask, int update_counts);
|
||||
extern int ima_path_check(struct path *path, int mask);
|
||||
extern void ima_file_free(struct file *file);
|
||||
extern int ima_file_mmap(struct file *file, unsigned long prot);
|
||||
extern void ima_counts_get(struct file *file);
|
||||
extern void ima_counts_put(struct path *path, int mask);
|
||||
|
||||
#else
|
||||
static inline int ima_bprm_check(struct linux_binprm *bprm)
|
||||
@ -42,7 +38,7 @@ static inline void ima_inode_free(struct inode *inode)
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int ima_path_check(struct path *path, int mask, int update_counts)
|
||||
static inline int ima_path_check(struct path *path, int mask)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -62,9 +58,5 @@ static inline void ima_counts_get(struct file *file)
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void ima_counts_put(struct path *path, int mask)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_IMA_H */
|
||||
#endif /* _LINUX_IMA_H */
|
||||
|
@ -23,7 +23,6 @@ struct proc_mounts {
|
||||
|
||||
struct fs_struct;
|
||||
|
||||
extern struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt);
|
||||
extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *,
|
||||
struct fs_struct *);
|
||||
extern void put_mnt_ns(struct mnt_namespace *ns);
|
||||
|
@ -41,20 +41,4 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
|
||||
extern int init_tmpfs(void);
|
||||
extern int shmem_fill_super(struct super_block *sb, void *data, int silent);
|
||||
|
||||
#ifdef CONFIG_TMPFS_POSIX_ACL
|
||||
int shmem_check_acl(struct inode *, int);
|
||||
int shmem_acl_init(struct inode *, struct inode *);
|
||||
|
||||
extern struct xattr_handler shmem_xattr_acl_access_handler;
|
||||
extern struct xattr_handler shmem_xattr_acl_default_handler;
|
||||
|
||||
extern struct generic_acl_operations shmem_acl_ops;
|
||||
|
||||
#else
|
||||
static inline int shmem_acl_init(struct inode *inode, struct inode *dir)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_TMPFS_POSIX_ACL */
|
||||
|
||||
#endif
|
||||
|
@ -38,12 +38,13 @@ struct dentry;
|
||||
|
||||
struct xattr_handler {
|
||||
char *prefix;
|
||||
size_t (*list)(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len);
|
||||
int (*get)(struct inode *inode, const char *name, void *buffer,
|
||||
size_t size);
|
||||
int (*set)(struct inode *inode, const char *name, const void *buffer,
|
||||
size_t size, int flags);
|
||||
int flags; /* fs private flags passed back to the handlers */
|
||||
size_t (*list)(struct dentry *dentry, char *list, size_t list_size,
|
||||
const char *name, size_t name_len, int handler_flags);
|
||||
int (*get)(struct dentry *dentry, const char *name, void *buffer,
|
||||
size_t size, int handler_flags);
|
||||
int (*set)(struct dentry *dentry, const char *name, const void *buffer,
|
||||
size_t size, int flags, int handler_flags);
|
||||
};
|
||||
|
||||
ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
|
||||
|
@ -32,7 +32,6 @@
|
||||
#include <linux/nsproxy.h>
|
||||
#include <linux/pid.h>
|
||||
#include <linux/ipc_namespace.h>
|
||||
#include <linux/ima.h>
|
||||
|
||||
#include <net/sock.h>
|
||||
#include "util.h"
|
||||
@ -734,7 +733,6 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode,
|
||||
error = PTR_ERR(filp);
|
||||
goto out_putfd;
|
||||
}
|
||||
ima_counts_get(filp);
|
||||
|
||||
fd_install(fd, filp);
|
||||
goto out_upsem;
|
||||
|
12
ipc/shm.c
12
ipc/shm.c
@ -39,7 +39,6 @@
|
||||
#include <linux/nsproxy.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/ipc_namespace.h>
|
||||
#include <linux/ima.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
@ -879,8 +878,8 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
|
||||
if (err)
|
||||
goto out_unlock;
|
||||
|
||||
path.dentry = dget(shp->shm_file->f_path.dentry);
|
||||
path.mnt = shp->shm_file->f_path.mnt;
|
||||
path = shp->shm_file->f_path;
|
||||
path_get(&path);
|
||||
shp->shm_nattch++;
|
||||
size = i_size_read(path.dentry->d_inode);
|
||||
shm_unlock(shp);
|
||||
@ -890,13 +889,12 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
|
||||
if (!sfd)
|
||||
goto out_put_dentry;
|
||||
|
||||
file = alloc_file(path.mnt, path.dentry, f_mode,
|
||||
is_file_hugepages(shp->shm_file) ?
|
||||
file = alloc_file(&path, f_mode,
|
||||
is_file_hugepages(shp->shm_file) ?
|
||||
&shm_file_operations_huge :
|
||||
&shm_file_operations);
|
||||
if (!file)
|
||||
goto out_free;
|
||||
ima_counts_get(file);
|
||||
|
||||
file->private_data = sfd;
|
||||
file->f_mapping = shp->shm_file->f_mapping;
|
||||
@ -951,7 +949,7 @@ out_unlock:
|
||||
out_free:
|
||||
kfree(sfd);
|
||||
out_put_dentry:
|
||||
dput(path.dentry);
|
||||
path_put(&path);
|
||||
goto out_nattch;
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,6 @@ obj-$(CONFIG_HUGETLBFS) += hugetlb.o
|
||||
obj-$(CONFIG_NUMA) += mempolicy.o
|
||||
obj-$(CONFIG_SPARSEMEM) += sparse.o
|
||||
obj-$(CONFIG_SPARSEMEM_VMEMMAP) += sparse-vmemmap.o
|
||||
obj-$(CONFIG_TMPFS_POSIX_ACL) += shmem_acl.o
|
||||
obj-$(CONFIG_SLOB) += slob.o
|
||||
obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o
|
||||
obj-$(CONFIG_KSM) += ksm.o
|
||||
|
15
mm/filemap.c
15
mm/filemap.c
@ -2240,7 +2240,6 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
|
||||
size_t count, ssize_t written)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct address_space *mapping = file->f_mapping;
|
||||
ssize_t status;
|
||||
struct iov_iter i;
|
||||
|
||||
@ -2252,15 +2251,6 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
|
||||
*ppos = pos + status;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we get here for O_DIRECT writes then we must have fallen through
|
||||
* to buffered writes (block instantiation inside i_size). So we sync
|
||||
* the file data here, to try to honour O_DIRECT expectations.
|
||||
*/
|
||||
if (unlikely(file->f_flags & O_DIRECT) && written)
|
||||
status = filemap_write_and_wait_range(mapping,
|
||||
pos, pos + written - 1);
|
||||
|
||||
return written ? written : status;
|
||||
}
|
||||
EXPORT_SYMBOL(generic_file_buffered_write);
|
||||
@ -2359,10 +2349,7 @@ ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
||||
* semantics.
|
||||
*/
|
||||
endbyte = pos + written_buffered - written - 1;
|
||||
err = do_sync_mapping_range(file->f_mapping, pos, endbyte,
|
||||
SYNC_FILE_RANGE_WAIT_BEFORE|
|
||||
SYNC_FILE_RANGE_WRITE|
|
||||
SYNC_FILE_RANGE_WAIT_AFTER);
|
||||
err = filemap_write_and_wait_range(file->f_mapping, pos, endbyte);
|
||||
if (err == 0) {
|
||||
written = written_buffered;
|
||||
invalidate_mapping_pages(mapping,
|
||||
|
71
mm/shmem.c
71
mm/shmem.c
@ -29,7 +29,6 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/swap.h>
|
||||
#include <linux/ima.h>
|
||||
|
||||
static struct vfsmount *shm_mnt;
|
||||
|
||||
@ -42,6 +41,7 @@ static struct vfsmount *shm_mnt;
|
||||
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/exportfs.h>
|
||||
#include <linux/posix_acl.h>
|
||||
#include <linux/generic_acl.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/string.h>
|
||||
@ -810,7 +810,7 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
|
||||
error = inode_setattr(inode, attr);
|
||||
#ifdef CONFIG_TMPFS_POSIX_ACL
|
||||
if (!error && (attr->ia_valid & ATTR_MODE))
|
||||
error = generic_acl_chmod(inode, &shmem_acl_ops);
|
||||
error = generic_acl_chmod(inode);
|
||||
#endif
|
||||
if (page)
|
||||
page_cache_release(page);
|
||||
@ -1824,11 +1824,13 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
|
||||
return error;
|
||||
}
|
||||
}
|
||||
error = shmem_acl_init(inode, dir);
|
||||
#ifdef CONFIG_TMPFS_POSIX_ACL
|
||||
error = generic_acl_init(inode, dir);
|
||||
if (error) {
|
||||
iput(inode);
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
if (dir->i_mode & S_ISGID) {
|
||||
inode->i_gid = dir->i_gid;
|
||||
if (S_ISDIR(mode))
|
||||
@ -2043,27 +2045,28 @@ static const struct inode_operations shmem_symlink_inode_operations = {
|
||||
* filesystem level, though.
|
||||
*/
|
||||
|
||||
static size_t shmem_xattr_security_list(struct inode *inode, char *list,
|
||||
static size_t shmem_xattr_security_list(struct dentry *dentry, char *list,
|
||||
size_t list_len, const char *name,
|
||||
size_t name_len)
|
||||
size_t name_len, int handler_flags)
|
||||
{
|
||||
return security_inode_listsecurity(inode, list, list_len);
|
||||
return security_inode_listsecurity(dentry->d_inode, list, list_len);
|
||||
}
|
||||
|
||||
static int shmem_xattr_security_get(struct inode *inode, const char *name,
|
||||
void *buffer, size_t size)
|
||||
static int shmem_xattr_security_get(struct dentry *dentry, const char *name,
|
||||
void *buffer, size_t size, int handler_flags)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
return xattr_getsecurity(inode, name, buffer, size);
|
||||
return xattr_getsecurity(dentry->d_inode, name, buffer, size);
|
||||
}
|
||||
|
||||
static int shmem_xattr_security_set(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
static int shmem_xattr_security_set(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags, int handler_flags)
|
||||
{
|
||||
if (strcmp(name, "") == 0)
|
||||
return -EINVAL;
|
||||
return security_inode_setsecurity(inode, name, value, size, flags);
|
||||
return security_inode_setsecurity(dentry->d_inode, name, value,
|
||||
size, flags);
|
||||
}
|
||||
|
||||
static struct xattr_handler shmem_xattr_security_handler = {
|
||||
@ -2074,8 +2077,8 @@ static struct xattr_handler shmem_xattr_security_handler = {
|
||||
};
|
||||
|
||||
static struct xattr_handler *shmem_xattr_handlers[] = {
|
||||
&shmem_xattr_acl_access_handler,
|
||||
&shmem_xattr_acl_default_handler,
|
||||
&generic_acl_access_handler,
|
||||
&generic_acl_default_handler,
|
||||
&shmem_xattr_security_handler,
|
||||
NULL
|
||||
};
|
||||
@ -2454,7 +2457,7 @@ static const struct inode_operations shmem_inode_operations = {
|
||||
.getxattr = generic_getxattr,
|
||||
.listxattr = generic_listxattr,
|
||||
.removexattr = generic_removexattr,
|
||||
.check_acl = shmem_check_acl,
|
||||
.check_acl = generic_check_acl,
|
||||
#endif
|
||||
|
||||
};
|
||||
@ -2477,7 +2480,7 @@ static const struct inode_operations shmem_dir_inode_operations = {
|
||||
.getxattr = generic_getxattr,
|
||||
.listxattr = generic_listxattr,
|
||||
.removexattr = generic_removexattr,
|
||||
.check_acl = shmem_check_acl,
|
||||
.check_acl = generic_check_acl,
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -2488,7 +2491,7 @@ static const struct inode_operations shmem_special_inode_operations = {
|
||||
.getxattr = generic_getxattr,
|
||||
.listxattr = generic_listxattr,
|
||||
.removexattr = generic_removexattr,
|
||||
.check_acl = shmem_check_acl,
|
||||
.check_acl = generic_check_acl,
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -2626,7 +2629,8 @@ struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags
|
||||
int error;
|
||||
struct file *file;
|
||||
struct inode *inode;
|
||||
struct dentry *dentry, *root;
|
||||
struct path path;
|
||||
struct dentry *root;
|
||||
struct qstr this;
|
||||
|
||||
if (IS_ERR(shm_mnt))
|
||||
@ -2643,38 +2647,35 @@ struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags
|
||||
this.len = strlen(name);
|
||||
this.hash = 0; /* will go */
|
||||
root = shm_mnt->mnt_root;
|
||||
dentry = d_alloc(root, &this);
|
||||
if (!dentry)
|
||||
path.dentry = d_alloc(root, &this);
|
||||
if (!path.dentry)
|
||||
goto put_memory;
|
||||
|
||||
error = -ENFILE;
|
||||
file = get_empty_filp();
|
||||
if (!file)
|
||||
goto put_dentry;
|
||||
path.mnt = mntget(shm_mnt);
|
||||
|
||||
error = -ENOSPC;
|
||||
inode = shmem_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0, flags);
|
||||
if (!inode)
|
||||
goto close_file;
|
||||
goto put_dentry;
|
||||
|
||||
d_instantiate(dentry, inode);
|
||||
d_instantiate(path.dentry, inode);
|
||||
inode->i_size = size;
|
||||
inode->i_nlink = 0; /* It is unlinked */
|
||||
init_file(file, shm_mnt, dentry, FMODE_WRITE | FMODE_READ,
|
||||
&shmem_file_operations);
|
||||
|
||||
#ifndef CONFIG_MMU
|
||||
error = ramfs_nommu_expand_for_mapping(inode, size);
|
||||
if (error)
|
||||
goto close_file;
|
||||
goto put_dentry;
|
||||
#endif
|
||||
ima_counts_get(file);
|
||||
|
||||
error = -ENFILE;
|
||||
file = alloc_file(&path, FMODE_WRITE | FMODE_READ,
|
||||
&shmem_file_operations);
|
||||
if (!file)
|
||||
goto put_dentry;
|
||||
|
||||
return file;
|
||||
|
||||
close_file:
|
||||
put_filp(file);
|
||||
put_dentry:
|
||||
dput(dentry);
|
||||
path_put(&path);
|
||||
put_memory:
|
||||
shmem_unacct_size(flags, size);
|
||||
return ERR_PTR(error);
|
||||
|
171
mm/shmem_acl.c
171
mm/shmem_acl.c
@ -1,171 +0,0 @@
|
||||
/*
|
||||
* mm/shmem_acl.c
|
||||
*
|
||||
* (C) 2005 Andreas Gruenbacher <agruen@suse.de>
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/shmem_fs.h>
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/generic_acl.h>
|
||||
|
||||
/**
|
||||
* shmem_get_acl - generic_acl_operations->getacl() operation
|
||||
*/
|
||||
static struct posix_acl *
|
||||
shmem_get_acl(struct inode *inode, int type)
|
||||
{
|
||||
struct posix_acl *acl = NULL;
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
switch(type) {
|
||||
case ACL_TYPE_ACCESS:
|
||||
acl = posix_acl_dup(inode->i_acl);
|
||||
break;
|
||||
|
||||
case ACL_TYPE_DEFAULT:
|
||||
acl = posix_acl_dup(inode->i_default_acl);
|
||||
break;
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
return acl;
|
||||
}
|
||||
|
||||
/**
|
||||
* shmem_set_acl - generic_acl_operations->setacl() operation
|
||||
*/
|
||||
static void
|
||||
shmem_set_acl(struct inode *inode, int type, struct posix_acl *acl)
|
||||
{
|
||||
struct posix_acl *free = NULL;
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
switch(type) {
|
||||
case ACL_TYPE_ACCESS:
|
||||
free = inode->i_acl;
|
||||
inode->i_acl = posix_acl_dup(acl);
|
||||
break;
|
||||
|
||||
case ACL_TYPE_DEFAULT:
|
||||
free = inode->i_default_acl;
|
||||
inode->i_default_acl = posix_acl_dup(acl);
|
||||
break;
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
posix_acl_release(free);
|
||||
}
|
||||
|
||||
struct generic_acl_operations shmem_acl_ops = {
|
||||
.getacl = shmem_get_acl,
|
||||
.setacl = shmem_set_acl,
|
||||
};
|
||||
|
||||
/**
|
||||
* shmem_list_acl_access, shmem_get_acl_access, shmem_set_acl_access,
|
||||
* shmem_xattr_acl_access_handler - plumbing code to implement the
|
||||
* system.posix_acl_access xattr using the generic acl functions.
|
||||
*/
|
||||
|
||||
static size_t
|
||||
shmem_list_acl_access(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
{
|
||||
return generic_acl_list(inode, &shmem_acl_ops, ACL_TYPE_ACCESS,
|
||||
list, list_size);
|
||||
}
|
||||
|
||||
static int
|
||||
shmem_get_acl_access(struct inode *inode, const char *name, void *buffer,
|
||||
size_t size)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return generic_acl_get(inode, &shmem_acl_ops, ACL_TYPE_ACCESS, buffer,
|
||||
size);
|
||||
}
|
||||
|
||||
static int
|
||||
shmem_set_acl_access(struct inode *inode, const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return generic_acl_set(inode, &shmem_acl_ops, ACL_TYPE_ACCESS, value,
|
||||
size);
|
||||
}
|
||||
|
||||
struct xattr_handler shmem_xattr_acl_access_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_ACCESS,
|
||||
.list = shmem_list_acl_access,
|
||||
.get = shmem_get_acl_access,
|
||||
.set = shmem_set_acl_access,
|
||||
};
|
||||
|
||||
/**
|
||||
* shmem_list_acl_default, shmem_get_acl_default, shmem_set_acl_default,
|
||||
* shmem_xattr_acl_default_handler - plumbing code to implement the
|
||||
* system.posix_acl_default xattr using the generic acl functions.
|
||||
*/
|
||||
|
||||
static size_t
|
||||
shmem_list_acl_default(struct inode *inode, char *list, size_t list_size,
|
||||
const char *name, size_t name_len)
|
||||
{
|
||||
return generic_acl_list(inode, &shmem_acl_ops, ACL_TYPE_DEFAULT,
|
||||
list, list_size);
|
||||
}
|
||||
|
||||
static int
|
||||
shmem_get_acl_default(struct inode *inode, const char *name, void *buffer,
|
||||
size_t size)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return generic_acl_get(inode, &shmem_acl_ops, ACL_TYPE_DEFAULT, buffer,
|
||||
size);
|
||||
}
|
||||
|
||||
static int
|
||||
shmem_set_acl_default(struct inode *inode, const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
{
|
||||
if (strcmp(name, "") != 0)
|
||||
return -EINVAL;
|
||||
return generic_acl_set(inode, &shmem_acl_ops, ACL_TYPE_DEFAULT, value,
|
||||
size);
|
||||
}
|
||||
|
||||
struct xattr_handler shmem_xattr_acl_default_handler = {
|
||||
.prefix = POSIX_ACL_XATTR_DEFAULT,
|
||||
.list = shmem_list_acl_default,
|
||||
.get = shmem_get_acl_default,
|
||||
.set = shmem_set_acl_default,
|
||||
};
|
||||
|
||||
/**
|
||||
* shmem_acl_init - Inizialize the acl(s) of a new inode
|
||||
*/
|
||||
int
|
||||
shmem_acl_init(struct inode *inode, struct inode *dir)
|
||||
{
|
||||
return generic_acl_init(inode, dir, &shmem_acl_ops);
|
||||
}
|
||||
|
||||
/**
|
||||
* shmem_check_acl - check_acl() callback for generic_permission()
|
||||
*/
|
||||
int
|
||||
shmem_check_acl(struct inode *inode, int mask)
|
||||
{
|
||||
struct posix_acl *acl = shmem_get_acl(inode, ACL_TYPE_ACCESS);
|
||||
|
||||
if (acl) {
|
||||
int error = posix_acl_permission(inode, acl, mask);
|
||||
posix_acl_release(acl);
|
||||
return error;
|
||||
}
|
||||
return -EAGAIN;
|
||||
}
|
@ -42,6 +42,8 @@
|
||||
#include <net/9p/client.h>
|
||||
#include <net/9p/transport.h>
|
||||
|
||||
#include <linux/syscalls.h> /* killme */
|
||||
|
||||
#define P9_PORT 564
|
||||
#define MAX_SOCK_BUF (64*1024)
|
||||
#define MAXPOLLWADDR 2
|
||||
@ -788,24 +790,41 @@ static int p9_fd_open(struct p9_client *client, int rfd, int wfd)
|
||||
|
||||
static int p9_socket_open(struct p9_client *client, struct socket *csocket)
|
||||
{
|
||||
int fd, ret;
|
||||
struct p9_trans_fd *p;
|
||||
int ret, fd;
|
||||
|
||||
p = kmalloc(sizeof(struct p9_trans_fd), GFP_KERNEL);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
csocket->sk->sk_allocation = GFP_NOIO;
|
||||
fd = sock_map_fd(csocket, 0);
|
||||
if (fd < 0) {
|
||||
P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n");
|
||||
sock_release(csocket);
|
||||
kfree(p);
|
||||
return fd;
|
||||
}
|
||||
|
||||
ret = p9_fd_open(client, fd, fd);
|
||||
if (ret < 0) {
|
||||
P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to open fd\n");
|
||||
get_file(csocket->file);
|
||||
get_file(csocket->file);
|
||||
p->wr = p->rd = csocket->file;
|
||||
client->trans = p;
|
||||
client->status = Connected;
|
||||
|
||||
sys_close(fd); /* still racy */
|
||||
|
||||
p->rd->f_flags |= O_NONBLOCK;
|
||||
|
||||
p->conn = p9_conn_create(client);
|
||||
if (IS_ERR(p->conn)) {
|
||||
ret = PTR_ERR(p->conn);
|
||||
p->conn = NULL;
|
||||
kfree(p);
|
||||
sockfd_put(csocket);
|
||||
sockfd_put(csocket);
|
||||
return ret;
|
||||
}
|
||||
|
||||
((struct p9_trans_fd *)client->trans)->rd->f_flags |= O_NONBLOCK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -883,7 +902,6 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
|
||||
struct socket *csocket;
|
||||
struct sockaddr_in sin_server;
|
||||
struct p9_fd_opts opts;
|
||||
struct p9_trans_fd *p = NULL; /* this gets allocated in p9_fd_open */
|
||||
|
||||
err = parse_opts(args, &opts);
|
||||
if (err < 0)
|
||||
@ -897,12 +915,11 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
|
||||
sin_server.sin_family = AF_INET;
|
||||
sin_server.sin_addr.s_addr = in_aton(addr);
|
||||
sin_server.sin_port = htons(opts.port);
|
||||
sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
|
||||
err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
|
||||
|
||||
if (!csocket) {
|
||||
if (err) {
|
||||
P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n");
|
||||
err = -EIO;
|
||||
goto error;
|
||||
return err;
|
||||
}
|
||||
|
||||
err = csocket->ops->connect(csocket,
|
||||
@ -912,30 +929,11 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
|
||||
P9_EPRINTK(KERN_ERR,
|
||||
"p9_trans_tcp: problem connecting socket to %s\n",
|
||||
addr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = p9_socket_open(client, csocket);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
p = (struct p9_trans_fd *) client->trans;
|
||||
p->conn = p9_conn_create(client);
|
||||
if (IS_ERR(p->conn)) {
|
||||
err = PTR_ERR(p->conn);
|
||||
p->conn = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (csocket)
|
||||
sock_release(csocket);
|
||||
return err;
|
||||
}
|
||||
|
||||
kfree(p);
|
||||
|
||||
return err;
|
||||
return p9_socket_open(client, csocket);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -944,49 +942,33 @@ p9_fd_create_unix(struct p9_client *client, const char *addr, char *args)
|
||||
int err;
|
||||
struct socket *csocket;
|
||||
struct sockaddr_un sun_server;
|
||||
struct p9_trans_fd *p = NULL; /* this gets allocated in p9_fd_open */
|
||||
|
||||
csocket = NULL;
|
||||
|
||||
if (strlen(addr) > UNIX_PATH_MAX) {
|
||||
P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
|
||||
addr);
|
||||
err = -ENAMETOOLONG;
|
||||
goto error;
|
||||
return -ENAMETOOLONG;
|
||||
}
|
||||
|
||||
sun_server.sun_family = PF_UNIX;
|
||||
strcpy(sun_server.sun_path, addr);
|
||||
sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
|
||||
err = sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
|
||||
if (err < 0) {
|
||||
P9_EPRINTK(KERN_ERR, "p9_trans_unix: problem creating socket\n");
|
||||
return err;
|
||||
}
|
||||
err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
|
||||
sizeof(struct sockaddr_un) - 1, 0);
|
||||
if (err < 0) {
|
||||
P9_EPRINTK(KERN_ERR,
|
||||
"p9_trans_unix: problem connecting socket: %s: %d\n",
|
||||
addr, err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = p9_socket_open(client, csocket);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
p = (struct p9_trans_fd *) client->trans;
|
||||
p->conn = p9_conn_create(client);
|
||||
if (IS_ERR(p->conn)) {
|
||||
err = PTR_ERR(p->conn);
|
||||
p->conn = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (csocket)
|
||||
sock_release(csocket);
|
||||
return err;
|
||||
}
|
||||
|
||||
kfree(p);
|
||||
return err;
|
||||
return p9_socket_open(client, csocket);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -994,7 +976,7 @@ p9_fd_create(struct p9_client *client, const char *addr, char *args)
|
||||
{
|
||||
int err;
|
||||
struct p9_fd_opts opts;
|
||||
struct p9_trans_fd *p = NULL; /* this get allocated in p9_fd_open */
|
||||
struct p9_trans_fd *p;
|
||||
|
||||
parse_opts(args, &opts);
|
||||
|
||||
@ -1005,21 +987,19 @@ p9_fd_create(struct p9_client *client, const char *addr, char *args)
|
||||
|
||||
err = p9_fd_open(client, opts.rfd, opts.wfd);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
return err;
|
||||
|
||||
p = (struct p9_trans_fd *) client->trans;
|
||||
p->conn = p9_conn_create(client);
|
||||
if (IS_ERR(p->conn)) {
|
||||
err = PTR_ERR(p->conn);
|
||||
p->conn = NULL;
|
||||
goto error;
|
||||
fput(p->rd);
|
||||
fput(p->wr);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
kfree(p);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct p9_trans_module p9_tcp_trans = {
|
||||
|
108
net/socket.c
108
net/socket.c
@ -355,68 +355,61 @@ static const struct dentry_operations sockfs_dentry_operations = {
|
||||
* but we take care of internal coherence yet.
|
||||
*/
|
||||
|
||||
static int sock_alloc_fd(struct file **filep, int flags)
|
||||
static int sock_alloc_file(struct socket *sock, struct file **f, int flags)
|
||||
{
|
||||
struct qstr name = { .name = "" };
|
||||
struct path path;
|
||||
struct file *file;
|
||||
int fd;
|
||||
|
||||
fd = get_unused_fd_flags(flags);
|
||||
if (likely(fd >= 0)) {
|
||||
struct file *file = get_empty_filp();
|
||||
if (unlikely(fd < 0))
|
||||
return fd;
|
||||
|
||||
*filep = file;
|
||||
if (unlikely(!file)) {
|
||||
put_unused_fd(fd);
|
||||
return -ENFILE;
|
||||
}
|
||||
} else
|
||||
*filep = NULL;
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int sock_attach_fd(struct socket *sock, struct file *file, int flags)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
struct qstr name = { .name = "" };
|
||||
|
||||
dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name);
|
||||
if (unlikely(!dentry))
|
||||
path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name);
|
||||
if (unlikely(!path.dentry)) {
|
||||
put_unused_fd(fd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
path.mnt = mntget(sock_mnt);
|
||||
|
||||
dentry->d_op = &sockfs_dentry_operations;
|
||||
path.dentry->d_op = &sockfs_dentry_operations;
|
||||
/*
|
||||
* We dont want to push this dentry into global dentry hash table.
|
||||
* We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED
|
||||
* This permits a working /proc/$pid/fd/XXX on sockets
|
||||
*/
|
||||
dentry->d_flags &= ~DCACHE_UNHASHED;
|
||||
d_instantiate(dentry, SOCK_INODE(sock));
|
||||
path.dentry->d_flags &= ~DCACHE_UNHASHED;
|
||||
d_instantiate(path.dentry, SOCK_INODE(sock));
|
||||
SOCK_INODE(sock)->i_fop = &socket_file_ops;
|
||||
|
||||
file = alloc_file(&path, FMODE_READ | FMODE_WRITE,
|
||||
&socket_file_ops);
|
||||
if (unlikely(!file)) {
|
||||
/* drop dentry, keep inode */
|
||||
atomic_inc(&path.dentry->d_inode->i_count);
|
||||
path_put(&path);
|
||||
put_unused_fd(fd);
|
||||
return -ENFILE;
|
||||
}
|
||||
|
||||
sock->file = file;
|
||||
init_file(file, sock_mnt, dentry, FMODE_READ | FMODE_WRITE,
|
||||
&socket_file_ops);
|
||||
SOCK_INODE(sock)->i_fop = &socket_file_ops;
|
||||
file->f_flags = O_RDWR | (flags & O_NONBLOCK);
|
||||
file->f_pos = 0;
|
||||
file->private_data = sock;
|
||||
|
||||
return 0;
|
||||
*f = file;
|
||||
return fd;
|
||||
}
|
||||
|
||||
int sock_map_fd(struct socket *sock, int flags)
|
||||
{
|
||||
struct file *newfile;
|
||||
int fd = sock_alloc_fd(&newfile, flags);
|
||||
int fd = sock_alloc_file(sock, &newfile, flags);
|
||||
|
||||
if (likely(fd >= 0)) {
|
||||
int err = sock_attach_fd(sock, newfile, flags);
|
||||
|
||||
if (unlikely(err < 0)) {
|
||||
put_filp(newfile);
|
||||
put_unused_fd(fd);
|
||||
return err;
|
||||
}
|
||||
if (likely(fd >= 0))
|
||||
fd_install(fd, newfile);
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
@ -1390,29 +1383,19 @@ SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol,
|
||||
if (err < 0)
|
||||
goto out_release_both;
|
||||
|
||||
fd1 = sock_alloc_fd(&newfile1, flags & O_CLOEXEC);
|
||||
fd1 = sock_alloc_file(sock1, &newfile1, flags);
|
||||
if (unlikely(fd1 < 0)) {
|
||||
err = fd1;
|
||||
goto out_release_both;
|
||||
}
|
||||
|
||||
fd2 = sock_alloc_fd(&newfile2, flags & O_CLOEXEC);
|
||||
fd2 = sock_alloc_file(sock2, &newfile2, flags);
|
||||
if (unlikely(fd2 < 0)) {
|
||||
err = fd2;
|
||||
put_filp(newfile1);
|
||||
put_unused_fd(fd1);
|
||||
goto out_release_both;
|
||||
}
|
||||
|
||||
err = sock_attach_fd(sock1, newfile1, flags & O_NONBLOCK);
|
||||
if (unlikely(err < 0)) {
|
||||
goto out_fd2;
|
||||
}
|
||||
|
||||
err = sock_attach_fd(sock2, newfile2, flags & O_NONBLOCK);
|
||||
if (unlikely(err < 0)) {
|
||||
fput(newfile1);
|
||||
goto out_fd1;
|
||||
put_unused_fd(fd1);
|
||||
sock_release(sock2);
|
||||
goto out;
|
||||
}
|
||||
|
||||
audit_fd_pair(fd1, fd2);
|
||||
@ -1438,16 +1421,6 @@ out_release_1:
|
||||
sock_release(sock1);
|
||||
out:
|
||||
return err;
|
||||
|
||||
out_fd2:
|
||||
put_filp(newfile1);
|
||||
sock_release(sock1);
|
||||
out_fd1:
|
||||
put_filp(newfile2);
|
||||
sock_release(sock2);
|
||||
put_unused_fd(fd1);
|
||||
put_unused_fd(fd2);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1551,17 +1524,13 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
|
||||
*/
|
||||
__module_get(newsock->ops->owner);
|
||||
|
||||
newfd = sock_alloc_fd(&newfile, flags & O_CLOEXEC);
|
||||
newfd = sock_alloc_file(newsock, &newfile, flags);
|
||||
if (unlikely(newfd < 0)) {
|
||||
err = newfd;
|
||||
sock_release(newsock);
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
err = sock_attach_fd(newsock, newfile, flags & O_NONBLOCK);
|
||||
if (err < 0)
|
||||
goto out_fd_simple;
|
||||
|
||||
err = security_socket_accept(sock, newsock);
|
||||
if (err)
|
||||
goto out_fd;
|
||||
@ -1591,11 +1560,6 @@ out_put:
|
||||
fput_light(sock->file, fput_needed);
|
||||
out:
|
||||
return err;
|
||||
out_fd_simple:
|
||||
sock_release(newsock);
|
||||
put_filp(newfile);
|
||||
put_unused_fd(newfd);
|
||||
goto out_put;
|
||||
out_fd:
|
||||
fput(newfile);
|
||||
put_unused_fd(newfd);
|
||||
|
@ -97,7 +97,6 @@ static inline unsigned long ima_hash_key(u8 *digest)
|
||||
|
||||
/* iint cache flags */
|
||||
#define IMA_MEASURED 1
|
||||
#define IMA_IINT_DUMP_STACK 512
|
||||
|
||||
/* integrity data associated with an inode */
|
||||
struct ima_iint_cache {
|
||||
@ -128,8 +127,6 @@ void ima_template_show(struct seq_file *m, void *e,
|
||||
*/
|
||||
struct ima_iint_cache *ima_iint_insert(struct inode *inode);
|
||||
struct ima_iint_cache *ima_iint_find_get(struct inode *inode);
|
||||
struct ima_iint_cache *ima_iint_find_insert_get(struct inode *inode);
|
||||
void ima_iint_delete(struct inode *inode);
|
||||
void iint_free(struct kref *kref);
|
||||
void iint_rcu_free(struct rcu_head *rcu);
|
||||
|
||||
|
@ -19,8 +19,6 @@
|
||||
#include <linux/radix-tree.h>
|
||||
#include "ima.h"
|
||||
|
||||
#define ima_iint_delete ima_inode_free
|
||||
|
||||
RADIX_TREE(ima_iint_store, GFP_ATOMIC);
|
||||
DEFINE_SPINLOCK(ima_iint_lock);
|
||||
|
||||
@ -45,22 +43,21 @@ out:
|
||||
return iint;
|
||||
}
|
||||
|
||||
/* Allocate memory for the iint associated with the inode
|
||||
* from the iint_cache slab, initialize the iint, and
|
||||
* insert it into the radix tree.
|
||||
*
|
||||
* On success return a pointer to the iint; on failure return NULL.
|
||||
/**
|
||||
* ima_inode_alloc - allocate an iint associated with an inode
|
||||
* @inode: pointer to the inode
|
||||
*/
|
||||
struct ima_iint_cache *ima_iint_insert(struct inode *inode)
|
||||
int ima_inode_alloc(struct inode *inode)
|
||||
{
|
||||
struct ima_iint_cache *iint = NULL;
|
||||
int rc = 0;
|
||||
|
||||
if (!ima_initialized)
|
||||
return iint;
|
||||
return 0;
|
||||
|
||||
iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
|
||||
if (!iint)
|
||||
return iint;
|
||||
return -ENOMEM;
|
||||
|
||||
rc = radix_tree_preload(GFP_NOFS);
|
||||
if (rc < 0)
|
||||
@ -70,66 +67,14 @@ struct ima_iint_cache *ima_iint_insert(struct inode *inode)
|
||||
rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint);
|
||||
spin_unlock(&ima_iint_lock);
|
||||
out:
|
||||
if (rc < 0) {
|
||||
if (rc < 0)
|
||||
kmem_cache_free(iint_cache, iint);
|
||||
if (rc == -EEXIST) {
|
||||
spin_lock(&ima_iint_lock);
|
||||
iint = radix_tree_lookup(&ima_iint_store,
|
||||
(unsigned long)inode);
|
||||
spin_unlock(&ima_iint_lock);
|
||||
} else
|
||||
iint = NULL;
|
||||
}
|
||||
|
||||
radix_tree_preload_end();
|
||||
return iint;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* ima_inode_alloc - allocate an iint associated with an inode
|
||||
* @inode: pointer to the inode
|
||||
*
|
||||
* Return 0 on success, 1 on failure.
|
||||
*/
|
||||
int ima_inode_alloc(struct inode *inode)
|
||||
{
|
||||
struct ima_iint_cache *iint;
|
||||
|
||||
if (!ima_initialized)
|
||||
return 0;
|
||||
|
||||
iint = ima_iint_insert(inode);
|
||||
if (!iint)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ima_iint_find_insert_get - get the iint associated with an inode
|
||||
*
|
||||
* Most insertions are done at inode_alloc, except those allocated
|
||||
* before late_initcall. When the iint does not exist, allocate it,
|
||||
* initialize and insert it, and increment the iint refcount.
|
||||
*
|
||||
* (Can't initialize at security_initcall before any inodes are
|
||||
* allocated, got to wait at least until proc_init.)
|
||||
*
|
||||
* Return the iint.
|
||||
*/
|
||||
struct ima_iint_cache *ima_iint_find_insert_get(struct inode *inode)
|
||||
{
|
||||
struct ima_iint_cache *iint = NULL;
|
||||
|
||||
iint = ima_iint_find_get(inode);
|
||||
if (iint)
|
||||
return iint;
|
||||
|
||||
iint = ima_iint_insert(inode);
|
||||
if (iint)
|
||||
kref_get(&iint->refcount);
|
||||
|
||||
return iint;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ima_iint_find_insert_get);
|
||||
|
||||
/* iint_free - called when the iint refcount goes to zero */
|
||||
void iint_free(struct kref *kref)
|
||||
{
|
||||
@ -164,12 +109,12 @@ void iint_rcu_free(struct rcu_head *rcu_head)
|
||||
}
|
||||
|
||||
/**
|
||||
* ima_iint_delete - called on integrity_inode_free
|
||||
* ima_inode_free - called on security_inode_free
|
||||
* @inode: pointer to the inode
|
||||
*
|
||||
* Free the integrity information(iint) associated with an inode.
|
||||
*/
|
||||
void ima_iint_delete(struct inode *inode)
|
||||
void ima_inode_free(struct inode *inode)
|
||||
{
|
||||
struct ima_iint_cache *iint;
|
||||
|
||||
|
@ -13,8 +13,8 @@
|
||||
* License.
|
||||
*
|
||||
* File: ima_main.c
|
||||
* implements the IMA hooks: ima_bprm_check, ima_file_mmap,
|
||||
* and ima_path_check.
|
||||
* implements the IMA hooks: ima_bprm_check, ima_file_mmap,
|
||||
* and ima_path_check.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/file.h>
|
||||
@ -35,6 +35,100 @@ static int __init hash_setup(char *str)
|
||||
}
|
||||
__setup("ima_hash=", hash_setup);
|
||||
|
||||
struct ima_imbalance {
|
||||
struct hlist_node node;
|
||||
unsigned long fsmagic;
|
||||
};
|
||||
|
||||
/*
|
||||
* ima_limit_imbalance - emit one imbalance message per filesystem type
|
||||
*
|
||||
* Maintain list of filesystem types that do not measure files properly.
|
||||
* Return false if unknown, true if known.
|
||||
*/
|
||||
static bool ima_limit_imbalance(struct file *file)
|
||||
{
|
||||
static DEFINE_SPINLOCK(ima_imbalance_lock);
|
||||
static HLIST_HEAD(ima_imbalance_list);
|
||||
|
||||
struct super_block *sb = file->f_dentry->d_sb;
|
||||
struct ima_imbalance *entry;
|
||||
struct hlist_node *node;
|
||||
bool found = false;
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(entry, node, &ima_imbalance_list, node) {
|
||||
if (entry->fsmagic == sb->s_magic) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
if (found)
|
||||
goto out;
|
||||
|
||||
entry = kmalloc(sizeof(*entry), GFP_NOFS);
|
||||
if (!entry)
|
||||
goto out;
|
||||
entry->fsmagic = sb->s_magic;
|
||||
spin_lock(&ima_imbalance_lock);
|
||||
/*
|
||||
* we could have raced and something else might have added this fs
|
||||
* to the list, but we don't really care
|
||||
*/
|
||||
hlist_add_head_rcu(&entry->node, &ima_imbalance_list);
|
||||
spin_unlock(&ima_imbalance_lock);
|
||||
printk(KERN_INFO "IMA: unmeasured files on fsmagic: %lX\n",
|
||||
entry->fsmagic);
|
||||
out:
|
||||
return found;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the counts given an fmode_t
|
||||
*/
|
||||
static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode)
|
||||
{
|
||||
BUG_ON(!mutex_is_locked(&iint->mutex));
|
||||
|
||||
iint->opencount++;
|
||||
if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
|
||||
iint->readcount++;
|
||||
if (mode & FMODE_WRITE)
|
||||
iint->writecount++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrement ima counts
|
||||
*/
|
||||
static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
mode_t mode = file->f_mode;
|
||||
BUG_ON(!mutex_is_locked(&iint->mutex));
|
||||
|
||||
iint->opencount--;
|
||||
if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
|
||||
iint->readcount--;
|
||||
if (mode & FMODE_WRITE) {
|
||||
iint->writecount--;
|
||||
if (iint->writecount == 0) {
|
||||
if (iint->version != inode->i_version)
|
||||
iint->flags &= ~IMA_MEASURED;
|
||||
}
|
||||
}
|
||||
|
||||
if (((iint->opencount < 0) ||
|
||||
(iint->readcount < 0) ||
|
||||
(iint->writecount < 0)) &&
|
||||
!ima_limit_imbalance(file)) {
|
||||
printk(KERN_INFO "%s: open/free imbalance (r:%ld w:%ld o:%ld)\n",
|
||||
__FUNCTION__, iint->readcount, iint->writecount,
|
||||
iint->opencount);
|
||||
dump_stack();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ima_file_free - called on __fput()
|
||||
* @file: pointer to file structure being freed
|
||||
@ -54,29 +148,7 @@ void ima_file_free(struct file *file)
|
||||
return;
|
||||
|
||||
mutex_lock(&iint->mutex);
|
||||
if (iint->opencount <= 0) {
|
||||
printk(KERN_INFO
|
||||
"%s: %s open/free imbalance (r:%ld w:%ld o:%ld f:%ld)\n",
|
||||
__FUNCTION__, file->f_dentry->d_name.name,
|
||||
iint->readcount, iint->writecount,
|
||||
iint->opencount, atomic_long_read(&file->f_count));
|
||||
if (!(iint->flags & IMA_IINT_DUMP_STACK)) {
|
||||
dump_stack();
|
||||
iint->flags |= IMA_IINT_DUMP_STACK;
|
||||
}
|
||||
}
|
||||
iint->opencount--;
|
||||
|
||||
if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
|
||||
iint->readcount--;
|
||||
|
||||
if (file->f_mode & FMODE_WRITE) {
|
||||
iint->writecount--;
|
||||
if (iint->writecount == 0) {
|
||||
if (iint->version != inode->i_version)
|
||||
iint->flags &= ~IMA_MEASURED;
|
||||
}
|
||||
}
|
||||
ima_dec_counts(iint, inode, file);
|
||||
mutex_unlock(&iint->mutex);
|
||||
kref_put(&iint->refcount, iint_free);
|
||||
}
|
||||
@ -116,8 +188,7 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file,
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
iint->opencount++;
|
||||
iint->readcount++;
|
||||
ima_inc_counts(iint, file->f_mode);
|
||||
|
||||
rc = ima_collect_measurement(iint, file);
|
||||
if (!rc)
|
||||
@ -125,15 +196,6 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void ima_update_counts(struct ima_iint_cache *iint, int mask)
|
||||
{
|
||||
iint->opencount++;
|
||||
if ((mask & MAY_WRITE) || (mask == 0))
|
||||
iint->writecount++;
|
||||
else if (mask & (MAY_READ | MAY_EXEC))
|
||||
iint->readcount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* ima_path_check - based on policy, collect/store measurement.
|
||||
* @path: contains a pointer to the path to be measured
|
||||
@ -152,7 +214,7 @@ static void ima_update_counts(struct ima_iint_cache *iint, int mask)
|
||||
* Always return 0 and audit dentry_open failures.
|
||||
* (Return code will be based upon measurement appraisal.)
|
||||
*/
|
||||
int ima_path_check(struct path *path, int mask, int update_counts)
|
||||
int ima_path_check(struct path *path, int mask)
|
||||
{
|
||||
struct inode *inode = path->dentry->d_inode;
|
||||
struct ima_iint_cache *iint;
|
||||
@ -161,13 +223,11 @@ int ima_path_check(struct path *path, int mask, int update_counts)
|
||||
|
||||
if (!ima_initialized || !S_ISREG(inode->i_mode))
|
||||
return 0;
|
||||
iint = ima_iint_find_insert_get(inode);
|
||||
iint = ima_iint_find_get(inode);
|
||||
if (!iint)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&iint->mutex);
|
||||
if (update_counts)
|
||||
ima_update_counts(iint, mask);
|
||||
|
||||
rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK);
|
||||
if (rc < 0)
|
||||
@ -219,7 +279,7 @@ static int process_measurement(struct file *file, const unsigned char *filename,
|
||||
|
||||
if (!ima_initialized || !S_ISREG(inode->i_mode))
|
||||
return 0;
|
||||
iint = ima_iint_find_insert_get(inode);
|
||||
iint = ima_iint_find_get(inode);
|
||||
if (!iint)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -237,39 +297,6 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* ima_counts_put - decrement file counts
|
||||
*
|
||||
* File counts are incremented in ima_path_check. On file open
|
||||
* error, such as ETXTBSY, decrement the counts to prevent
|
||||
* unnecessary imbalance messages.
|
||||
*/
|
||||
void ima_counts_put(struct path *path, int mask)
|
||||
{
|
||||
struct inode *inode = path->dentry->d_inode;
|
||||
struct ima_iint_cache *iint;
|
||||
|
||||
/* The inode may already have been freed, freeing the iint
|
||||
* with it. Verify the inode is not NULL before dereferencing
|
||||
* it.
|
||||
*/
|
||||
if (!ima_initialized || !inode || !S_ISREG(inode->i_mode))
|
||||
return;
|
||||
iint = ima_iint_find_insert_get(inode);
|
||||
if (!iint)
|
||||
return;
|
||||
|
||||
mutex_lock(&iint->mutex);
|
||||
iint->opencount--;
|
||||
if ((mask & MAY_WRITE) || (mask == 0))
|
||||
iint->writecount--;
|
||||
else if (mask & (MAY_READ | MAY_EXEC))
|
||||
iint->readcount--;
|
||||
mutex_unlock(&iint->mutex);
|
||||
|
||||
kref_put(&iint->refcount, iint_free);
|
||||
}
|
||||
|
||||
/*
|
||||
* ima_counts_get - increment file counts
|
||||
*
|
||||
@ -286,16 +313,11 @@ void ima_counts_get(struct file *file)
|
||||
|
||||
if (!ima_initialized || !S_ISREG(inode->i_mode))
|
||||
return;
|
||||
iint = ima_iint_find_insert_get(inode);
|
||||
iint = ima_iint_find_get(inode);
|
||||
if (!iint)
|
||||
return;
|
||||
mutex_lock(&iint->mutex);
|
||||
iint->opencount++;
|
||||
if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
|
||||
iint->readcount++;
|
||||
|
||||
if (file->f_mode & FMODE_WRITE)
|
||||
iint->writecount++;
|
||||
ima_inc_counts(iint, file->f_mode);
|
||||
mutex_unlock(&iint->mutex);
|
||||
|
||||
kref_put(&iint->refcount, iint_free);
|
||||
|
Loading…
Reference in New Issue
Block a user