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:
Linus Torvalds 2009-12-16 12:04:02 -08:00
commit bac5e54c29
81 changed files with 1173 additions and 1832 deletions

View file

@ -2200,7 +2200,7 @@ pfm_alloc_file(pfm_context_t *ctx)
{ {
struct file *file; struct file *file;
struct inode *inode; struct inode *inode;
struct dentry *dentry; struct path path;
char name[32]; char name[32];
struct qstr this; struct qstr this;
@ -2225,18 +2225,19 @@ pfm_alloc_file(pfm_context_t *ctx)
/* /*
* allocate a new dcache entry * allocate a new dcache entry
*/ */
dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this); path.dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this);
if (!dentry) { if (!path.dentry) {
iput(inode); iput(inode);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
path.mnt = mntget(pfmfs_mnt);
dentry->d_op = &pfmfs_dentry_operations; path.dentry->d_op = &pfmfs_dentry_operations;
d_add(dentry, inode); 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) { if (!file) {
dput(dentry); path_put(&path);
return ERR_PTR(-ENFILE); return ERR_PTR(-ENFILE);
} }

View file

@ -445,12 +445,7 @@ done:
int hpux_pipe(int *kstack_fildes) int hpux_pipe(int *kstack_fildes)
{ {
int error; return do_pipe_flags(kstack_fildes, 0);
lock_kernel();
error = do_pipe_flags(kstack_fildes, 0);
unlock_kernel();
return error;
} }
/* lies - says it works, but it really didn't lock anything */ /* lies - says it works, but it really didn't lock anything */

View file

@ -30,7 +30,6 @@ struct mmap_arg_struct;
asmlinkage long sys32_mmap(struct mmap_arg_struct __user *); asmlinkage long sys32_mmap(struct mmap_arg_struct __user *);
asmlinkage long sys32_mprotect(unsigned long, size_t, unsigned long); asmlinkage long sys32_mprotect(unsigned long, size_t, unsigned long);
asmlinkage long sys32_pipe(int __user *);
struct sigaction32; struct sigaction32;
struct old_sigaction32; struct old_sigaction32;
asmlinkage long sys32_rt_sigaction(int, struct sigaction32 __user *, asmlinkage long sys32_rt_sigaction(int, struct sigaction32 __user *,

View file

@ -12,7 +12,6 @@ struct pt_regs;
struct sigaction; struct sigaction;
asmlinkage long xtensa_execve(char*, char**, char**, struct pt_regs*); asmlinkage long xtensa_execve(char*, char**, char**, struct pt_regs*);
asmlinkage long xtensa_clone(unsigned long, unsigned long, 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_ptrace(long, long, long, long);
asmlinkage long xtensa_sigreturn(struct pt_regs*); asmlinkage long xtensa_sigreturn(struct pt_regs*);
asmlinkage long xtensa_rt_sigreturn(struct pt_regs*); asmlinkage long xtensa_rt_sigreturn(struct pt_regs*);

View file

@ -94,7 +94,7 @@ __SYSCALL( 35, sys_readlink, 3)
#define __NR_mknod 36 #define __NR_mknod 36
__SYSCALL( 36, sys_mknod, 3) __SYSCALL( 36, sys_mknod, 3)
#define __NR_pipe 37 #define __NR_pipe 37
__SYSCALL( 37, xtensa_pipe, 1) __SYSCALL( 37, sys_pipe, 1)
#define __NR_unlink 38 #define __NR_unlink 38
__SYSCALL( 38, sys_unlink, 1) __SYSCALL( 38, sys_unlink, 1)
#define __NR_rmdir 39 #define __NR_rmdir 39

View file

@ -39,24 +39,6 @@ syscall_t sys_call_table[__NR_syscall_count] /* FIXME __cacheline_aligned */= {
#include <asm/unistd.h> #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) asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg)
{ {
unsigned long ret; unsigned long ret;

View file

@ -492,6 +492,7 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
int is_async, int *fd) int is_async, int *fd)
{ {
struct ib_uverbs_event_file *ev_file; struct ib_uverbs_event_file *ev_file;
struct path path;
struct file *filp; struct file *filp;
int ret; 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 * system call on a uverbs file, which will already have a
* module reference. * module reference.
*/ */
filp = alloc_file(uverbs_event_mnt, dget(uverbs_event_mnt->mnt_root), path.mnt = uverbs_event_mnt;
FMODE_READ, fops_get(&uverbs_event_fops)); path.dentry = uverbs_event_mnt->mnt_root;
path_get(&path);
filp = alloc_file(&path, FMODE_READ, fops_get(&uverbs_event_fops));
if (!filp) { if (!filp) {
ret = -ENFILE; ret = -ENFILE;
goto err_fd; goto err_fd;
@ -531,6 +534,8 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
return filp; return filp;
err_fd: err_fd:
fops_put(&uverbs_event_fops);
path_put(&path);
put_unused_fd(*fd); put_unused_fd(*fd);
err: err:

View file

@ -403,7 +403,7 @@ static void dst_node_cleanup(struct dst_node *n)
if (n->bdev) { if (n->bdev) {
sync_blockdev(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); 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 * Setting up export device: lookup by the name, get its size
* and setup listening socket, which will accept clients, which * 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) struct dst_export_ctl *le)
{ {
int err; int err;
dev_t dev = 0; /* gcc likes to scream here */
snprintf(n->info->local, sizeof(n->info->local), "%s", le->device); snprintf(n->info->local, sizeof(n->info->local), "%s", le->device);
err = dst_lookup_device(le->device, &dev); n->bdev = open_bdev_exclusive(le->device, FMODE_READ|FMODE_WRITE, NULL);
if (err) if (IS_ERR(n->bdev))
return err; return PTR_ERR(n->bdev);
n->bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE);
if (!n->bdev)
return -ENODEV;
if (n->size != 0) if (n->size != 0)
n->size = min_t(loff_t, n->bdev->bd_inode->i_size, n->size); 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; return 0;
err_out_cleanup: err_out_cleanup:
blkdev_put(n->bdev, FMODE_READ|FMODE_WRITE); close_bdev_exclusive(n->bdev, FMODE_READ|FMODE_WRITE);
n->bdev = NULL; n->bdev = NULL;
return err; return err;

View file

@ -88,7 +88,7 @@ struct file *anon_inode_getfile(const char *name,
void *priv, int flags) void *priv, int flags)
{ {
struct qstr this; struct qstr this;
struct dentry *dentry; struct path path;
struct file *file; struct file *file;
int error; int error;
@ -106,10 +106,11 @@ struct file *anon_inode_getfile(const char *name,
this.name = name; this.name = name;
this.len = strlen(name); this.len = strlen(name);
this.hash = 0; this.hash = 0;
dentry = d_alloc(anon_inode_mnt->mnt_sb->s_root, &this); path.dentry = d_alloc(anon_inode_mnt->mnt_sb->s_root, &this);
if (!dentry) if (!path.dentry)
goto err_module; goto err_module;
path.mnt = mntget(anon_inode_mnt);
/* /*
* We know the anon_inode inode count is always greater than zero, * 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 * 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); 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 */ /* Do not publish this dentry inside the global dentry hash table */
dentry->d_flags &= ~DCACHE_UNHASHED; path.dentry->d_flags &= ~DCACHE_UNHASHED;
d_instantiate(dentry, anon_inode_inode); d_instantiate(path.dentry, anon_inode_inode);
error = -ENFILE; error = -ENFILE;
file = alloc_file(anon_inode_mnt, dentry, file = alloc_file(&path, FMODE_READ | FMODE_WRITE, fops);
FMODE_READ | FMODE_WRITE, fops);
if (!file) if (!file)
goto err_dput; goto err_dput;
file->f_mapping = anon_inode_inode->i_mapping; file->f_mapping = anon_inode_inode->i_mapping;
@ -137,7 +137,7 @@ struct file *anon_inode_getfile(const char *name,
return file; return file;
err_dput: err_dput:
dput(dentry); path_put(&path);
err_module: err_module:
module_put(fops->owner); module_put(fops->owner);
return ERR_PTR(error); return ERR_PTR(error);

View file

@ -73,13 +73,13 @@ static struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
return acl; return acl;
} }
static int btrfs_xattr_get_acl(struct inode *inode, int type, static int btrfs_xattr_acl_get(struct dentry *dentry, const char *name,
void *value, size_t size) void *value, size_t size, int type)
{ {
struct posix_acl *acl; struct posix_acl *acl;
int ret = 0; int ret = 0;
acl = btrfs_get_acl(inode, type); acl = btrfs_get_acl(dentry->d_inode, type);
if (IS_ERR(acl)) if (IS_ERR(acl))
return PTR_ERR(acl); return PTR_ERR(acl);
@ -151,8 +151,8 @@ out:
return ret; return ret;
} }
static int btrfs_xattr_set_acl(struct inode *inode, int type, static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
const void *value, size_t size) const void *value, size_t size, int flags, int type)
{ {
int ret = 0; int ret = 0;
struct posix_acl *acl = NULL; 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); posix_acl_release(acl);
return ret; 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) int btrfs_check_acl(struct inode *inode, int mask)
{ {
struct posix_acl *acl; struct posix_acl *acl;
@ -303,14 +278,16 @@ int btrfs_acl_chmod(struct inode *inode)
struct xattr_handler btrfs_xattr_acl_default_handler = { struct xattr_handler btrfs_xattr_acl_default_handler = {
.prefix = POSIX_ACL_XATTR_DEFAULT, .prefix = POSIX_ACL_XATTR_DEFAULT,
.get = btrfs_xattr_acl_default_get, .flags = ACL_TYPE_DEFAULT,
.set = btrfs_xattr_acl_default_set, .get = btrfs_xattr_acl_get,
.set = btrfs_xattr_acl_set,
}; };
struct xattr_handler btrfs_xattr_acl_access_handler = { struct xattr_handler btrfs_xattr_acl_access_handler = {
.prefix = POSIX_ACL_XATTR_ACCESS, .prefix = POSIX_ACL_XATTR_ACCESS,
.get = btrfs_xattr_acl_access_get, .flags = ACL_TYPE_ACCESS,
.set = btrfs_xattr_acl_access_set, .get = btrfs_xattr_acl_get,
.set = btrfs_xattr_acl_set,
}; };
#else /* CONFIG_BTRFS_FS_POSIX_ACL */ #else /* CONFIG_BTRFS_FS_POSIX_ACL */

View file

@ -84,7 +84,7 @@ int cachefiles_daemon_bind(struct cachefiles_cache *cache, char *args)
static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache) static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache)
{ {
struct cachefiles_object *fsdef; struct cachefiles_object *fsdef;
struct nameidata nd; struct path path;
struct kstatfs stats; struct kstatfs stats;
struct dentry *graveyard, *cachedir, *root; struct dentry *graveyard, *cachedir, *root;
const struct cred *saved_cred; const struct cred *saved_cred;
@ -114,15 +114,12 @@ static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache)
_debug("- fsdef %p", fsdef); _debug("- fsdef %p", fsdef);
/* look up the directory at the root of the cache */ /* look up the directory at the root of the cache */
memset(&nd, 0, sizeof(nd)); ret = kern_path(cache->rootdirname, LOOKUP_DIRECTORY, &path);
ret = path_lookup(cache->rootdirname, LOOKUP_DIRECTORY, &nd);
if (ret < 0) if (ret < 0)
goto error_open_root; goto error_open_root;
cache->mnt = mntget(nd.path.mnt); cache->mnt = path.mnt;
root = dget(nd.path.dentry); root = path.dentry;
path_put(&nd.path);
/* check parameters */ /* check parameters */
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;

View file

@ -11,7 +11,6 @@
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/ima.h>
#include "internal.h" #include "internal.h"
/* /*
@ -923,7 +922,6 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)
if (IS_ERR(file)) { if (IS_ERR(file)) {
ret = PTR_ERR(file); ret = PTR_ERR(file);
} else { } else {
ima_counts_get(file);
ret = -EIO; ret = -EIO;
if (file->f_op->write) { if (file->f_op->write) {
pos = (loff_t) page->index << PAGE_SHIFT; pos = (loff_t) page->index << PAGE_SHIFT;

View file

@ -978,6 +978,7 @@ struct dentry *d_alloc_name(struct dentry *parent, const char *name)
q.hash = full_name_hash(q.name, q.len); q.hash = full_name_hash(q.name, q.len);
return d_alloc(parent, &q); return d_alloc(parent, &q);
} }
EXPORT_SYMBOL(d_alloc_name);
/* the caller must hold dcache_lock */ /* the caller must hold dcache_lock */
static void __d_instantiate(struct dentry *dentry, struct inode *inode) static void __d_instantiate(struct dentry *dentry, struct inode *inode)

View file

@ -35,7 +35,6 @@
#include <linux/key.h> #include <linux/key.h>
#include <linux/parser.h> #include <linux/parser.h>
#include <linux/fs_stack.h> #include <linux/fs_stack.h>
#include <linux/ima.h>
#include "ecryptfs_kernel.h" #include "ecryptfs_kernel.h"
/** /**
@ -119,7 +118,6 @@ int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
struct ecryptfs_inode_info *inode_info = struct ecryptfs_inode_info *inode_info =
ecryptfs_inode_to_private(ecryptfs_dentry->d_inode); ecryptfs_inode_to_private(ecryptfs_dentry->d_inode);
int opened_lower_file = 0;
int rc = 0; int rc = 0;
mutex_lock(&inode_info->lower_file_mutex); 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]; " "for lower_dentry [0x%p] and lower_mnt [0x%p]; "
"rc = [%d]\n", lower_dentry, lower_mnt, rc); "rc = [%d]\n", lower_dentry, lower_mnt, rc);
inode_info->lower_file = NULL; inode_info->lower_file = NULL;
} else }
opened_lower_file = 1;
} }
mutex_unlock(&inode_info->lower_file_mutex); mutex_unlock(&inode_info->lower_file_mutex);
if (opened_lower_file)
ima_counts_get(inode_info->lower_file);
return rc; return rc;
} }

View file

@ -339,12 +339,12 @@ ext2_acl_chmod(struct inode *inode)
* Extended attribut handlers * Extended attribut handlers
*/ */
static size_t static size_t
ext2_xattr_list_acl_access(struct inode *inode, char *list, size_t list_size, ext2_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len) const char *name, size_t name_len, int type)
{ {
const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); 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; return 0;
if (list && size <= list_size) if (list && size <= list_size)
memcpy(list, POSIX_ACL_XATTR_ACCESS, 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 static size_t
ext2_xattr_list_acl_default(struct inode *inode, char *list, size_t list_size, ext2_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len) const char *name, size_t name_len, int type)
{ {
const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); 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; return 0;
if (list && size <= list_size) if (list && size <= list_size)
memcpy(list, POSIX_ACL_XATTR_DEFAULT, 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 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; struct posix_acl *acl;
int error; 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; return -EOPNOTSUPP;
acl = ext2_get_acl(inode, type); acl = ext2_get_acl(dentry->d_inode, type);
if (IS_ERR(acl)) if (IS_ERR(acl))
return PTR_ERR(acl); return PTR_ERR(acl);
if (acl == NULL) if (acl == NULL)
@ -385,33 +388,17 @@ ext2_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
} }
static int static int
ext2_xattr_get_acl_access(struct inode *inode, const char *name, ext2_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
void *buffer, size_t size) size_t size, int flags, int type)
{
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)
{ {
struct posix_acl *acl; struct posix_acl *acl;
int error; 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; return -EOPNOTSUPP;
if (!is_owner_or_cap(inode)) if (!is_owner_or_cap(dentry->d_inode))
return -EPERM; return -EPERM;
if (value) { if (value) {
@ -426,41 +413,25 @@ ext2_xattr_set_acl(struct inode *inode, int type, const void *value,
} else } else
acl = NULL; acl = NULL;
error = ext2_set_acl(inode, type, acl); error = ext2_set_acl(dentry->d_inode, type, acl);
release_and_out: release_and_out:
posix_acl_release(acl); posix_acl_release(acl);
return error; 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 = { struct xattr_handler ext2_xattr_acl_access_handler = {
.prefix = POSIX_ACL_XATTR_ACCESS, .prefix = POSIX_ACL_XATTR_ACCESS,
.flags = ACL_TYPE_ACCESS,
.list = ext2_xattr_list_acl_access, .list = ext2_xattr_list_acl_access,
.get = ext2_xattr_get_acl_access, .get = ext2_xattr_get_acl,
.set = ext2_xattr_set_acl_access, .set = ext2_xattr_set_acl,
}; };
struct xattr_handler ext2_xattr_acl_default_handler = { struct xattr_handler ext2_xattr_acl_default_handler = {
.prefix = POSIX_ACL_XATTR_DEFAULT, .prefix = POSIX_ACL_XATTR_DEFAULT,
.flags = ACL_TYPE_DEFAULT,
.list = ext2_xattr_list_acl_default, .list = ext2_xattr_list_acl_default,
.get = ext2_xattr_get_acl_default, .get = ext2_xattr_get_acl,
.set = ext2_xattr_set_acl_default, .set = ext2_xattr_set_acl,
}; };

View file

@ -60,6 +60,7 @@
#include <linux/mbcache.h> #include <linux/mbcache.h>
#include <linux/quotaops.h> #include <linux/quotaops.h>
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/security.h>
#include "ext2.h" #include "ext2.h"
#include "xattr.h" #include "xattr.h"
#include "acl.h" #include "acl.h"
@ -249,8 +250,9 @@ cleanup:
* used / required on success. * used / required on success.
*/ */
static int 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 buffer_head *bh = NULL;
struct ext2_xattr_entry *entry; struct ext2_xattr_entry *entry;
char *end; char *end;
@ -300,9 +302,10 @@ bad_block: ext2_error(inode->i_sb, "ext2_xattr_list",
ext2_xattr_handler(entry->e_name_index); ext2_xattr_handler(entry->e_name_index);
if (handler) { if (handler) {
size_t size = handler->list(inode, buffer, rest, size_t size = handler->list(dentry, buffer, rest,
entry->e_name, entry->e_name,
entry->e_name_len); entry->e_name_len,
handler->flags);
if (buffer) { if (buffer) {
if (size > rest) { if (size > rest) {
error = -ERANGE; error = -ERANGE;
@ -330,7 +333,7 @@ cleanup:
ssize_t ssize_t
ext2_listxattr(struct dentry *dentry, char *buffer, size_t size) 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);
} }
/* /*

View file

@ -11,8 +11,8 @@
#include "xattr.h" #include "xattr.h"
static size_t static size_t
ext2_xattr_security_list(struct inode *inode, char *list, size_t list_size, ext2_xattr_security_list(struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len) const char *name, size_t name_len, int type)
{ {
const int prefix_len = XATTR_SECURITY_PREFIX_LEN; const int prefix_len = XATTR_SECURITY_PREFIX_LEN;
const size_t total_len = prefix_len + name_len + 1; 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 static int
ext2_xattr_security_get(struct inode *inode, const char *name, ext2_xattr_security_get(struct dentry *dentry, const char *name,
void *buffer, size_t size) void *buffer, size_t size, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; 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); buffer, size);
} }
static int static int
ext2_xattr_security_set(struct inode *inode, const char *name, ext2_xattr_security_set(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; 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); value, size, flags);
} }

View file

@ -13,8 +13,8 @@
#include "xattr.h" #include "xattr.h"
static size_t static size_t
ext2_xattr_trusted_list(struct inode *inode, char *list, size_t list_size, ext2_xattr_trusted_list(struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len) const char *name, size_t name_len, int type)
{ {
const int prefix_len = XATTR_TRUSTED_PREFIX_LEN; const int prefix_len = XATTR_TRUSTED_PREFIX_LEN;
const size_t total_len = prefix_len + name_len + 1; 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 static int
ext2_xattr_trusted_get(struct inode *inode, const char *name, ext2_xattr_trusted_get(struct dentry *dentry, const char *name,
void *buffer, size_t size) void *buffer, size_t size, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; 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); buffer, size);
} }
static int static int
ext2_xattr_trusted_set(struct inode *inode, const char *name, ext2_xattr_trusted_set(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; 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); value, size, flags);
} }

View file

@ -12,13 +12,13 @@
#include "xattr.h" #include "xattr.h"
static size_t static size_t
ext2_xattr_user_list(struct inode *inode, char *list, size_t list_size, ext2_xattr_user_list(struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len) const char *name, size_t name_len, int type)
{ {
const size_t prefix_len = XATTR_USER_PREFIX_LEN; const size_t prefix_len = XATTR_USER_PREFIX_LEN;
const size_t total_len = prefix_len + name_len + 1; 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; return 0;
if (list && total_len <= list_size) { 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 static int
ext2_xattr_user_get(struct inode *inode, const char *name, ext2_xattr_user_get(struct dentry *dentry, const char *name,
void *buffer, size_t size) void *buffer, size_t size, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
if (!test_opt(inode->i_sb, XATTR_USER)) if (!test_opt(dentry->d_sb, XATTR_USER))
return -EOPNOTSUPP; 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 static int
ext2_xattr_user_set(struct inode *inode, const char *name, ext2_xattr_user_set(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
if (!test_opt(inode->i_sb, XATTR_USER)) if (!test_opt(dentry->d_sb, XATTR_USER))
return -EOPNOTSUPP; return -EOPNOTSUPP;
return ext2_xattr_set(inode, EXT2_XATTR_INDEX_USER, name, return ext2_xattr_set(dentry->d_inode, EXT2_XATTR_INDEX_USER,
value, size, flags); name, value, size, flags);
} }
struct xattr_handler ext2_xattr_user_handler = { struct xattr_handler ext2_xattr_user_handler = {

View file

@ -366,12 +366,12 @@ out:
* Extended attribute handlers * Extended attribute handlers
*/ */
static size_t static size_t
ext3_xattr_list_acl_access(struct inode *inode, char *list, size_t list_len, ext3_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_len,
const char *name, size_t name_len) const char *name, size_t name_len, int type)
{ {
const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); 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; return 0;
if (list && size <= list_len) if (list && size <= list_len)
memcpy(list, POSIX_ACL_XATTR_ACCESS, size); 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 static size_t
ext3_xattr_list_acl_default(struct inode *inode, char *list, size_t list_len, ext3_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_len,
const char *name, size_t name_len) const char *name, size_t name_len, int type)
{ {
const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); 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; return 0;
if (list && size <= list_len) if (list && size <= list_len)
memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); 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 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; struct posix_acl *acl;
int error; 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; return -EOPNOTSUPP;
acl = ext3_get_acl(inode, type); acl = ext3_get_acl(dentry->d_inode, type);
if (IS_ERR(acl)) if (IS_ERR(acl))
return PTR_ERR(acl); return PTR_ERR(acl);
if (acl == NULL) if (acl == NULL)
@ -412,31 +415,16 @@ ext3_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
} }
static int static int
ext3_xattr_get_acl_access(struct inode *inode, const char *name, ext3_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
void *buffer, size_t size) size_t size, int flags, int type)
{
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)
{ {
struct inode *inode = dentry->d_inode;
handle_t *handle; handle_t *handle;
struct posix_acl *acl; struct posix_acl *acl;
int error, retries = 0; int error, retries = 0;
if (strcmp(name, "") != 0)
return -EINVAL;
if (!test_opt(inode->i_sb, POSIX_ACL)) if (!test_opt(inode->i_sb, POSIX_ACL))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (!is_owner_or_cap(inode)) if (!is_owner_or_cap(inode))
@ -468,34 +456,18 @@ release_and_out:
return error; 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 = { struct xattr_handler ext3_xattr_acl_access_handler = {
.prefix = POSIX_ACL_XATTR_ACCESS, .prefix = POSIX_ACL_XATTR_ACCESS,
.flags = ACL_TYPE_ACCESS,
.list = ext3_xattr_list_acl_access, .list = ext3_xattr_list_acl_access,
.get = ext3_xattr_get_acl_access, .get = ext3_xattr_get_acl,
.set = ext3_xattr_set_acl_access, .set = ext3_xattr_set_acl,
}; };
struct xattr_handler ext3_xattr_acl_default_handler = { struct xattr_handler ext3_xattr_acl_default_handler = {
.prefix = POSIX_ACL_XATTR_DEFAULT, .prefix = POSIX_ACL_XATTR_DEFAULT,
.flags = ACL_TYPE_DEFAULT,
.list = ext3_xattr_list_acl_default, .list = ext3_xattr_list_acl_default,
.get = ext3_xattr_get_acl_default, .get = ext3_xattr_get_acl,
.set = ext3_xattr_set_acl_default, .set = ext3_xattr_set_acl,
}; };

View file

@ -99,7 +99,7 @@ static struct buffer_head *ext3_xattr_cache_find(struct inode *,
struct mb_cache_entry **); struct mb_cache_entry **);
static void ext3_xattr_rehash(struct ext3_xattr_header *, static void ext3_xattr_rehash(struct ext3_xattr_header *,
struct ext3_xattr_entry *); 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); size_t buffer_size);
static struct mb_cache *ext3_xattr_cache; static struct mb_cache *ext3_xattr_cache;
@ -147,7 +147,7 @@ ext3_xattr_handler(int name_index)
ssize_t ssize_t
ext3_listxattr(struct dentry *dentry, char *buffer, size_t size) 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 static int
@ -332,7 +332,7 @@ ext3_xattr_get(struct inode *inode, int name_index, const char *name,
} }
static int 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) char *buffer, size_t buffer_size)
{ {
size_t rest = 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); ext3_xattr_handler(entry->e_name_index);
if (handler) { if (handler) {
size_t size = handler->list(inode, buffer, rest, size_t size = handler->list(dentry, buffer, rest,
entry->e_name, entry->e_name,
entry->e_name_len); entry->e_name_len,
handler->flags);
if (buffer) { if (buffer) {
if (size > rest) if (size > rest)
return -ERANGE; return -ERANGE;
@ -357,8 +358,9 @@ ext3_xattr_list_entries(struct inode *inode, struct ext3_xattr_entry *entry,
} }
static int 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; struct buffer_head *bh = NULL;
int error; int error;
@ -383,7 +385,7 @@ ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
goto cleanup; goto cleanup;
} }
ext3_xattr_cache_insert(bh); 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: cleanup:
brelse(bh); brelse(bh);
@ -392,8 +394,9 @@ cleanup:
} }
static int 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_xattr_ibody_header *header;
struct ext3_inode *raw_inode; struct ext3_inode *raw_inode;
struct ext3_iloc iloc; 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); error = ext3_xattr_check_names(IFIRST(header), end);
if (error) if (error)
goto cleanup; goto cleanup;
error = ext3_xattr_list_entries(inode, IFIRST(header), error = ext3_xattr_list_entries(dentry, IFIRST(header),
buffer, buffer_size); buffer, buffer_size);
cleanup: cleanup:
@ -430,12 +433,12 @@ cleanup:
* used / required on success. * used / required on success.
*/ */
static int 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; int i_error, b_error;
down_read(&EXT3_I(inode)->xattr_sem); down_read(&EXT3_I(dentry->d_inode)->xattr_sem);
i_error = ext3_xattr_ibody_list(inode, buffer, buffer_size); i_error = ext3_xattr_ibody_list(dentry, buffer, buffer_size);
if (i_error < 0) { if (i_error < 0) {
b_error = 0; b_error = 0;
} else { } else {
@ -443,11 +446,11 @@ ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
buffer += i_error; buffer += i_error;
buffer_size -= 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) if (b_error < 0)
i_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; return i_error + b_error;
} }

View file

@ -12,8 +12,8 @@
#include "xattr.h" #include "xattr.h"
static size_t static size_t
ext3_xattr_security_list(struct inode *inode, char *list, size_t list_size, ext3_xattr_security_list(struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len) const char *name, size_t name_len, int type)
{ {
const size_t prefix_len = XATTR_SECURITY_PREFIX_LEN; const size_t prefix_len = XATTR_SECURITY_PREFIX_LEN;
const size_t total_len = prefix_len + name_len + 1; 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 static int
ext3_xattr_security_get(struct inode *inode, const char *name, ext3_xattr_security_get(struct dentry *dentry, const char *name,
void *buffer, size_t size) void *buffer, size_t size, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
return ext3_xattr_get(inode, EXT3_XATTR_INDEX_SECURITY, name, return ext3_xattr_get(dentry->d_inode, EXT3_XATTR_INDEX_SECURITY,
buffer, size); name, buffer, size);
} }
static int static int
ext3_xattr_security_set(struct inode *inode, const char *name, ext3_xattr_security_set(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
return ext3_xattr_set(inode, EXT3_XATTR_INDEX_SECURITY, name, return ext3_xattr_set(dentry->d_inode, EXT3_XATTR_INDEX_SECURITY,
value, size, flags); name, value, size, flags);
} }
int int

View file

@ -14,8 +14,8 @@
#include "xattr.h" #include "xattr.h"
static size_t static size_t
ext3_xattr_trusted_list(struct inode *inode, char *list, size_t list_size, ext3_xattr_trusted_list(struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len) const char *name, size_t name_len, int type)
{ {
const size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN; const size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN;
const size_t total_len = prefix_len + name_len + 1; 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 static int
ext3_xattr_trusted_get(struct inode *inode, const char *name, ext3_xattr_trusted_get(struct dentry *dentry, const char *name,
void *buffer, size_t size) void *buffer, size_t size, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
return ext3_xattr_get(inode, EXT3_XATTR_INDEX_TRUSTED, name, return ext3_xattr_get(dentry->d_inode, EXT3_XATTR_INDEX_TRUSTED,
buffer, size); name, buffer, size);
} }
static int static int
ext3_xattr_trusted_set(struct inode *inode, const char *name, ext3_xattr_trusted_set(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; 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); value, size, flags);
} }

View file

@ -13,13 +13,13 @@
#include "xattr.h" #include "xattr.h"
static size_t static size_t
ext3_xattr_user_list(struct inode *inode, char *list, size_t list_size, ext3_xattr_user_list(struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len) const char *name, size_t name_len, int type)
{ {
const size_t prefix_len = XATTR_USER_PREFIX_LEN; const size_t prefix_len = XATTR_USER_PREFIX_LEN;
const size_t total_len = prefix_len + name_len + 1; 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; return 0;
if (list && total_len <= list_size) { 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 static int
ext3_xattr_user_get(struct inode *inode, const char *name, ext3_xattr_user_get(struct dentry *dentry, const char *name, void *buffer,
void *buffer, size_t size) size_t size, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
if (!test_opt(inode->i_sb, XATTR_USER)) if (!test_opt(dentry->d_sb, XATTR_USER))
return -EOPNOTSUPP; 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 static int
ext3_xattr_user_set(struct inode *inode, const char *name, ext3_xattr_user_set(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
if (!test_opt(inode->i_sb, XATTR_USER)) if (!test_opt(dentry->d_sb, XATTR_USER))
return -EOPNOTSUPP; return -EOPNOTSUPP;
return ext3_xattr_set(inode, EXT3_XATTR_INDEX_USER, name, return ext3_xattr_set(dentry->d_inode, EXT3_XATTR_INDEX_USER,
value, size, flags); name, value, size, flags);
} }
struct xattr_handler ext3_xattr_user_handler = { struct xattr_handler ext3_xattr_user_handler = {

View file

@ -364,12 +364,12 @@ out:
* Extended attribute handlers * Extended attribute handlers
*/ */
static size_t static size_t
ext4_xattr_list_acl_access(struct inode *inode, char *list, size_t list_len, ext4_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_len,
const char *name, size_t name_len) const char *name, size_t name_len, int type)
{ {
const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); 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; return 0;
if (list && size <= list_len) if (list && size <= list_len)
memcpy(list, POSIX_ACL_XATTR_ACCESS, size); 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 static size_t
ext4_xattr_list_acl_default(struct inode *inode, char *list, size_t list_len, ext4_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_len,
const char *name, size_t name_len) const char *name, size_t name_len, int type)
{ {
const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); 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; return 0;
if (list && size <= list_len) if (list && size <= list_len)
memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); 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 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; struct posix_acl *acl;
int error; 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; return -EOPNOTSUPP;
acl = ext4_get_acl(inode, type); acl = ext4_get_acl(dentry->d_inode, type);
if (IS_ERR(acl)) if (IS_ERR(acl))
return PTR_ERR(acl); return PTR_ERR(acl);
if (acl == NULL) if (acl == NULL)
@ -410,31 +413,16 @@ ext4_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
} }
static int static int
ext4_xattr_get_acl_access(struct inode *inode, const char *name, ext4_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
void *buffer, size_t size) size_t size, int flags, int type)
{
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)
{ {
struct inode *inode = dentry->d_inode;
handle_t *handle; handle_t *handle;
struct posix_acl *acl; struct posix_acl *acl;
int error, retries = 0; int error, retries = 0;
if (strcmp(name, "") != 0)
return -EINVAL;
if (!test_opt(inode->i_sb, POSIX_ACL)) if (!test_opt(inode->i_sb, POSIX_ACL))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (!is_owner_or_cap(inode)) if (!is_owner_or_cap(inode))
@ -466,34 +454,18 @@ release_and_out:
return error; 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 = { struct xattr_handler ext4_xattr_acl_access_handler = {
.prefix = POSIX_ACL_XATTR_ACCESS, .prefix = POSIX_ACL_XATTR_ACCESS,
.flags = ACL_TYPE_ACCESS,
.list = ext4_xattr_list_acl_access, .list = ext4_xattr_list_acl_access,
.get = ext4_xattr_get_acl_access, .get = ext4_xattr_get_acl,
.set = ext4_xattr_set_acl_access, .set = ext4_xattr_set_acl,
}; };
struct xattr_handler ext4_xattr_acl_default_handler = { struct xattr_handler ext4_xattr_acl_default_handler = {
.prefix = POSIX_ACL_XATTR_DEFAULT, .prefix = POSIX_ACL_XATTR_DEFAULT,
.flags = ACL_TYPE_DEFAULT,
.list = ext4_xattr_list_acl_default, .list = ext4_xattr_list_acl_default,
.get = ext4_xattr_get_acl_default, .get = ext4_xattr_get_acl,
.set = ext4_xattr_set_acl_default, .set = ext4_xattr_set_acl,
}; };

View file

@ -92,7 +92,7 @@ static struct buffer_head *ext4_xattr_cache_find(struct inode *,
struct mb_cache_entry **); struct mb_cache_entry **);
static void ext4_xattr_rehash(struct ext4_xattr_header *, static void ext4_xattr_rehash(struct ext4_xattr_header *,
struct ext4_xattr_entry *); 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); size_t buffer_size);
static struct mb_cache *ext4_xattr_cache; static struct mb_cache *ext4_xattr_cache;
@ -140,7 +140,7 @@ ext4_xattr_handler(int name_index)
ssize_t ssize_t
ext4_listxattr(struct dentry *dentry, char *buffer, size_t size) 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 static int
@ -325,7 +325,7 @@ ext4_xattr_get(struct inode *inode, int name_index, const char *name,
} }
static int 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) char *buffer, size_t buffer_size)
{ {
size_t rest = 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); ext4_xattr_handler(entry->e_name_index);
if (handler) { if (handler) {
size_t size = handler->list(inode, buffer, rest, size_t size = handler->list(dentry, buffer, rest,
entry->e_name, entry->e_name,
entry->e_name_len); entry->e_name_len,
handler->flags);
if (buffer) { if (buffer) {
if (size > rest) if (size > rest)
return -ERANGE; return -ERANGE;
@ -350,8 +351,9 @@ ext4_xattr_list_entries(struct inode *inode, struct ext4_xattr_entry *entry,
} }
static int 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; struct buffer_head *bh = NULL;
int error; int error;
@ -376,7 +378,7 @@ ext4_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
goto cleanup; goto cleanup;
} }
ext4_xattr_cache_insert(bh); 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: cleanup:
brelse(bh); brelse(bh);
@ -385,8 +387,9 @@ cleanup:
} }
static int 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_xattr_ibody_header *header;
struct ext4_inode *raw_inode; struct ext4_inode *raw_inode;
struct ext4_iloc iloc; 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); error = ext4_xattr_check_names(IFIRST(header), end);
if (error) if (error)
goto cleanup; goto cleanup;
error = ext4_xattr_list_entries(inode, IFIRST(header), error = ext4_xattr_list_entries(dentry, IFIRST(header),
buffer, buffer_size); buffer, buffer_size);
cleanup: cleanup:
@ -423,12 +426,12 @@ cleanup:
* used / required on success. * used / required on success.
*/ */
static int 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; int i_error, b_error;
down_read(&EXT4_I(inode)->xattr_sem); down_read(&EXT4_I(dentry->d_inode)->xattr_sem);
i_error = ext4_xattr_ibody_list(inode, buffer, buffer_size); i_error = ext4_xattr_ibody_list(dentry, buffer, buffer_size);
if (i_error < 0) { if (i_error < 0) {
b_error = 0; b_error = 0;
} else { } else {
@ -436,11 +439,11 @@ ext4_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
buffer += i_error; buffer += i_error;
buffer_size -= 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) if (b_error < 0)
i_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; return i_error + b_error;
} }

View file

@ -12,8 +12,8 @@
#include "xattr.h" #include "xattr.h"
static size_t static size_t
ext4_xattr_security_list(struct inode *inode, char *list, size_t list_size, ext4_xattr_security_list(struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len) const char *name, size_t name_len, int type)
{ {
const size_t prefix_len = sizeof(XATTR_SECURITY_PREFIX)-1; const size_t prefix_len = sizeof(XATTR_SECURITY_PREFIX)-1;
const size_t total_len = prefix_len + name_len + 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 static int
ext4_xattr_security_get(struct inode *inode, const char *name, ext4_xattr_security_get(struct dentry *dentry, const char *name,
void *buffer, size_t size) void *buffer, size_t size, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
return ext4_xattr_get(inode, EXT4_XATTR_INDEX_SECURITY, name, return ext4_xattr_get(dentry->d_inode, EXT4_XATTR_INDEX_SECURITY,
buffer, size); name, buffer, size);
} }
static int static int
ext4_xattr_security_set(struct inode *inode, const char *name, ext4_xattr_security_set(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
return ext4_xattr_set(inode, EXT4_XATTR_INDEX_SECURITY, name, return ext4_xattr_set(dentry->d_inode, EXT4_XATTR_INDEX_SECURITY,
value, size, flags); name, value, size, flags);
} }
int int

View file

@ -14,8 +14,8 @@
#include "xattr.h" #include "xattr.h"
static size_t static size_t
ext4_xattr_trusted_list(struct inode *inode, char *list, size_t list_size, ext4_xattr_trusted_list(struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len) const char *name, size_t name_len, int type)
{ {
const size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN; const size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN;
const size_t total_len = prefix_len + name_len + 1; 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 static int
ext4_xattr_trusted_get(struct inode *inode, const char *name, ext4_xattr_trusted_get(struct dentry *dentry, const char *name, void *buffer,
void *buffer, size_t size) size_t size, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
return ext4_xattr_get(inode, EXT4_XATTR_INDEX_TRUSTED, name, return ext4_xattr_get(dentry->d_inode, EXT4_XATTR_INDEX_TRUSTED,
buffer, size); name, buffer, size);
} }
static int static int
ext4_xattr_trusted_set(struct inode *inode, const char *name, ext4_xattr_trusted_set(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
return ext4_xattr_set(inode, EXT4_XATTR_INDEX_TRUSTED, name, return ext4_xattr_set(dentry->d_inode, EXT4_XATTR_INDEX_TRUSTED,
value, size, flags); name, value, size, flags);
} }
struct xattr_handler ext4_xattr_trusted_handler = { struct xattr_handler ext4_xattr_trusted_handler = {

View file

@ -13,13 +13,13 @@
#include "xattr.h" #include "xattr.h"
static size_t static size_t
ext4_xattr_user_list(struct inode *inode, char *list, size_t list_size, ext4_xattr_user_list(struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len) const char *name, size_t name_len, int type)
{ {
const size_t prefix_len = XATTR_USER_PREFIX_LEN; const size_t prefix_len = XATTR_USER_PREFIX_LEN;
const size_t total_len = prefix_len + name_len + 1; 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; return 0;
if (list && total_len <= list_size) { 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 static int
ext4_xattr_user_get(struct inode *inode, const char *name, ext4_xattr_user_get(struct dentry *dentry, const char *name,
void *buffer, size_t size) void *buffer, size_t size, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
if (!test_opt(inode->i_sb, XATTR_USER)) if (!test_opt(dentry->d_sb, XATTR_USER))
return -EOPNOTSUPP; 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 static int
ext4_xattr_user_set(struct inode *inode, const char *name, ext4_xattr_user_set(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
if (!test_opt(inode->i_sb, XATTR_USER)) if (!test_opt(dentry->d_sb, XATTR_USER))
return -EOPNOTSUPP; return -EOPNOTSUPP;
return ext4_xattr_set(inode, EXT4_XATTR_INDEX_USER, name, return ext4_xattr_set(dentry->d_inode, EXT4_XATTR_INDEX_USER,
value, size, flags); name, value, size, flags);
} }
struct xattr_handler ext4_xattr_user_handler = { struct xattr_handler ext4_xattr_user_handler = {

View file

@ -21,9 +21,12 @@
#include <linux/fsnotify.h> #include <linux/fsnotify.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
#include <linux/percpu_counter.h> #include <linux/percpu_counter.h>
#include <linux/ima.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include "internal.h"
/* sysctl tunables... */ /* sysctl tunables... */
struct files_stat_struct files_stat = { struct files_stat_struct files_stat = {
.max_files = NR_FILE .max_files = NR_FILE
@ -147,8 +150,6 @@ fail:
return NULL; return NULL;
} }
EXPORT_SYMBOL(get_empty_filp);
/** /**
* alloc_file - allocate and initialize a 'struct file' * alloc_file - allocate and initialize a 'struct file'
* @mnt: the vfsmount on which the file will reside * @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 * If all the callers of init_file() are eliminated, its
* code should be moved into this function. * code should be moved into this function.
*/ */
struct file *alloc_file(struct vfsmount *mnt, struct dentry *dentry, struct file *alloc_file(struct path *path, fmode_t mode,
fmode_t mode, const struct file_operations *fop) const struct file_operations *fop)
{ {
struct file *file; struct file *file;
@ -173,35 +174,8 @@ struct file *alloc_file(struct vfsmount *mnt, struct dentry *dentry,
if (!file) if (!file)
return NULL; return NULL;
init_file(file, mnt, dentry, mode, fop); file->f_path = *path;
return file; file->f_mapping = path->dentry->d_inode->i_mapping;
}
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_mode = mode; file->f_mode = mode;
file->f_op = fop; 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 * visible. We do this for consistency, and so
* that we can do debugging checks at __fput() * 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); file_take_write(file);
error = mnt_clone_write(mnt); error = mnt_clone_write(path->mnt);
WARN_ON(error); WARN_ON(error);
} }
return error; ima_counts_get(file);
return file;
} }
EXPORT_SYMBOL(init_file);
void fput(struct file *file) void fput(struct file *file)
{ {

View file

@ -1,62 +1,58 @@
/* /*
* fs/generic_acl.c
*
* (C) 2005 Andreas Gruenbacher <agruen@suse.de> * (C) 2005 Andreas Gruenbacher <agruen@suse.de>
* *
* This file is released under the GPL. * This file is released under the GPL.
*
* Generic ACL support for in-memory filesystems.
*/ */
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/generic_acl.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 static size_t
* @ops: Filesystem specific getacl and setacl callbacks generic_acl_list(struct dentry *dentry, char *list, size_t list_size,
*/ const char *name, size_t name_len, int type)
size_t
generic_acl_list(struct inode *inode, struct generic_acl_operations *ops,
int type, char *list, size_t list_size)
{ {
struct posix_acl *acl; struct posix_acl *acl;
const char *name; const char *xname;
size_t size; size_t size;
acl = ops->getacl(inode, type); acl = get_cached_acl(dentry->d_inode, type);
if (!acl) if (!acl)
return 0; return 0;
posix_acl_release(acl); posix_acl_release(acl);
switch(type) { switch (type) {
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
name = POSIX_ACL_XATTR_ACCESS; xname = POSIX_ACL_XATTR_ACCESS;
break; break;
case ACL_TYPE_DEFAULT: case ACL_TYPE_DEFAULT:
name = POSIX_ACL_XATTR_DEFAULT; xname = POSIX_ACL_XATTR_DEFAULT;
break; break;
default: default:
return 0; return 0;
} }
size = strlen(name) + 1; size = strlen(xname) + 1;
if (list && size <= list_size) if (list && size <= list_size)
memcpy(list, name, size); memcpy(list, xname, size);
return size; return size;
} }
/** static int
* generic_acl_get - Generic xattr_handler->get() operation generic_acl_get(struct dentry *dentry, const char *name, void *buffer,
* @ops: Filesystem specific getacl and setacl callbacks size_t size, int type)
*/
int
generic_acl_get(struct inode *inode, struct generic_acl_operations *ops,
int type, void *buffer, size_t size)
{ {
struct posix_acl *acl; struct posix_acl *acl;
int error; int error;
acl = ops->getacl(inode, type); if (strcmp(name, "") != 0)
return -EINVAL;
acl = get_cached_acl(dentry->d_inode, type);
if (!acl) if (!acl)
return -ENODATA; return -ENODATA;
error = posix_acl_to_xattr(acl, buffer, size); 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; return error;
} }
/** static int
* generic_acl_set - Generic xattr_handler->set() operation generic_acl_set(struct dentry *dentry, const char *name, const void *value,
* @ops: Filesystem specific getacl and setacl callbacks size_t size, int flags, int type)
*/
int
generic_acl_set(struct inode *inode, struct generic_acl_operations *ops,
int type, const void *value, size_t size)
{ {
struct inode *inode = dentry->d_inode;
struct posix_acl *acl = NULL; struct posix_acl *acl = NULL;
int error; int error;
if (strcmp(name, "") != 0)
return -EINVAL;
if (S_ISLNK(inode->i_mode)) if (S_ISLNK(inode->i_mode))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (!is_owner_or_cap(inode)) if (!is_owner_or_cap(inode))
@ -91,7 +86,7 @@ generic_acl_set(struct inode *inode, struct generic_acl_operations *ops,
error = posix_acl_valid(acl); error = posix_acl_valid(acl);
if (error) if (error)
goto failed; goto failed;
switch(type) { switch (type) {
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
mode = inode->i_mode; mode = inode->i_mode;
error = posix_acl_equiv_mode(acl, &mode); error = posix_acl_equiv_mode(acl, &mode);
@ -103,7 +98,6 @@ generic_acl_set(struct inode *inode, struct generic_acl_operations *ops,
acl = NULL; acl = NULL;
} }
break; break;
case ACL_TYPE_DEFAULT: case ACL_TYPE_DEFAULT:
if (!S_ISDIR(inode->i_mode)) { if (!S_ISDIR(inode->i_mode)) {
error = -EINVAL; error = -EINVAL;
@ -112,7 +106,7 @@ generic_acl_set(struct inode *inode, struct generic_acl_operations *ops,
break; break;
} }
} }
ops->setacl(inode, type, acl); set_cached_acl(inode, type, acl);
error = 0; error = 0;
failed: failed:
posix_acl_release(acl); posix_acl_release(acl);
@ -121,14 +115,12 @@ failed:
/** /**
* generic_acl_init - Take care of acl inheritance at @inode create time * 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 * Files created inside a directory with a default ACL inherit the
* directory's default ACL. * directory's default ACL.
*/ */
int int
generic_acl_init(struct inode *inode, struct inode *dir, generic_acl_init(struct inode *inode, struct inode *dir)
struct generic_acl_operations *ops)
{ {
struct posix_acl *acl = NULL; struct posix_acl *acl = NULL;
mode_t mode = inode->i_mode; 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(); inode->i_mode = mode & ~current_umask();
if (!S_ISLNK(inode->i_mode)) if (!S_ISLNK(inode->i_mode))
acl = ops->getacl(dir, ACL_TYPE_DEFAULT); acl = get_cached_acl(dir, ACL_TYPE_DEFAULT);
if (acl) { if (acl) {
struct posix_acl *clone; struct posix_acl *clone;
@ -145,7 +137,7 @@ generic_acl_init(struct inode *inode, struct inode *dir,
error = -ENOMEM; error = -ENOMEM;
if (!clone) if (!clone)
goto cleanup; goto cleanup;
ops->setacl(inode, ACL_TYPE_DEFAULT, clone); set_cached_acl(inode, ACL_TYPE_DEFAULT, clone);
posix_acl_release(clone); posix_acl_release(clone);
} }
clone = posix_acl_clone(acl, GFP_KERNEL); clone = posix_acl_clone(acl, GFP_KERNEL);
@ -156,7 +148,7 @@ generic_acl_init(struct inode *inode, struct inode *dir,
if (error >= 0) { if (error >= 0) {
inode->i_mode = mode; inode->i_mode = mode;
if (error > 0) if (error > 0)
ops->setacl(inode, ACL_TYPE_ACCESS, clone); set_cached_acl(inode, ACL_TYPE_ACCESS, clone);
} }
posix_acl_release(clone); posix_acl_release(clone);
} }
@ -169,20 +161,19 @@ cleanup:
/** /**
* generic_acl_chmod - change the access acl of @inode upon chmod() * 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 * A chmod also changes the permissions of the owner, group/mask, and
* other ACL entries. * other ACL entries.
*/ */
int int
generic_acl_chmod(struct inode *inode, struct generic_acl_operations *ops) generic_acl_chmod(struct inode *inode)
{ {
struct posix_acl *acl, *clone; struct posix_acl *acl, *clone;
int error = 0; int error = 0;
if (S_ISLNK(inode->i_mode)) if (S_ISLNK(inode->i_mode))
return -EOPNOTSUPP; return -EOPNOTSUPP;
acl = ops->getacl(inode, ACL_TYPE_ACCESS); acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
if (acl) { if (acl) {
clone = posix_acl_clone(acl, GFP_KERNEL); clone = posix_acl_clone(acl, GFP_KERNEL);
posix_acl_release(acl); posix_acl_release(acl);
@ -190,8 +181,37 @@ generic_acl_chmod(struct inode *inode, struct generic_acl_operations *ops)
return -ENOMEM; return -ENOMEM;
error = posix_acl_chmod_masq(clone, inode->i_mode); error = posix_acl_chmod_masq(clone, inode->i_mode);
if (!error) if (!error)
ops->setacl(inode, ACL_TYPE_ACCESS, clone); set_cached_acl(inode, ACL_TYPE_ACCESS, clone);
posix_acl_release(clone); posix_acl_release(clone);
} }
return error; 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,
};

View file

@ -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); error = posix_acl_to_xattr(acl, data, len);
if (error < 0) if (error < 0)
goto out; 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) if (!error)
set_cached_acl(inode, type, acl); set_cached_acl(inode, type, acl);
out: out:
@ -232,9 +232,10 @@ static int gfs2_acl_type(const char *name)
return -EINVAL; return -EINVAL;
} }
static int gfs2_xattr_system_get(struct inode *inode, const char *name, static int gfs2_xattr_system_get(struct dentry *dentry, const char *name,
void *buffer, size_t size) void *buffer, size_t size, int xtype)
{ {
struct inode *inode = dentry->d_inode;
struct posix_acl *acl; struct posix_acl *acl;
int type; int type;
int error; int error;
@ -255,9 +256,11 @@ static int gfs2_xattr_system_get(struct inode *inode, const char *name,
return error; return error;
} }
static int gfs2_xattr_system_set(struct inode *inode, const char *name, static int gfs2_xattr_system_set(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags,
int xtype)
{ {
struct inode *inode = dentry->d_inode;
struct gfs2_sbd *sdp = GFS2_SB(inode); struct gfs2_sbd *sdp = GFS2_SB(inode);
struct posix_acl *acl = NULL; struct posix_acl *acl = NULL;
int error = 0, type; int error = 0, type;
@ -319,7 +322,7 @@ static int gfs2_xattr_system_set(struct inode *inode, const char *name,
} }
set_acl: 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 (!error) {
if (acl) if (acl)
set_cached_acl(inode, type, acl); set_cached_acl(inode, type, acl);
@ -334,6 +337,7 @@ out:
struct xattr_handler gfs2_xattr_system_handler = { struct xattr_handler gfs2_xattr_system_handler = {
.prefix = XATTR_SYSTEM_PREFIX, .prefix = XATTR_SYSTEM_PREFIX,
.flags = GFS2_EATYPE_SYS,
.get = gfs2_xattr_system_get, .get = gfs2_xattr_system_get,
.set = gfs2_xattr_system_set, .set = gfs2_xattr_system_set,
}; };

View file

@ -801,7 +801,8 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip)
return err; 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(value);
kfree(name); kfree(name);

View file

@ -567,18 +567,17 @@ out:
/** /**
* gfs2_xattr_get - Get a GFS2 extended attribute * gfs2_xattr_get - Get a GFS2 extended attribute
* @inode: The inode * @inode: The inode
* @type: The type of extended attribute
* @name: The name of the extended attribute * @name: The name of the extended attribute
* @buffer: The buffer to write the result into * @buffer: The buffer to write the result into
* @size: The size of the buffer * @size: The size of the buffer
* @type: The type of extended attribute
* *
* Returns: actual size of data on success, -errno on error * Returns: actual size of data on success, -errno on error
*/ */
static int gfs2_xattr_get(struct dentry *dentry, const char *name,
int gfs2_xattr_get(struct inode *inode, int type, const char *name, void *buffer, size_t size, int type)
void *buffer, size_t size)
{ {
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
struct gfs2_ea_location el; struct gfs2_ea_location el;
int error; 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 * gfs2_xattr_remove - Remove a GFS2 extended attribute
* @inode: The inode * @ip: The inode
* @type: The type of the extended attribute * @type: The type of the extended attribute
* @name: The name 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 * 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; struct gfs2_ea_location el;
int error; 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 * __gfs2_xattr_set - Set (or 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 * @name: The name of the extended attribute
* @value: The value of the extended attribute (NULL for remove) * @value: The value of the extended attribute (NULL for remove)
* @size: The size of the @value argument * @size: The size of the @value argument
* @flags: Create or Replace * @flags: Create or Replace
* @type: The type of the extended attribute
* *
* See gfs2_xattr_remove() for details of the removal of xattrs. * See gfs2_xattr_remove() for details of the removal of xattrs.
* *
* Returns: 0 or errno on failure * Returns: 0 or errno on failure
*/ */
int gfs2_xattr_set(struct inode *inode, int type, const char *name, int __gfs2_xattr_set(struct inode *inode, const char *name,
const void *value, size_t size, int flags) 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_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
struct gfs2_ea_location el; struct gfs2_ea_location el;
unsigned int namel = strlen(name); unsigned int namel = strlen(name);
int error; int error;
@ -1184,7 +1182,7 @@ int gfs2_xattr_set(struct inode *inode, int type, const char *name,
return -ERANGE; return -ERANGE;
if (value == NULL) if (value == NULL)
return gfs2_xattr_remove(inode, type, name); return gfs2_xattr_remove(ip, type, name);
if (ea_check_size(sdp, namel, size)) if (ea_check_size(sdp, namel, size))
return -ERANGE; return -ERANGE;
@ -1224,6 +1222,13 @@ int gfs2_xattr_set(struct inode *inode, int type, const char *name,
return error; 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, static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip,
struct gfs2_ea_header *ea, char *data) struct gfs2_ea_header *ea, char *data)
{ {
@ -1529,40 +1534,18 @@ out_alloc:
return error; 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 = { static struct xattr_handler gfs2_xattr_user_handler = {
.prefix = XATTR_USER_PREFIX, .prefix = XATTR_USER_PREFIX,
.get = gfs2_xattr_user_get, .flags = GFS2_EATYPE_USR,
.set = gfs2_xattr_user_set, .get = gfs2_xattr_get,
.set = gfs2_xattr_set,
}; };
static struct xattr_handler gfs2_xattr_security_handler = { static struct xattr_handler gfs2_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX, .prefix = XATTR_SECURITY_PREFIX,
.get = gfs2_xattr_security_get, .flags = GFS2_EATYPE_SECURITY,
.set = gfs2_xattr_security_set, .get = gfs2_xattr_get,
.set = gfs2_xattr_set,
}; };
struct xattr_handler *gfs2_xattr_handlers[] = { struct xattr_handler *gfs2_xattr_handlers[] = {

View file

@ -53,10 +53,9 @@ struct gfs2_ea_location {
struct gfs2_ea_header *el_prev; struct gfs2_ea_header *el_prev;
}; };
extern int gfs2_xattr_get(struct inode *inode, int type, const char *name, extern int __gfs2_xattr_set(struct inode *inode, const char *name,
void *buffer, size_t size); const void *value, size_t size,
extern int gfs2_xattr_set(struct inode *inode, int type, const char *name, int flags, int type);
const void *value, size_t size, int flags);
extern ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size); extern ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size);
extern int gfs2_ea_dealloc(struct gfs2_inode *ip); extern int gfs2_ea_dealloc(struct gfs2_inode *ip);

View file

@ -30,7 +30,6 @@
#include <linux/dnotify.h> #include <linux/dnotify.h>
#include <linux/statfs.h> #include <linux/statfs.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/ima.h>
#include <linux/magic.h> #include <linux/magic.h>
#include <asm/uaccess.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; int error = -ENOMEM;
struct file *file; struct file *file;
struct inode *inode; struct inode *inode;
struct dentry *dentry, *root; struct path path;
struct dentry *root;
struct qstr quick_string; struct qstr quick_string;
*user = NULL; *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.name = name;
quick_string.len = strlen(quick_string.name); quick_string.len = strlen(quick_string.name);
quick_string.hash = 0; quick_string.hash = 0;
dentry = d_alloc(root, &quick_string); path.dentry = d_alloc(root, &quick_string);
if (!dentry) if (!path.dentry)
goto out_shm_unlock; goto out_shm_unlock;
path.mnt = mntget(hugetlbfs_vfsmount);
error = -ENOSPC; error = -ENOSPC;
inode = hugetlbfs_get_inode(root->d_sb, current_fsuid(), inode = hugetlbfs_get_inode(root->d_sb, current_fsuid(),
current_fsgid(), S_IFREG | S_IRWXUGO, 0); 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)) acctflag))
goto out_inode; goto out_inode;
d_instantiate(dentry, inode); d_instantiate(path.dentry, inode);
inode->i_size = size; inode->i_size = size;
inode->i_nlink = 0; inode->i_nlink = 0;
error = -ENFILE; error = -ENFILE;
file = alloc_file(hugetlbfs_vfsmount, dentry, file = alloc_file(&path, FMODE_WRITE | FMODE_READ,
FMODE_WRITE | FMODE_READ,
&hugetlbfs_file_operations); &hugetlbfs_file_operations);
if (!file) if (!file)
goto out_dentry; /* inode is already attached */ goto out_dentry; /* inode is already attached */
ima_counts_get(file);
return file; return file;
out_inode: out_inode:
iput(inode); iput(inode);
out_dentry: out_dentry:
dput(dentry); path_put(&path);
out_shm_unlock: out_shm_unlock:
if (*user) { if (*user) {
user_shm_unlock(size, *user); user_shm_unlock(size, *user);

View file

@ -79,6 +79,7 @@ extern void chroot_fs_refs(struct path *, struct path *);
* file_table.c * file_table.c
*/ */
extern void mark_files_ro(struct super_block *); extern void mark_files_ro(struct super_block *);
extern struct file *get_empty_filp(void);
/* /*
* super.c * super.c

View file

@ -350,8 +350,8 @@ int jffs2_acl_chmod(struct inode *inode)
return rc; return rc;
} }
static size_t jffs2_acl_access_listxattr(struct inode *inode, char *list, size_t list_size, static size_t jffs2_acl_access_listxattr(struct dentry *dentry, char *list,
const char *name, size_t name_len) size_t list_size, const char *name, size_t name_len, int type)
{ {
const int retlen = sizeof(POSIX_ACL_XATTR_ACCESS); 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; return retlen;
} }
static size_t jffs2_acl_default_listxattr(struct inode *inode, char *list, size_t list_size, static size_t jffs2_acl_default_listxattr(struct dentry *dentry, char *list,
const char *name, size_t name_len) size_t list_size, const char *name, size_t name_len, int type)
{ {
const int retlen = sizeof(POSIX_ACL_XATTR_DEFAULT); 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; 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; struct posix_acl *acl;
int rc; 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)) if (IS_ERR(acl))
return PTR_ERR(acl); return PTR_ERR(acl);
if (!acl) if (!acl)
@ -386,26 +390,15 @@ static int jffs2_acl_getxattr(struct inode *inode, int type, void *buffer, size_
return rc; return rc;
} }
static int jffs2_acl_access_getxattr(struct inode *inode, const char *name, void *buffer, size_t size) static int jffs2_acl_setxattr(struct dentry *dentry, const char *name,
{ const void *value, size_t size, int flags, int type)
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)
{ {
struct posix_acl *acl; struct posix_acl *acl;
int rc; int rc;
if (!is_owner_or_cap(inode)) if (name[0] != '\0')
return -EINVAL;
if (!is_owner_or_cap(dentry->d_inode))
return -EPERM; return -EPERM;
if (value) { if (value) {
@ -420,38 +413,24 @@ static int jffs2_acl_setxattr(struct inode *inode, int type, const void *value,
} else { } else {
acl = NULL; acl = NULL;
} }
rc = jffs2_set_acl(inode, type, acl); rc = jffs2_set_acl(dentry->d_inode, type, acl);
out: out:
posix_acl_release(acl); posix_acl_release(acl);
return rc; 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 = { struct xattr_handler jffs2_acl_access_xattr_handler = {
.prefix = POSIX_ACL_XATTR_ACCESS, .prefix = POSIX_ACL_XATTR_ACCESS,
.flags = ACL_TYPE_DEFAULT,
.list = jffs2_acl_access_listxattr, .list = jffs2_acl_access_listxattr,
.get = jffs2_acl_access_getxattr, .get = jffs2_acl_getxattr,
.set = jffs2_acl_access_setxattr, .set = jffs2_acl_setxattr,
}; };
struct xattr_handler jffs2_acl_default_xattr_handler = { struct xattr_handler jffs2_acl_default_xattr_handler = {
.prefix = POSIX_ACL_XATTR_DEFAULT, .prefix = POSIX_ACL_XATTR_DEFAULT,
.flags = ACL_TYPE_DEFAULT,
.list = jffs2_acl_default_listxattr, .list = jffs2_acl_default_listxattr,
.get = jffs2_acl_default_getxattr, .get = jffs2_acl_getxattr,
.set = jffs2_acl_default_setxattr, .set = jffs2_acl_setxattr,
}; };

View file

@ -44,26 +44,28 @@ int jffs2_init_security(struct inode *inode, struct inode *dir)
} }
/* ---- XATTR Handler for "security.*" ----------------- */ /* ---- XATTR Handler for "security.*" ----------------- */
static int jffs2_security_getxattr(struct inode *inode, const char *name, static int jffs2_security_getxattr(struct dentry *dentry, const char *name,
void *buffer, size_t size) void *buffer, size_t size, int type)
{ {
if (!strcmp(name, "")) if (!strcmp(name, ""))
return -EINVAL; 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, static int jffs2_security_setxattr(struct dentry *dentry, const char *name,
size_t size, int flags) const void *buffer, size_t size, int flags, int type)
{ {
if (!strcmp(name, "")) if (!strcmp(name, ""))
return -EINVAL; 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, static size_t jffs2_security_listxattr(struct dentry *dentry, char *list,
const char *name, size_t name_len) size_t list_size, const char *name, size_t name_len, int type)
{ {
size_t retlen = XATTR_SECURITY_PREFIX_LEN + name_len + 1; size_t retlen = XATTR_SECURITY_PREFIX_LEN + name_len + 1;

View file

@ -990,9 +990,11 @@ ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
if (!xhandle) if (!xhandle)
continue; continue;
if (buffer) { 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 { } 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) if (rc < 0)
goto out; goto out;

View file

@ -16,24 +16,26 @@
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include "nodelist.h" #include "nodelist.h"
static int jffs2_trusted_getxattr(struct inode *inode, const char *name, static int jffs2_trusted_getxattr(struct dentry *dentry, const char *name,
void *buffer, size_t size) void *buffer, size_t size, int type)
{ {
if (!strcmp(name, "")) if (!strcmp(name, ""))
return -EINVAL; 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, static int jffs2_trusted_setxattr(struct dentry *dentry, const char *name,
size_t size, int flags) const void *buffer, size_t size, int flags, int type)
{ {
if (!strcmp(name, "")) if (!strcmp(name, ""))
return -EINVAL; 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, static size_t jffs2_trusted_listxattr(struct dentry *dentry, char *list,
const char *name, size_t name_len) size_t list_size, const char *name, size_t name_len, int type)
{ {
size_t retlen = XATTR_TRUSTED_PREFIX_LEN + name_len + 1; size_t retlen = XATTR_TRUSTED_PREFIX_LEN + name_len + 1;

View file

@ -16,24 +16,26 @@
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include "nodelist.h" #include "nodelist.h"
static int jffs2_user_getxattr(struct inode *inode, const char *name, static int jffs2_user_getxattr(struct dentry *dentry, const char *name,
void *buffer, size_t size) void *buffer, size_t size, int type)
{ {
if (!strcmp(name, "")) if (!strcmp(name, ""))
return -EINVAL; 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, static int jffs2_user_setxattr(struct dentry *dentry, const char *name,
size_t size, int flags) const void *buffer, size_t size, int flags, int type)
{ {
if (!strcmp(name, "")) if (!strcmp(name, ""))
return -EINVAL; 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, static size_t jffs2_user_listxattr(struct dentry *dentry, char *list,
const char *name, size_t name_len) size_t list_size, const char *name, size_t name_len, int type)
{ {
size_t retlen = XATTR_USER_PREFIX_LEN + name_len + 1; size_t retlen = XATTR_USER_PREFIX_LEN + name_len + 1;

View file

@ -848,7 +848,6 @@ EXPORT_SYMBOL(simple_write_end);
EXPORT_SYMBOL(simple_dir_inode_operations); EXPORT_SYMBOL(simple_dir_inode_operations);
EXPORT_SYMBOL(simple_dir_operations); EXPORT_SYMBOL(simple_dir_operations);
EXPORT_SYMBOL(simple_empty); EXPORT_SYMBOL(simple_empty);
EXPORT_SYMBOL(d_alloc_name);
EXPORT_SYMBOL(simple_fill_super); EXPORT_SYMBOL(simple_fill_super);
EXPORT_SYMBOL(simple_getattr); EXPORT_SYMBOL(simple_getattr);
EXPORT_SYMBOL(simple_link); EXPORT_SYMBOL(simple_link);

View file

@ -35,6 +35,8 @@
#include <linux/fs_struct.h> #include <linux/fs_struct.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "internal.h"
#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
/* [Feb-1997 T. Schoebel-Theuer] /* [Feb-1997 T. Schoebel-Theuer]
@ -108,8 +110,6 @@
* any extra contention... * 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 /* In order to reduce some races, while at the same time doing additional
* checking and hopefully speeding things up, we copy filenames to the * checking and hopefully speeding things up, we copy filenames to the
* kernel data space before using them.. * 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. * force_reval_path - force revalidation of a dentry
* SMP-safe *
* 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) if (!(dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT))
dentry = d_lookup(parent, name); return 0;
if (dentry && dentry->d_op && dentry->d_op->d_revalidate) status = dentry->d_op->d_revalidate(dentry, nd);
dentry = do_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 * Short-cut version of permission(), for calling on directories
* path_walk(), when dcache lock is held. Combines parts * during pathname resolution. Combines parts of permission()
* of permission() and generic_permission(), and tests ONLY for * and generic_permission(), and tests ONLY for MAY_EXEC permission.
* MAY_EXEC permission.
* *
* If appropriate, check DAC only. If not appropriate, or * 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. * complete permission check.
*/ */
static int exec_permission_lite(struct inode *inode) static int exec_permission(struct inode *inode)
{ {
int ret; int ret;
@ -465,99 +484,6 @@ ok:
return security_inode_permission(inode, MAY_EXEC); 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) static __always_inline void set_root(struct nameidata *nd)
{ {
if (!nd->root.mnt) { 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) static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
{ {
int res = 0; int res = 0;
@ -641,11 +569,14 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata
error = 0; error = 0;
if (s) if (s)
error = __vfs_follow_link(nd, 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) if (dentry->d_inode->i_op->put_link)
dentry->d_inode->i_op->put_link(dentry, nd, cookie); dentry->d_inode->i_op->put_link(dentry, nd, cookie);
} }
path_put(path);
return error; return error;
} }
@ -672,6 +603,7 @@ static inline int do_follow_link(struct path *path, struct nameidata *nd)
current->total_link_count++; current->total_link_count++;
nd->depth++; nd->depth++;
err = __do_follow_link(path, nd); err = __do_follow_link(path, nd);
path_put(path);
current->link_count--; current->link_count--;
nd->depth--; nd->depth--;
return err; return err;
@ -797,8 +729,19 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
struct path *path) struct path *path)
{ {
struct vfsmount *mnt = nd->path.mnt; 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) if (!dentry)
goto need_lookup; goto need_lookup;
if (dentry->d_op && dentry->d_op->d_revalidate) if (dentry->d_op && dentry->d_op->d_revalidate)
@ -810,7 +753,59 @@ done:
return 0; return 0;
need_lookup: 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)) if (IS_ERR(dentry))
goto fail; goto fail;
goto done; goto done;
@ -835,7 +830,7 @@ fail:
* Returns 0 and nd will have valid dentry and mnt on success. * Returns 0 and nd will have valid dentry and mnt on success.
* Returns error and drops reference to input namei data on failure. * 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 path next;
struct inode *inode; struct inode *inode;
@ -858,7 +853,7 @@ static int __link_path_walk(const char *name, struct nameidata *nd)
unsigned int c; unsigned int c;
nd->flags |= LOOKUP_CONTINUE; nd->flags |= LOOKUP_CONTINUE;
err = exec_permission_lite(inode); err = exec_permission(inode);
if (err) if (err)
break; break;
@ -898,16 +893,6 @@ static int __link_path_walk(const char *name, struct nameidata *nd)
case 1: case 1:
continue; 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.. */ /* This does the actual lookups.. */
err = do_lookup(nd, &this, &next); err = do_lookup(nd, &this, &next);
if (err) if (err)
@ -953,12 +938,6 @@ last_component:
case 1: case 1:
goto return_reval; 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); err = do_lookup(nd, &this, &next);
if (err) if (err)
break; break;
@ -1017,8 +996,27 @@ return_err:
static int path_walk(const char *name, struct nameidata *nd) static int path_walk(const char *name, struct nameidata *nd)
{ {
struct path save = nd->path;
int result;
current->total_link_count = 0; 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) 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; 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, static struct dentry *__lookup_hash(struct qstr *name,
struct dentry *base, struct nameidata *nd) struct dentry *base, struct nameidata *nd)
{ {
@ -1191,7 +1159,17 @@ static struct dentry *__lookup_hash(struct qstr *name,
goto out; 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) { if (!dentry) {
struct dentry *new; struct dentry *new;
@ -1223,7 +1201,7 @@ static struct dentry *lookup_hash(struct nameidata *nd)
{ {
int err; int err;
err = inode_permission(nd->path.dentry->d_inode, MAY_EXEC); err = exec_permission(nd->path.dentry->d_inode);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
return __lookup_hash(&nd->last, nd->path.dentry, nd); 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) if (err)
return ERR_PTR(err); return ERR_PTR(err);
err = inode_permission(base->d_inode, MAY_EXEC); err = exec_permission(base->d_inode);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
return __lookup_hash(&this, base, NULL); return __lookup_hash(&this, base, NULL);
@ -1511,43 +1489,32 @@ int may_open(struct path *path, int acc_mode, int flag)
if (error) if (error)
return 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. * An append-only file must be opened in append mode for writing.
*/ */
if (IS_APPEND(inode)) { if (IS_APPEND(inode)) {
error = -EPERM;
if ((flag & FMODE_WRITE) && !(flag & O_APPEND)) if ((flag & FMODE_WRITE) && !(flag & O_APPEND))
goto err_out; return -EPERM;
if (flag & O_TRUNC) if (flag & O_TRUNC)
goto err_out; return -EPERM;
} }
/* O_NOATIME can only be set by the owner or superuser */ /* O_NOATIME can only be set by the owner or superuser */
if (flag & O_NOATIME) if (flag & O_NOATIME && !is_owner_or_cap(inode))
if (!is_owner_or_cap(inode)) { return -EPERM;
error = -EPERM;
goto err_out;
}
/* /*
* Ensure there are no outstanding leases on the file. * Ensure there are no outstanding leases on the file.
*/ */
error = break_lease(inode, flag); return break_lease(inode, flag);
if (error) }
goto err_out;
if (flag & O_TRUNC) { static int handle_truncate(struct path *path)
error = get_write_access(inode); {
struct inode *inode = path->dentry->d_inode;
int error = get_write_access(inode);
if (error) if (error)
goto err_out; return error;
/* /*
* Refuse to truncate files with mandatory locks held on them. * Refuse to truncate files with mandatory locks held on them.
*/ */
@ -1556,24 +1523,11 @@ int may_open(struct path *path, int acc_mode, int flag)
error = security_path_truncate(path, 0, error = security_path_truncate(path, 0,
ATTR_MTIME|ATTR_CTIME|ATTR_OPEN); ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
if (!error) { if (!error) {
vfs_dq_init(inode); error = do_truncate(path->dentry, 0,
error = do_truncate(dentry, 0,
ATTR_MTIME|ATTR_CTIME|ATTR_OPEN, ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
NULL); NULL);
} }
put_write_access(inode); 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; return error;
} }
@ -1628,7 +1582,7 @@ static inline int open_to_namei_flags(int flag)
return 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 * 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 file *filp;
struct nameidata nd; struct nameidata nd;
int error; int error;
struct path path; struct path path, save;
struct dentry *dir; struct dentry *dir;
int count = 0; int count = 0;
int will_write; int will_truncate;
int flag = open_to_namei_flags(open_flag); 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. * The simplest case - just a plain lookup.
*/ */
if (!(flag & O_CREAT)) { if (!(flag & O_CREAT)) {
error = path_lookup_open(dfd, pathname, lookup_flags(flag), filp = get_empty_filp();
&nd, flag);
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) if (error)
return ERR_PTR(error); return ERR_PTR(error);
goto ok; goto ok;
@ -1758,13 +1726,17 @@ do_last:
goto exit; goto exit;
} }
filp = nameidata_to_filp(&nd, open_flag); 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); mnt_drop_write(nd.path.mnt);
if (nd.root.mnt) if (nd.root.mnt)
path_put(&nd.root); 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; return filp;
} }
@ -1805,28 +1777,45 @@ ok:
* be avoided. Taking this mnt write here * be avoided. Taking this mnt write here
* ensures that (2) can not occur. * ensures that (2) can not occur.
*/ */
will_write = open_will_write_to_fs(flag, nd.path.dentry->d_inode); will_truncate = open_will_truncate(flag, nd.path.dentry->d_inode);
if (will_write) { if (will_truncate) {
error = mnt_want_write(nd.path.mnt); error = mnt_want_write(nd.path.mnt);
if (error) if (error)
goto exit; goto exit;
} }
error = may_open(&nd.path, acc_mode, flag); error = may_open(&nd.path, acc_mode, flag);
if (error) { if (error) {
if (will_write) if (will_truncate)
mnt_drop_write(nd.path.mnt); mnt_drop_write(nd.path.mnt);
goto exit; goto exit;
} }
filp = nameidata_to_filp(&nd, open_flag); filp = nameidata_to_filp(&nd, open_flag);
if (IS_ERR(filp)) if (!IS_ERR(filp)) {
ima_counts_put(&nd.path, error = ima_path_check(&filp->f_path, filp->f_mode &
acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC)); (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 * It is now safe to drop the mnt write
* because the filp has had a write taken * because the filp has had a write taken
* on its behalf. * on its behalf.
*/ */
if (will_write) if (will_truncate)
mnt_drop_write(nd.path.mnt); mnt_drop_write(nd.path.mnt);
if (nd.root.mnt) if (nd.root.mnt)
path_put(&nd.root); path_put(&nd.root);
@ -1863,7 +1852,18 @@ do_link:
error = security_inode_follow_link(path.dentry, &nd); error = security_inode_follow_link(path.dentry, &nd);
if (error) if (error)
goto exit_dput; goto exit_dput;
save = nd.path;
path_get(&save);
error = __do_follow_link(&path, &nd); 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) { if (error) {
/* Does someone understand code flow here? Or it is only /* Does someone understand code flow here? Or it is only
* me so stupid? Anathema to whoever designed this non-sense * me so stupid? Anathema to whoever designed this non-sense

View file

@ -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 * create_mnt_ns - creates a private namespace and adds a root filesystem
* @mnt: pointer to the new root filesystem mountpoint * @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; struct mnt_namespace *new_ns;
@ -2080,7 +2080,6 @@ struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt)
} }
return new_ns; return new_ns;
} }
EXPORT_SYMBOL(create_mnt_ns);
SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
char __user *, type, unsigned long, flags, void __user *, data) char __user *, type, unsigned long, flags, void __user *, data)

View file

@ -2648,21 +2648,13 @@ out_freepage:
static int nfs_follow_remote_path(struct vfsmount *root_mnt, static int nfs_follow_remote_path(struct vfsmount *root_mnt,
const char *export_path, struct vfsmount *mnt_target) const char *export_path, struct vfsmount *mnt_target)
{ {
struct mnt_namespace *ns_private;
struct nameidata nd; struct nameidata nd;
struct super_block *s; struct super_block *s;
int ret; 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, ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt,
export_path, LOOKUP_FOLLOW, &nd); export_path, LOOKUP_FOLLOW, &nd);
put_mnt_ns(ns_private);
if (ret != 0) if (ret != 0)
goto out_err; goto out_err;

View file

@ -752,8 +752,6 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
flags, current_cred()); flags, current_cred());
if (IS_ERR(*filp)) if (IS_ERR(*filp))
host_err = PTR_ERR(*filp); host_err = PTR_ERR(*filp);
else
ima_counts_get(*filp);
out_nfserr: out_nfserr:
err = nfserrno(host_err); err = nfserrno(host_err);
out: out:
@ -2132,8 +2130,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
*/ */
path.mnt = exp->ex_path.mnt; path.mnt = exp->ex_path.mnt;
path.dentry = dentry; path.dentry = dentry;
err = ima_path_check(&path, acc & (MAY_READ | MAY_WRITE | MAY_EXEC), err = ima_path_check(&path, acc & (MAY_READ | MAY_WRITE | MAY_EXEC));
IMA_COUNT_LEAVE);
nfsd_out: nfsd_out:
return err? nfserrno(err) : 0; return err? nfserrno(err) : 0;
} }

View file

@ -1118,8 +1118,7 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
/* Abandoning the newly allocated superblock */ /* Abandoning the newly allocated superblock */
mutex_unlock(&nilfs->ns_mount_mutex); mutex_unlock(&nilfs->ns_mount_mutex);
put_nilfs(nilfs); put_nilfs(nilfs);
up_write(&s->s_umount); deactivate_locked_super(s);
deactivate_super(s);
/* /*
* deactivate_super() invokes close_bdev_exclusive(). * deactivate_super() invokes close_bdev_exclusive().
* We must finish all post-cleaning before this call; * We must finish all post-cleaning before this call;

View file

@ -646,6 +646,7 @@ SYSCALL_DEFINE1(inotify_init1, int, flags)
struct fsnotify_group *group; struct fsnotify_group *group;
struct user_struct *user; struct user_struct *user;
struct file *filp; struct file *filp;
struct path path;
int fd, ret; int fd, ret;
/* Check the IN_* constants for consistency. */ /* Check the IN_* constants for consistency. */
@ -659,12 +660,6 @@ SYSCALL_DEFINE1(inotify_init1, int, flags)
if (fd < 0) if (fd < 0)
return fd; return fd;
filp = get_empty_filp();
if (!filp) {
ret = -ENFILE;
goto out_put_fd;
}
user = get_current_user(); user = get_current_user();
if (unlikely(atomic_read(&user->inotify_devs) >= if (unlikely(atomic_read(&user->inotify_devs) >=
inotify_max_user_instances)) { inotify_max_user_instances)) {
@ -679,24 +674,28 @@ SYSCALL_DEFINE1(inotify_init1, int, flags)
goto out_free_uid; goto out_free_uid;
} }
filp->f_op = &inotify_fops; atomic_inc(&user->inotify_devs);
filp->f_path.mnt = mntget(inotify_mnt);
filp->f_path.dentry = dget(inotify_mnt->mnt_root); path.mnt = inotify_mnt;
filp->f_mapping = filp->f_path.dentry->d_inode->i_mapping; path.dentry = inotify_mnt->mnt_root;
filp->f_mode = FMODE_READ; path_get(&path);
filp = alloc_file(&path, FMODE_READ, &inotify_fops);
if (!filp)
goto Enfile;
filp->f_flags = O_RDONLY | (flags & O_NONBLOCK); filp->f_flags = O_RDONLY | (flags & O_NONBLOCK);
filp->private_data = group; filp->private_data = group;
atomic_inc(&user->inotify_devs);
fd_install(fd, filp); fd_install(fd, filp);
return fd; return fd;
Enfile:
ret = -ENFILE;
path_put(&path);
atomic_dec(&user->inotify_devs);
out_free_uid: out_free_uid:
free_uid(user); free_uid(user);
put_filp(filp);
out_put_fd:
put_unused_fd(fd); put_unused_fd(fd);
return ret; return ret;
} }

View file

@ -331,13 +331,14 @@ cleanup:
return ret; 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, char *list,
size_t list_len, size_t list_len,
const char *name, 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); const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 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; 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, char *list,
size_t list_len, size_t list_len,
const char *name, 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); const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 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; return size;
} }
static int ocfs2_xattr_get_acl(struct inode *inode, static int ocfs2_xattr_get_acl(struct dentry *dentry, const char *name,
int type, void *buffer, size_t size, int type)
void *buffer,
size_t size)
{ {
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
struct posix_acl *acl; struct posix_acl *acl;
int ret; int ret;
if (strcmp(name, "") != 0)
return -EINVAL;
if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
return -EOPNOTSUPP; return -EOPNOTSUPP;
acl = ocfs2_get_acl(inode, type); acl = ocfs2_get_acl(dentry->d_inode, type);
if (IS_ERR(acl)) if (IS_ERR(acl))
return PTR_ERR(acl); return PTR_ERR(acl);
if (acl == NULL) if (acl == NULL)
@ -388,35 +390,16 @@ static int ocfs2_xattr_get_acl(struct inode *inode,
return ret; return ret;
} }
static int ocfs2_xattr_get_acl_access(struct inode *inode, static int ocfs2_xattr_set_acl(struct dentry *dentry, const char *name,
const char *name, const void *value, size_t size, int flags, int type)
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)
{ {
struct inode *inode = dentry->d_inode;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
struct posix_acl *acl; struct posix_acl *acl;
int ret = 0; int ret = 0;
if (strcmp(name, "") != 0)
return -EINVAL;
if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -442,38 +425,18 @@ cleanup:
return ret; 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 = { struct xattr_handler ocfs2_xattr_acl_access_handler = {
.prefix = POSIX_ACL_XATTR_ACCESS, .prefix = POSIX_ACL_XATTR_ACCESS,
.flags = ACL_TYPE_ACCESS,
.list = ocfs2_xattr_list_acl_access, .list = ocfs2_xattr_list_acl_access,
.get = ocfs2_xattr_get_acl_access, .get = ocfs2_xattr_get_acl,
.set = ocfs2_xattr_set_acl_access, .set = ocfs2_xattr_set_acl,
}; };
struct xattr_handler ocfs2_xattr_acl_default_handler = { struct xattr_handler ocfs2_xattr_acl_default_handler = {
.prefix = POSIX_ACL_XATTR_DEFAULT, .prefix = POSIX_ACL_XATTR_DEFAULT,
.flags = ACL_TYPE_DEFAULT,
.list = ocfs2_xattr_list_acl_default, .list = ocfs2_xattr_list_acl_default,
.get = ocfs2_xattr_get_acl_default, .get = ocfs2_xattr_get_acl,
.set = ocfs2_xattr_set_acl_default, .set = ocfs2_xattr_set_acl,
}; };

View file

@ -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 * wait on them - the truncate_inode_pages() call later will
* do that for us. * do that for us.
*/ */
ret = do_sync_mapping_range(inode->i_mapping, range_start, ret = filemap_fdatawrite_range(inode->i_mapping, range_start,
range_end - 1, SYNC_FILE_RANGE_WRITE); range_end - 1);
if (ret) if (ret)
mlog_errno(ret); mlog_errno(ret);

View file

@ -205,8 +205,6 @@ static int ocfs2_get_xattr_tree_value_root(struct super_block *sb,
int offset, int offset,
struct ocfs2_xattr_value_root **xv, struct ocfs2_xattr_value_root **xv,
struct buffer_head **bh); 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) static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb)
{ {
@ -6978,8 +6976,8 @@ int ocfs2_init_security_and_acl(struct inode *dir,
ret = ocfs2_init_security_get(inode, dir, &si); ret = ocfs2_init_security_get(inode, dir, &si);
if (!ret) { if (!ret) {
ret = ocfs2_xattr_security_set(inode, si.name, ret = ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_SECURITY,
si.value, si.value_len, si.name, si.value, si.value_len,
XATTR_CREATE); XATTR_CREATE);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
@ -7008,9 +7006,9 @@ leave:
/* /*
* 'security' attributes support * '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 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 prefix_len = XATTR_SECURITY_PREFIX_LEN;
const size_t total_len = prefix_len + name_len + 1; 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; return total_len;
} }
static int ocfs2_xattr_security_get(struct inode *inode, const char *name, static int ocfs2_xattr_security_get(struct dentry *dentry, const char *name,
void *buffer, size_t size) void *buffer, size_t size, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_SECURITY, name, return ocfs2_xattr_get(dentry->d_inode, OCFS2_XATTR_INDEX_SECURITY,
buffer, size); name, buffer, size);
} }
static int ocfs2_xattr_security_set(struct inode *inode, const char *name, static int ocfs2_xattr_security_set(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_SECURITY, name, value, return ocfs2_xattr_set(dentry->d_inode, OCFS2_XATTR_INDEX_SECURITY,
size, flags); name, value, size, flags);
} }
int ocfs2_init_security_get(struct inode *inode, int ocfs2_init_security_get(struct inode *inode,
@ -7076,9 +7074,9 @@ struct xattr_handler ocfs2_xattr_security_handler = {
/* /*
* 'trusted' attributes support * '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 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 prefix_len = XATTR_TRUSTED_PREFIX_LEN;
const size_t total_len = prefix_len + name_len + 1; 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; return total_len;
} }
static int ocfs2_xattr_trusted_get(struct inode *inode, const char *name, static int ocfs2_xattr_trusted_get(struct dentry *dentry, const char *name,
void *buffer, size_t size) void *buffer, size_t size, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_TRUSTED, name, return ocfs2_xattr_get(dentry->d_inode, OCFS2_XATTR_INDEX_TRUSTED,
buffer, size); name, buffer, size);
} }
static int ocfs2_xattr_trusted_set(struct inode *inode, const char *name, static int ocfs2_xattr_trusted_set(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags, int type)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_TRUSTED, name, value, return ocfs2_xattr_set(dentry->d_inode, OCFS2_XATTR_INDEX_TRUSTED,
size, flags); name, value, size, flags);
} }
struct xattr_handler ocfs2_xattr_trusted_handler = { struct xattr_handler ocfs2_xattr_trusted_handler = {
@ -7120,13 +7118,13 @@ struct xattr_handler ocfs2_xattr_trusted_handler = {
/* /*
* 'user' attributes support * '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 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 prefix_len = XATTR_USER_PREFIX_LEN;
const size_t total_len = prefix_len + name_len + 1; 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) if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
return 0; return 0;
@ -7139,31 +7137,31 @@ static size_t ocfs2_xattr_user_list(struct inode *inode, char *list,
return total_len; return total_len;
} }
static int ocfs2_xattr_user_get(struct inode *inode, const char *name, static int ocfs2_xattr_user_get(struct dentry *dentry, const char *name,
void *buffer, size_t size) 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) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR) if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
return -EOPNOTSUPP; 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); buffer, size);
} }
static int ocfs2_xattr_user_set(struct inode *inode, const char *name, static int ocfs2_xattr_user_set(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags) 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) if (strcmp(name, "") == 0)
return -EINVAL; return -EINVAL;
if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR) if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_USER, name, value, return ocfs2_xattr_set(dentry->d_inode, OCFS2_XATTR_INDEX_USER,
size, flags); name, value, size, flags);
} }
struct xattr_handler ocfs2_xattr_user_handler = { struct xattr_handler ocfs2_xattr_user_handler = {

View file

@ -30,6 +30,9 @@
#include <linux/audit.h> #include <linux/audit.h>
#include <linux/falloc.h> #include <linux/falloc.h>
#include <linux/fs_struct.h> #include <linux/fs_struct.h>
#include <linux/ima.h>
#include "internal.h"
int vfs_statfs(struct dentry *dentry, struct kstatfs *buf) 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) if (error)
goto cleanup_all; goto cleanup_all;
} }
ima_counts_get(f);
f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);

View file

@ -974,7 +974,7 @@ struct file *create_write_pipe(int flags)
int err; int err;
struct inode *inode; struct inode *inode;
struct file *f; struct file *f;
struct dentry *dentry; struct path path;
struct qstr name = { .name = "" }; struct qstr name = { .name = "" };
err = -ENFILE; err = -ENFILE;
@ -983,21 +983,22 @@ struct file *create_write_pipe(int flags)
goto err; goto err;
err = -ENOMEM; err = -ENOMEM;
dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &name); path.dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &name);
if (!dentry) if (!path.dentry)
goto err_inode; 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 dont want to publish this dentry into global dentry hash table.
* We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED * We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED
* This permits a working /proc/$pid/fd/XXX on pipes * This permits a working /proc/$pid/fd/XXX on pipes
*/ */
dentry->d_flags &= ~DCACHE_UNHASHED; path.dentry->d_flags &= ~DCACHE_UNHASHED;
d_instantiate(dentry, inode); d_instantiate(path.dentry, inode);
err = -ENFILE; err = -ENFILE;
f = alloc_file(pipe_mnt, dentry, FMODE_WRITE, &write_pipefifo_fops); f = alloc_file(&path, FMODE_WRITE, &write_pipefifo_fops);
if (!f) if (!f)
goto err_dentry; goto err_dentry;
f->f_mapping = inode->i_mapping; f->f_mapping = inode->i_mapping;
@ -1009,7 +1010,7 @@ struct file *create_write_pipe(int flags)
err_dentry: err_dentry:
free_pipe_info(inode); free_pipe_info(inode);
dput(dentry); path_put(&path);
return ERR_PTR(err); return ERR_PTR(err);
err_inode: 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 *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) if (!f)
return ERR_PTR(-ENFILE); return ERR_PTR(-ENFILE);
/* Grab pipe from the writer */
f->f_path = wrf->f_path;
path_get(&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_flags = O_RDONLY | (flags & O_NONBLOCK);
f->f_op = &read_pipefifo_fops;
f->f_mode = FMODE_READ;
f->f_version = 0;
return f; return f;
} }

View file

@ -48,6 +48,7 @@
#include <net/checksum.h> #include <net/checksum.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/quotaops.h> #include <linux/quotaops.h>
#include <linux/security.h>
#define PRIVROOT_NAME ".reiserfs_priv" #define PRIVROOT_NAME ".reiserfs_priv"
#define XAROOT_NAME "xattrs" #define XAROOT_NAME "xattrs"
@ -726,15 +727,14 @@ ssize_t
reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer, reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer,
size_t size) size_t size)
{ {
struct inode *inode = dentry->d_inode;
struct xattr_handler *handler; 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 -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, reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value,
size_t size, int flags) size_t size, int flags)
{ {
struct inode *inode = dentry->d_inode;
struct xattr_handler *handler; 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 -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) int reiserfs_removexattr(struct dentry *dentry, const char *name)
{ {
struct inode *inode = dentry->d_inode;
struct xattr_handler *handler; 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 -EOPNOTSUPP;
return handler->set(inode, name, NULL, 0, XATTR_REPLACE); return handler->set(dentry, name, NULL, 0, XATTR_REPLACE, handler->flags);
} }
struct listxattr_buf { struct listxattr_buf {
size_t size; size_t size;
size_t pos; size_t pos;
char *buf; char *buf;
struct inode *inode; struct dentry *dentry;
}; };
static int listxattr_filler(void *buf, const char *name, int namelen, 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] != '.' || if (name[0] != '.' ||
(namelen != 1 && (name[1] != '.' || namelen != 2))) { (namelen != 1 && (name[1] != '.' || namelen != 2))) {
struct xattr_handler *handler; 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); name);
if (!handler) /* Unsupported xattr name */ if (!handler) /* Unsupported xattr name */
return 0; return 0;
if (b->buf) { if (b->buf) {
size = handler->list(b->inode, b->buf + b->pos, size = handler->list(b->dentry, b->buf + b->pos,
b->size, name, namelen); b->size, name, namelen,
handler->flags);
if (size > b->size) if (size > b->size)
return -ERANGE; return -ERANGE;
} else { } else {
size = handler->list(b->inode, NULL, 0, name, namelen); size = handler->list(b->dentry, NULL, 0, name,
namelen, handler->flags);
} }
b->pos += size; b->pos += size;
@ -820,7 +820,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size)
int err = 0; int err = 0;
loff_t pos = 0; loff_t pos = 0;
struct listxattr_buf buf = { struct listxattr_buf buf = {
.inode = dentry->d_inode, .dentry = dentry,
.buf = buffer, .buf = buffer,
.size = buffer ? size : 0, .size = buffer ? size : 0,
}; };

View file

@ -15,8 +15,10 @@ static int reiserfs_set_acl(struct reiserfs_transaction_handle *th,
struct posix_acl *acl); struct posix_acl *acl);
static int 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; struct posix_acl *acl;
int error, error2; int error, error2;
struct reiserfs_transaction_handle th; 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 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; struct posix_acl *acl;
int error; int error;
if (!reiserfs_posixacl(inode->i_sb)) if (!reiserfs_posixacl(dentry->d_sb))
return -EOPNOTSUPP; return -EOPNOTSUPP;
acl = reiserfs_get_acl(inode, type); acl = reiserfs_get_acl(dentry->d_inode, type);
if (IS_ERR(acl)) if (IS_ERR(acl))
return PTR_ERR(acl); return PTR_ERR(acl);
if (acl == NULL) if (acl == NULL)
@ -482,30 +485,12 @@ int reiserfs_acl_chmod(struct inode *inode)
return error; return error;
} }
static int static size_t posix_acl_access_list(struct dentry *dentry, char *list,
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,
size_t list_size, const char *name, 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); const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
if (!reiserfs_posixacl(inode->i_sb)) if (!reiserfs_posixacl(dentry->d_sb))
return 0; return 0;
if (list && size <= list_size) if (list && size <= list_size)
memcpy(list, POSIX_ACL_XATTR_ACCESS, 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 = { struct xattr_handler reiserfs_posix_acl_access_handler = {
.prefix = POSIX_ACL_XATTR_ACCESS, .prefix = POSIX_ACL_XATTR_ACCESS,
.get = posix_acl_access_get, .flags = ACL_TYPE_ACCESS,
.set = posix_acl_access_set, .get = posix_acl_get,
.set = posix_acl_set,
.list = posix_acl_access_list, .list = posix_acl_access_list,
}; };
static int static size_t posix_acl_default_list(struct dentry *dentry, char *list,
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,
size_t list_size, const char *name, 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); const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
if (!reiserfs_posixacl(inode->i_sb)) if (!reiserfs_posixacl(dentry->d_sb))
return 0; return 0;
if (list && size <= list_size) if (list && size <= list_size)
memcpy(list, POSIX_ACL_XATTR_DEFAULT, 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 = { struct xattr_handler reiserfs_posix_acl_default_handler = {
.prefix = POSIX_ACL_XATTR_DEFAULT, .prefix = POSIX_ACL_XATTR_DEFAULT,
.get = posix_acl_default_get, .flags = ACL_TYPE_DEFAULT,
.set = posix_acl_default_set, .get = posix_acl_get,
.set = posix_acl_set,
.list = posix_acl_default_list, .list = posix_acl_default_list,
}; };

View file

@ -8,36 +8,37 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
static int 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)) if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
return -EINVAL; return -EINVAL;
if (IS_PRIVATE(inode)) if (IS_PRIVATE(dentry->d_inode))
return -EPERM; return -EPERM;
return reiserfs_xattr_get(inode, name, buffer, size); return reiserfs_xattr_get(dentry->d_inode, name, buffer, size);
} }
static int static int
security_set(struct inode *inode, const char *name, const void *buffer, security_set(struct dentry *dentry, const char *name, const void *buffer,
size_t size, int flags) size_t size, int flags, int handler_flags)
{ {
if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX)) if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
return -EINVAL; return -EINVAL;
if (IS_PRIVATE(inode)) if (IS_PRIVATE(dentry->d_inode))
return -EPERM; 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, static size_t security_list(struct dentry *dentry, char *list, size_t list_len,
const char *name, size_t namelen) const char *name, size_t namelen, int handler_flags)
{ {
const size_t len = namelen + 1; const size_t len = namelen + 1;
if (IS_PRIVATE(inode)) if (IS_PRIVATE(dentry->d_inode))
return 0; return 0;
if (list && len <= list_len) { if (list && len <= list_len) {

View file

@ -8,36 +8,37 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
static int 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)) if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
return -EINVAL; return -EINVAL;
if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode)) if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(dentry->d_inode))
return -EPERM; return -EPERM;
return reiserfs_xattr_get(inode, name, buffer, size); return reiserfs_xattr_get(dentry->d_inode, name, buffer, size);
} }
static int static int
trusted_set(struct inode *inode, const char *name, const void *buffer, trusted_set(struct dentry *dentry, const char *name, const void *buffer,
size_t size, int flags) size_t size, int flags, int handler_flags)
{ {
if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX)) if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
return -EINVAL; return -EINVAL;
if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode)) if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(dentry->d_inode))
return -EPERM; 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, static size_t trusted_list(struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len) const char *name, size_t name_len, int handler_flags)
{ {
const size_t len = name_len + 1; 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; return 0;
if (list && len <= list_size) { if (list && len <= list_size) {

View file

@ -7,34 +7,35 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
static int 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)) if (strlen(name) < sizeof(XATTR_USER_PREFIX))
return -EINVAL; return -EINVAL;
if (!reiserfs_xattrs_user(inode->i_sb)) if (!reiserfs_xattrs_user(dentry->d_sb))
return -EOPNOTSUPP; return -EOPNOTSUPP;
return reiserfs_xattr_get(inode, name, buffer, size); return reiserfs_xattr_get(dentry->d_inode, name, buffer, size);
} }
static int static int
user_set(struct inode *inode, const char *name, const void *buffer, user_set(struct dentry *dentry, const char *name, const void *buffer,
size_t size, int flags) size_t size, int flags, int handler_flags)
{ {
if (strlen(name) < sizeof(XATTR_USER_PREFIX)) if (strlen(name) < sizeof(XATTR_USER_PREFIX))
return -EINVAL; return -EINVAL;
if (!reiserfs_xattrs_user(inode->i_sb)) if (!reiserfs_xattrs_user(dentry->d_sb))
return -EOPNOTSUPP; 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, static size_t user_list(struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len) const char *name, size_t name_len, int handler_flags)
{ {
const size_t len = name_len + 1; const size_t len = name_len + 1;
if (!reiserfs_xattrs_user(inode->i_sb)) if (!reiserfs_xattrs_user(dentry->d_sb))
return 0; return 0;
if (list && len <= list_size) { if (list && len <= list_size) {
memcpy(list, name, name_len); memcpy(list, name, name_len);

View file

@ -615,12 +615,11 @@ ssize_t
generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size) generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size)
{ {
struct xattr_handler *handler; 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) if (!handler)
return -EOPNOTSUPP; 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 ssize_t
generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
{ {
struct inode *inode = dentry->d_inode; struct xattr_handler *handler, **handlers = dentry->d_sb->s_xattr;
struct xattr_handler *handler, **handlers = inode->i_sb->s_xattr;
unsigned int size = 0; unsigned int size = 0;
if (!buffer) { if (!buffer) {
for_each_xattr_handler(handlers, handler) for_each_xattr_handler(handlers, handler) {
size += handler->list(inode, NULL, 0, NULL, 0); size += handler->list(dentry, NULL, 0, NULL, 0,
handler->flags);
}
} else { } else {
char *buf = buffer; char *buf = buffer;
for_each_xattr_handler(handlers, handler) { 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) if (size > buffer_size)
return -ERANGE; return -ERANGE;
buf += size; buf += size;
@ -659,14 +660,13 @@ int
generic_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) generic_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags)
{ {
struct xattr_handler *handler; struct xattr_handler *handler;
struct inode *inode = dentry->d_inode;
if (size == 0) if (size == 0)
value = ""; /* empty EA, do not remove */ 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) if (!handler)
return -EOPNOTSUPP; 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) generic_removexattr(struct dentry *dentry, const char *name)
{ {
struct xattr_handler *handler; 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) if (!handler)
return -EOPNOTSUPP; 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); EXPORT_SYMBOL(generic_getxattr);

View file

@ -354,37 +354,14 @@ xfs_acl_chmod(struct inode *inode)
return error; 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 static int
xfs_decode_acl(const char *name) xfs_xattr_acl_get(struct dentry *dentry, const char *name,
{ void *value, size_t size, int type)
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)
{ {
struct posix_acl *acl; struct posix_acl *acl;
int type, error; int error;
type = xfs_decode_acl(name); acl = xfs_get_acl(dentry->d_inode, type);
if (type < 0)
return type;
acl = xfs_get_acl(inode, type);
if (IS_ERR(acl)) if (IS_ERR(acl))
return PTR_ERR(acl); return PTR_ERR(acl);
if (acl == NULL) if (acl == NULL)
@ -397,15 +374,13 @@ xfs_xattr_system_get(struct inode *inode, const char *name,
} }
static int static int
xfs_xattr_system_set(struct inode *inode, const char *name, xfs_xattr_acl_set(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags, int type)
{ {
struct inode *inode = dentry->d_inode;
struct posix_acl *acl = NULL; 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) if (flags & XATTR_CREATE)
return -EINVAL; return -EINVAL;
if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) 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; return error;
} }
struct xattr_handler xfs_xattr_system_handler = { struct xattr_handler xfs_xattr_acl_access_handler = {
.prefix = XATTR_SYSTEM_PREFIX, .prefix = POSIX_ACL_XATTR_ACCESS,
.get = xfs_xattr_system_get, .flags = ACL_TYPE_ACCESS,
.set = xfs_xattr_system_set, .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,
}; };

View file

@ -30,10 +30,10 @@
static int 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) 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; int error, asize = size;
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
@ -52,10 +52,10 @@ __xfs_xattr_get(struct inode *inode, const char *name,
} }
static int 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) 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) if (strcmp(name, "") == 0)
return -EINVAL; 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); 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 = { static struct xattr_handler xfs_xattr_user_handler = {
.prefix = XATTR_USER_PREFIX, .prefix = XATTR_USER_PREFIX,
.get = xfs_xattr_user_get, .flags = 0, /* no flags implies user namespace */
.set = xfs_xattr_user_set, .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 = { static struct xattr_handler xfs_xattr_trusted_handler = {
.prefix = XATTR_TRUSTED_PREFIX, .prefix = XATTR_TRUSTED_PREFIX,
.get = xfs_xattr_trusted_get, .flags = ATTR_ROOT,
.set = xfs_xattr_trusted_set, .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 = { static struct xattr_handler xfs_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX, .prefix = XATTR_SECURITY_PREFIX,
.get = xfs_xattr_secure_get, .flags = ATTR_SECURE,
.set = xfs_xattr_secure_set, .get = xfs_xattr_get,
.set = xfs_xattr_set,
}; };
struct xattr_handler *xfs_xattr_handlers[] = { struct xattr_handler *xfs_xattr_handlers[] = {
&xfs_xattr_user_handler, &xfs_xattr_user_handler,
&xfs_xattr_trusted_handler, &xfs_xattr_trusted_handler,
&xfs_xattr_security_handler, &xfs_xattr_security_handler,
#ifdef CONFIG_XFS_POSIX_ACL #ifdef CONFIG_XFS_POSIX_ACL
&xfs_xattr_system_handler, &xfs_xattr_acl_access_handler,
&xfs_xattr_acl_default_handler,
#endif #endif
NULL NULL
}; };

View file

@ -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_access_exists(struct inode *inode);
extern int posix_acl_default_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 #else
# define xfs_check_acl NULL # define xfs_check_acl NULL
# define xfs_get_acl(inode, type) NULL # define xfs_get_acl(inode, type) NULL

View file

@ -18,11 +18,9 @@ extern void drop_file_write_access(struct file *file);
struct file_operations; struct file_operations;
struct vfsmount; struct vfsmount;
struct dentry; struct dentry;
extern int init_file(struct file *, struct vfsmount *mnt, struct path;
struct dentry *dentry, fmode_t mode, extern struct file *alloc_file(struct path *, fmode_t mode,
const struct file_operations *fop); const struct file_operations *fop);
extern struct file *alloc_file(struct vfsmount *, struct dentry *dentry,
fmode_t mode, const struct file_operations *fop);
static inline void fput_light(struct file *file, int fput_needed) static inline void fput_light(struct file *file, int fput_needed)
{ {

View file

@ -2189,7 +2189,6 @@ static inline void insert_inode_hash(struct inode *inode) {
__insert_inode_hash(inode, inode->i_ino); __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_move(struct file *f, struct list_head *list);
extern void file_kill(struct file *f); extern void file_kill(struct file *f);
#ifdef CONFIG_BLOCK #ifdef CONFIG_BLOCK

View file

@ -1,36 +1,15 @@
/* #ifndef LINUX_GENERIC_ACL_H
* include/linux/generic_acl.h #define LINUX_GENERIC_ACL_H
*
* (C) 2005 Andreas Gruenbacher <agruen@suse.de>
*
* This file is released under the GPL.
*/
#ifndef GENERIC_ACL_H #include <linux/xattr.h>
#define GENERIC_ACL_H
#include <linux/posix_acl.h> struct inode;
#include <linux/posix_acl_xattr.h>
/** extern struct xattr_handler generic_acl_access_handler;
* struct generic_acl_operations - filesystem operations extern struct xattr_handler generic_acl_default_handler;
*
* 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 *);
};
size_t generic_acl_list(struct inode *, struct generic_acl_operations *, int, int generic_acl_init(struct inode *, struct inode *);
char *, size_t); int generic_acl_chmod(struct inode *);
int generic_acl_get(struct inode *, struct generic_acl_operations *, int, int generic_check_acl(struct inode *inode, int mask);
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 *);
#endif #endif /* LINUX_GENERIC_ACL_H */

View file

@ -13,18 +13,14 @@
#include <linux/fs.h> #include <linux/fs.h>
struct linux_binprm; struct linux_binprm;
#define IMA_COUNT_UPDATE 1
#define IMA_COUNT_LEAVE 0
#ifdef CONFIG_IMA #ifdef CONFIG_IMA
extern int ima_bprm_check(struct linux_binprm *bprm); extern int ima_bprm_check(struct linux_binprm *bprm);
extern int ima_inode_alloc(struct inode *inode); extern int ima_inode_alloc(struct inode *inode);
extern void ima_inode_free(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 void ima_file_free(struct file *file);
extern int ima_file_mmap(struct file *file, unsigned long prot); extern int ima_file_mmap(struct file *file, unsigned long prot);
extern void ima_counts_get(struct file *file); extern void ima_counts_get(struct file *file);
extern void ima_counts_put(struct path *path, int mask);
#else #else
static inline int ima_bprm_check(struct linux_binprm *bprm) static inline int ima_bprm_check(struct linux_binprm *bprm)
@ -42,7 +38,7 @@ static inline void ima_inode_free(struct inode *inode)
return; 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; return 0;
} }
@ -62,9 +58,5 @@ static inline void ima_counts_get(struct file *file)
return; return;
} }
static inline void ima_counts_put(struct path *path, int mask)
{
return;
}
#endif /* CONFIG_IMA_H */ #endif /* CONFIG_IMA_H */
#endif /* _LINUX_IMA_H */ #endif /* _LINUX_IMA_H */

View file

@ -23,7 +23,6 @@ struct proc_mounts {
struct fs_struct; 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 *, extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *,
struct fs_struct *); struct fs_struct *);
extern void put_mnt_ns(struct mnt_namespace *ns); extern void put_mnt_ns(struct mnt_namespace *ns);

View file

@ -41,20 +41,4 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
extern int init_tmpfs(void); extern int init_tmpfs(void);
extern int shmem_fill_super(struct super_block *sb, void *data, int silent); 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 #endif

View file

@ -38,12 +38,13 @@ struct dentry;
struct xattr_handler { struct xattr_handler {
char *prefix; char *prefix;
size_t (*list)(struct inode *inode, char *list, size_t list_size, int flags; /* fs private flags passed back to the handlers */
const char *name, size_t name_len); size_t (*list)(struct dentry *dentry, char *list, size_t list_size,
int (*get)(struct inode *inode, const char *name, void *buffer, const char *name, size_t name_len, int handler_flags);
size_t size); int (*get)(struct dentry *dentry, const char *name, void *buffer,
int (*set)(struct inode *inode, const char *name, const void *buffer, size_t size, int handler_flags);
size_t size, int 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); ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);

View file

@ -32,7 +32,6 @@
#include <linux/nsproxy.h> #include <linux/nsproxy.h>
#include <linux/pid.h> #include <linux/pid.h>
#include <linux/ipc_namespace.h> #include <linux/ipc_namespace.h>
#include <linux/ima.h>
#include <net/sock.h> #include <net/sock.h>
#include "util.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); error = PTR_ERR(filp);
goto out_putfd; goto out_putfd;
} }
ima_counts_get(filp);
fd_install(fd, filp); fd_install(fd, filp);
goto out_upsem; goto out_upsem;

View file

@ -39,7 +39,6 @@
#include <linux/nsproxy.h> #include <linux/nsproxy.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/ipc_namespace.h> #include <linux/ipc_namespace.h>
#include <linux/ima.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
@ -879,8 +878,8 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
if (err) if (err)
goto out_unlock; goto out_unlock;
path.dentry = dget(shp->shm_file->f_path.dentry); path = shp->shm_file->f_path;
path.mnt = shp->shm_file->f_path.mnt; path_get(&path);
shp->shm_nattch++; shp->shm_nattch++;
size = i_size_read(path.dentry->d_inode); size = i_size_read(path.dentry->d_inode);
shm_unlock(shp); shm_unlock(shp);
@ -890,13 +889,12 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
if (!sfd) if (!sfd)
goto out_put_dentry; goto out_put_dentry;
file = alloc_file(path.mnt, path.dentry, f_mode, file = alloc_file(&path, f_mode,
is_file_hugepages(shp->shm_file) ? is_file_hugepages(shp->shm_file) ?
&shm_file_operations_huge : &shm_file_operations_huge :
&shm_file_operations); &shm_file_operations);
if (!file) if (!file)
goto out_free; goto out_free;
ima_counts_get(file);
file->private_data = sfd; file->private_data = sfd;
file->f_mapping = shp->shm_file->f_mapping; file->f_mapping = shp->shm_file->f_mapping;
@ -951,7 +949,7 @@ out_unlock:
out_free: out_free:
kfree(sfd); kfree(sfd);
out_put_dentry: out_put_dentry:
dput(path.dentry); path_put(&path);
goto out_nattch; goto out_nattch;
} }

View file

@ -22,7 +22,6 @@ obj-$(CONFIG_HUGETLBFS) += hugetlb.o
obj-$(CONFIG_NUMA) += mempolicy.o obj-$(CONFIG_NUMA) += mempolicy.o
obj-$(CONFIG_SPARSEMEM) += sparse.o obj-$(CONFIG_SPARSEMEM) += sparse.o
obj-$(CONFIG_SPARSEMEM_VMEMMAP) += sparse-vmemmap.o obj-$(CONFIG_SPARSEMEM_VMEMMAP) += sparse-vmemmap.o
obj-$(CONFIG_TMPFS_POSIX_ACL) += shmem_acl.o
obj-$(CONFIG_SLOB) += slob.o obj-$(CONFIG_SLOB) += slob.o
obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o
obj-$(CONFIG_KSM) += ksm.o obj-$(CONFIG_KSM) += ksm.o

View file

@ -2240,7 +2240,6 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
size_t count, ssize_t written) size_t count, ssize_t written)
{ {
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping;
ssize_t status; ssize_t status;
struct iov_iter i; struct iov_iter i;
@ -2252,15 +2251,6 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
*ppos = pos + status; *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; return written ? written : status;
} }
EXPORT_SYMBOL(generic_file_buffered_write); EXPORT_SYMBOL(generic_file_buffered_write);
@ -2359,10 +2349,7 @@ ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
* semantics. * semantics.
*/ */
endbyte = pos + written_buffered - written - 1; endbyte = pos + written_buffered - written - 1;
err = do_sync_mapping_range(file->f_mapping, pos, endbyte, err = filemap_write_and_wait_range(file->f_mapping, pos, endbyte);
SYNC_FILE_RANGE_WAIT_BEFORE|
SYNC_FILE_RANGE_WRITE|
SYNC_FILE_RANGE_WAIT_AFTER);
if (err == 0) { if (err == 0) {
written = written_buffered; written = written_buffered;
invalidate_mapping_pages(mapping, invalidate_mapping_pages(mapping,

View file

@ -29,7 +29,6 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/ima.h>
static struct vfsmount *shm_mnt; static struct vfsmount *shm_mnt;
@ -42,6 +41,7 @@ static struct vfsmount *shm_mnt;
#include <linux/xattr.h> #include <linux/xattr.h>
#include <linux/exportfs.h> #include <linux/exportfs.h>
#include <linux/posix_acl.h>
#include <linux/generic_acl.h> #include <linux/generic_acl.h>
#include <linux/mman.h> #include <linux/mman.h>
#include <linux/string.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); error = inode_setattr(inode, attr);
#ifdef CONFIG_TMPFS_POSIX_ACL #ifdef CONFIG_TMPFS_POSIX_ACL
if (!error && (attr->ia_valid & ATTR_MODE)) if (!error && (attr->ia_valid & ATTR_MODE))
error = generic_acl_chmod(inode, &shmem_acl_ops); error = generic_acl_chmod(inode);
#endif #endif
if (page) if (page)
page_cache_release(page); page_cache_release(page);
@ -1824,11 +1824,13 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
return error; return error;
} }
} }
error = shmem_acl_init(inode, dir); #ifdef CONFIG_TMPFS_POSIX_ACL
error = generic_acl_init(inode, dir);
if (error) { if (error) {
iput(inode); iput(inode);
return error; return error;
} }
#endif
if (dir->i_mode & S_ISGID) { if (dir->i_mode & S_ISGID) {
inode->i_gid = dir->i_gid; inode->i_gid = dir->i_gid;
if (S_ISDIR(mode)) if (S_ISDIR(mode))
@ -2043,27 +2045,28 @@ static const struct inode_operations shmem_symlink_inode_operations = {
* filesystem level, though. * 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 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, static int shmem_xattr_security_get(struct dentry *dentry, const char *name,
void *buffer, size_t size) void *buffer, size_t size, int handler_flags)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; 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, static int shmem_xattr_security_set(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags, int handler_flags)
{ {
if (strcmp(name, "") == 0) if (strcmp(name, "") == 0)
return -EINVAL; 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 = { 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[] = { static struct xattr_handler *shmem_xattr_handlers[] = {
&shmem_xattr_acl_access_handler, &generic_acl_access_handler,
&shmem_xattr_acl_default_handler, &generic_acl_default_handler,
&shmem_xattr_security_handler, &shmem_xattr_security_handler,
NULL NULL
}; };
@ -2454,7 +2457,7 @@ static const struct inode_operations shmem_inode_operations = {
.getxattr = generic_getxattr, .getxattr = generic_getxattr,
.listxattr = generic_listxattr, .listxattr = generic_listxattr,
.removexattr = generic_removexattr, .removexattr = generic_removexattr,
.check_acl = shmem_check_acl, .check_acl = generic_check_acl,
#endif #endif
}; };
@ -2477,7 +2480,7 @@ static const struct inode_operations shmem_dir_inode_operations = {
.getxattr = generic_getxattr, .getxattr = generic_getxattr,
.listxattr = generic_listxattr, .listxattr = generic_listxattr,
.removexattr = generic_removexattr, .removexattr = generic_removexattr,
.check_acl = shmem_check_acl, .check_acl = generic_check_acl,
#endif #endif
}; };
@ -2488,7 +2491,7 @@ static const struct inode_operations shmem_special_inode_operations = {
.getxattr = generic_getxattr, .getxattr = generic_getxattr,
.listxattr = generic_listxattr, .listxattr = generic_listxattr,
.removexattr = generic_removexattr, .removexattr = generic_removexattr,
.check_acl = shmem_check_acl, .check_acl = generic_check_acl,
#endif #endif
}; };
@ -2626,7 +2629,8 @@ struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags
int error; int error;
struct file *file; struct file *file;
struct inode *inode; struct inode *inode;
struct dentry *dentry, *root; struct path path;
struct dentry *root;
struct qstr this; struct qstr this;
if (IS_ERR(shm_mnt)) 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.len = strlen(name);
this.hash = 0; /* will go */ this.hash = 0; /* will go */
root = shm_mnt->mnt_root; root = shm_mnt->mnt_root;
dentry = d_alloc(root, &this); path.dentry = d_alloc(root, &this);
if (!dentry) if (!path.dentry)
goto put_memory; goto put_memory;
path.mnt = mntget(shm_mnt);
error = -ENFILE;
file = get_empty_filp();
if (!file)
goto put_dentry;
error = -ENOSPC; error = -ENOSPC;
inode = shmem_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0, flags); inode = shmem_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0, flags);
if (!inode) if (!inode)
goto close_file; goto put_dentry;
d_instantiate(dentry, inode); d_instantiate(path.dentry, inode);
inode->i_size = size; inode->i_size = size;
inode->i_nlink = 0; /* It is unlinked */ inode->i_nlink = 0; /* It is unlinked */
init_file(file, shm_mnt, dentry, FMODE_WRITE | FMODE_READ,
&shmem_file_operations);
#ifndef CONFIG_MMU #ifndef CONFIG_MMU
error = ramfs_nommu_expand_for_mapping(inode, size); error = ramfs_nommu_expand_for_mapping(inode, size);
if (error) if (error)
goto close_file; goto put_dentry;
#endif #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; return file;
close_file:
put_filp(file);
put_dentry: put_dentry:
dput(dentry); path_put(&path);
put_memory: put_memory:
shmem_unacct_size(flags, size); shmem_unacct_size(flags, size);
return ERR_PTR(error); return ERR_PTR(error);

View file

@ -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;
}

View file

@ -42,6 +42,8 @@
#include <net/9p/client.h> #include <net/9p/client.h>
#include <net/9p/transport.h> #include <net/9p/transport.h>
#include <linux/syscalls.h> /* killme */
#define P9_PORT 564 #define P9_PORT 564
#define MAX_SOCK_BUF (64*1024) #define MAX_SOCK_BUF (64*1024)
#define MAXPOLLWADDR 2 #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) 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; csocket->sk->sk_allocation = GFP_NOIO;
fd = sock_map_fd(csocket, 0); fd = sock_map_fd(csocket, 0);
if (fd < 0) { if (fd < 0) {
P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n"); P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n");
sock_release(csocket);
kfree(p);
return fd; return fd;
} }
ret = p9_fd_open(client, fd, fd); get_file(csocket->file);
if (ret < 0) { get_file(csocket->file);
P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to open fd\n"); 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); sockfd_put(csocket);
return ret; return ret;
} }
((struct p9_trans_fd *)client->trans)->rd->f_flags |= O_NONBLOCK;
return 0; return 0;
} }
@ -883,7 +902,6 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
struct socket *csocket; struct socket *csocket;
struct sockaddr_in sin_server; struct sockaddr_in sin_server;
struct p9_fd_opts opts; struct p9_fd_opts opts;
struct p9_trans_fd *p = NULL; /* this gets allocated in p9_fd_open */
err = parse_opts(args, &opts); err = parse_opts(args, &opts);
if (err < 0) 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_family = AF_INET;
sin_server.sin_addr.s_addr = in_aton(addr); sin_server.sin_addr.s_addr = in_aton(addr);
sin_server.sin_port = htons(opts.port); 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"); P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n");
err = -EIO; return err;
goto error;
} }
err = csocket->ops->connect(csocket, 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_EPRINTK(KERN_ERR,
"p9_trans_tcp: problem connecting socket to %s\n", "p9_trans_tcp: problem connecting socket to %s\n",
addr); 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); sock_release(csocket);
kfree(p);
return err; return err;
}
return p9_socket_open(client, csocket);
} }
static int static int
@ -944,49 +942,33 @@ p9_fd_create_unix(struct p9_client *client, const char *addr, char *args)
int err; int err;
struct socket *csocket; struct socket *csocket;
struct sockaddr_un sun_server; struct sockaddr_un sun_server;
struct p9_trans_fd *p = NULL; /* this gets allocated in p9_fd_open */
csocket = NULL; csocket = NULL;
if (strlen(addr) > UNIX_PATH_MAX) { if (strlen(addr) > UNIX_PATH_MAX) {
P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n", P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
addr); addr);
err = -ENAMETOOLONG; return -ENAMETOOLONG;
goto error;
} }
sun_server.sun_family = PF_UNIX; sun_server.sun_family = PF_UNIX;
strcpy(sun_server.sun_path, addr); 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, err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
sizeof(struct sockaddr_un) - 1, 0); sizeof(struct sockaddr_un) - 1, 0);
if (err < 0) { if (err < 0) {
P9_EPRINTK(KERN_ERR, P9_EPRINTK(KERN_ERR,
"p9_trans_unix: problem connecting socket: %s: %d\n", "p9_trans_unix: problem connecting socket: %s: %d\n",
addr, err); 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); sock_release(csocket);
kfree(p);
return err; return err;
}
return p9_socket_open(client, csocket);
} }
static int static int
@ -994,7 +976,7 @@ p9_fd_create(struct p9_client *client, const char *addr, char *args)
{ {
int err; int err;
struct p9_fd_opts opts; 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); 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); err = p9_fd_open(client, opts.rfd, opts.wfd);
if (err < 0) if (err < 0)
goto error; return err;
p = (struct p9_trans_fd *) client->trans; p = (struct p9_trans_fd *) client->trans;
p->conn = p9_conn_create(client); p->conn = p9_conn_create(client);
if (IS_ERR(p->conn)) { if (IS_ERR(p->conn)) {
err = PTR_ERR(p->conn); err = PTR_ERR(p->conn);
p->conn = NULL; p->conn = NULL;
goto error; fput(p->rd);
fput(p->wr);
return err;
} }
return 0; return 0;
error:
kfree(p);
return err;
} }
static struct p9_trans_module p9_tcp_trans = { static struct p9_trans_module p9_tcp_trans = {

View file

@ -355,68 +355,61 @@ static const struct dentry_operations sockfs_dentry_operations = {
* but we take care of internal coherence yet. * 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; int fd;
fd = get_unused_fd_flags(flags); fd = get_unused_fd_flags(flags);
if (likely(fd >= 0)) { if (unlikely(fd < 0))
struct file *file = get_empty_filp();
*filep = file;
if (unlikely(!file)) {
put_unused_fd(fd);
return -ENFILE;
}
} else
*filep = NULL;
return fd; return fd;
}
static int sock_attach_fd(struct socket *sock, struct file *file, int flags) path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name);
{ if (unlikely(!path.dentry)) {
struct dentry *dentry; put_unused_fd(fd);
struct qstr name = { .name = "" };
dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name);
if (unlikely(!dentry))
return -ENOMEM; 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 dont want to push this dentry into global dentry hash table.
* We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED * We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED
* This permits a working /proc/$pid/fd/XXX on sockets * This permits a working /proc/$pid/fd/XXX on sockets
*/ */
dentry->d_flags &= ~DCACHE_UNHASHED; path.dentry->d_flags &= ~DCACHE_UNHASHED;
d_instantiate(dentry, SOCK_INODE(sock)); 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; 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_flags = O_RDWR | (flags & O_NONBLOCK);
file->f_pos = 0; file->f_pos = 0;
file->private_data = sock; file->private_data = sock;
return 0; *f = file;
return fd;
} }
int sock_map_fd(struct socket *sock, int flags) int sock_map_fd(struct socket *sock, int flags)
{ {
struct file *newfile; struct file *newfile;
int fd = sock_alloc_fd(&newfile, flags); int fd = sock_alloc_file(sock, &newfile, flags);
if (likely(fd >= 0)) { 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;
}
fd_install(fd, newfile); fd_install(fd, newfile);
}
return fd; return fd;
} }
@ -1390,29 +1383,19 @@ SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol,
if (err < 0) if (err < 0)
goto out_release_both; goto out_release_both;
fd1 = sock_alloc_fd(&newfile1, flags & O_CLOEXEC); fd1 = sock_alloc_file(sock1, &newfile1, flags);
if (unlikely(fd1 < 0)) { if (unlikely(fd1 < 0)) {
err = fd1; err = fd1;
goto out_release_both; goto out_release_both;
} }
fd2 = sock_alloc_fd(&newfile2, flags & O_CLOEXEC); fd2 = sock_alloc_file(sock2, &newfile2, flags);
if (unlikely(fd2 < 0)) { if (unlikely(fd2 < 0)) {
err = fd2; 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); fput(newfile1);
goto out_fd1; put_unused_fd(fd1);
sock_release(sock2);
goto out;
} }
audit_fd_pair(fd1, fd2); audit_fd_pair(fd1, fd2);
@ -1438,16 +1421,6 @@ out_release_1:
sock_release(sock1); sock_release(sock1);
out: out:
return err; 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); __module_get(newsock->ops->owner);
newfd = sock_alloc_fd(&newfile, flags & O_CLOEXEC); newfd = sock_alloc_file(newsock, &newfile, flags);
if (unlikely(newfd < 0)) { if (unlikely(newfd < 0)) {
err = newfd; err = newfd;
sock_release(newsock); sock_release(newsock);
goto out_put; 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); err = security_socket_accept(sock, newsock);
if (err) if (err)
goto out_fd; goto out_fd;
@ -1591,11 +1560,6 @@ out_put:
fput_light(sock->file, fput_needed); fput_light(sock->file, fput_needed);
out: out:
return err; return err;
out_fd_simple:
sock_release(newsock);
put_filp(newfile);
put_unused_fd(newfd);
goto out_put;
out_fd: out_fd:
fput(newfile); fput(newfile);
put_unused_fd(newfd); put_unused_fd(newfd);

View file

@ -97,7 +97,6 @@ static inline unsigned long ima_hash_key(u8 *digest)
/* iint cache flags */ /* iint cache flags */
#define IMA_MEASURED 1 #define IMA_MEASURED 1
#define IMA_IINT_DUMP_STACK 512
/* integrity data associated with an inode */ /* integrity data associated with an inode */
struct ima_iint_cache { 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_insert(struct inode *inode);
struct ima_iint_cache *ima_iint_find_get(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_free(struct kref *kref);
void iint_rcu_free(struct rcu_head *rcu); void iint_rcu_free(struct rcu_head *rcu);

View file

@ -19,8 +19,6 @@
#include <linux/radix-tree.h> #include <linux/radix-tree.h>
#include "ima.h" #include "ima.h"
#define ima_iint_delete ima_inode_free
RADIX_TREE(ima_iint_store, GFP_ATOMIC); RADIX_TREE(ima_iint_store, GFP_ATOMIC);
DEFINE_SPINLOCK(ima_iint_lock); DEFINE_SPINLOCK(ima_iint_lock);
@ -45,22 +43,21 @@ out:
return iint; return iint;
} }
/* Allocate memory for the iint associated with the inode /**
* from the iint_cache slab, initialize the iint, and * ima_inode_alloc - allocate an iint associated with an inode
* insert it into the radix tree. * @inode: pointer to the inode
*
* On success return a pointer to the iint; on failure return NULL.
*/ */
struct ima_iint_cache *ima_iint_insert(struct inode *inode) int ima_inode_alloc(struct inode *inode)
{ {
struct ima_iint_cache *iint = NULL; struct ima_iint_cache *iint = NULL;
int rc = 0; int rc = 0;
if (!ima_initialized) if (!ima_initialized)
return iint; return 0;
iint = kmem_cache_alloc(iint_cache, GFP_NOFS); iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
if (!iint) if (!iint)
return iint; return -ENOMEM;
rc = radix_tree_preload(GFP_NOFS); rc = radix_tree_preload(GFP_NOFS);
if (rc < 0) 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); rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint);
spin_unlock(&ima_iint_lock); spin_unlock(&ima_iint_lock);
out: out:
if (rc < 0) { if (rc < 0)
kmem_cache_free(iint_cache, iint); 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(); 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 */ /* iint_free - called when the iint refcount goes to zero */
void iint_free(struct kref *kref) 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 * @inode: pointer to the inode
* *
* Free the integrity information(iint) associated with an 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; struct ima_iint_cache *iint;

View file

@ -35,6 +35,100 @@ static int __init hash_setup(char *str)
} }
__setup("ima_hash=", hash_setup); __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() * ima_file_free - called on __fput()
* @file: pointer to file structure being freed * @file: pointer to file structure being freed
@ -54,29 +148,7 @@ void ima_file_free(struct file *file)
return; return;
mutex_lock(&iint->mutex); mutex_lock(&iint->mutex);
if (iint->opencount <= 0) { ima_dec_counts(iint, inode, file);
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;
}
}
mutex_unlock(&iint->mutex); mutex_unlock(&iint->mutex);
kref_put(&iint->refcount, iint_free); 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; int rc = 0;
iint->opencount++; ima_inc_counts(iint, file->f_mode);
iint->readcount++;
rc = ima_collect_measurement(iint, file); rc = ima_collect_measurement(iint, file);
if (!rc) if (!rc)
@ -125,15 +196,6 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file,
return rc; 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. * ima_path_check - based on policy, collect/store measurement.
* @path: contains a pointer to the path to be measured * @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. * Always return 0 and audit dentry_open failures.
* (Return code will be based upon measurement appraisal.) * (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 inode *inode = path->dentry->d_inode;
struct ima_iint_cache *iint; 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)) if (!ima_initialized || !S_ISREG(inode->i_mode))
return 0; return 0;
iint = ima_iint_find_insert_get(inode); iint = ima_iint_find_get(inode);
if (!iint) if (!iint)
return 0; return 0;
mutex_lock(&iint->mutex); mutex_lock(&iint->mutex);
if (update_counts)
ima_update_counts(iint, mask);
rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK); rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK);
if (rc < 0) 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)) if (!ima_initialized || !S_ISREG(inode->i_mode))
return 0; return 0;
iint = ima_iint_find_insert_get(inode); iint = ima_iint_find_get(inode);
if (!iint) if (!iint)
return -ENOMEM; return -ENOMEM;
@ -237,39 +297,6 @@ out:
return rc; 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 * 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)) if (!ima_initialized || !S_ISREG(inode->i_mode))
return; return;
iint = ima_iint_find_insert_get(inode); iint = ima_iint_find_get(inode);
if (!iint) if (!iint)
return; return;
mutex_lock(&iint->mutex); mutex_lock(&iint->mutex);
iint->opencount++; ima_inc_counts(iint, file->f_mode);
if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
iint->readcount++;
if (file->f_mode & FMODE_WRITE)
iint->writecount++;
mutex_unlock(&iint->mutex); mutex_unlock(&iint->mutex);
kref_put(&iint->refcount, iint_free); kref_put(&iint->refcount, iint_free);