fs: provide rcu-walk aware permission i_ops
Signed-off-by: Nick Piggin <npiggin@kernel.dk>
This commit is contained in:
parent
34286d6662
commit
b74c79e993
|
@ -47,8 +47,8 @@ ata *);
|
|||
void * (*follow_link) (struct dentry *, struct nameidata *);
|
||||
void (*put_link) (struct dentry *, struct nameidata *, void *);
|
||||
void (*truncate) (struct inode *);
|
||||
int (*permission) (struct inode *, int, struct nameidata *);
|
||||
int (*check_acl)(struct inode *, int);
|
||||
int (*permission) (struct inode *, int, unsigned int);
|
||||
int (*check_acl)(struct inode *, int, unsigned int);
|
||||
int (*setattr) (struct dentry *, struct iattr *);
|
||||
int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *);
|
||||
int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
|
||||
|
@ -76,7 +76,7 @@ follow_link: no
|
|||
put_link: no
|
||||
truncate: yes (see below)
|
||||
setattr: yes
|
||||
permission: no
|
||||
permission: no (may not block if called in rcu-walk mode)
|
||||
check_acl: no
|
||||
getattr: no
|
||||
setxattr: yes
|
||||
|
|
|
@ -316,11 +316,9 @@ The detailed design for rcu-walk is like this:
|
|||
|
||||
The cases where rcu-walk cannot continue are:
|
||||
* NULL dentry (ie. any uncached path element)
|
||||
* parent with d_inode->i_op->permission or ACLs
|
||||
* Following links
|
||||
|
||||
In future patches, permission checks become rcu-walk aware. It may be possible
|
||||
eventually to make following links rcu-walk aware.
|
||||
It may be possible eventually to make following links rcu-walk aware.
|
||||
|
||||
Uncached path elements will always require dropping to ref-walk mode, at the
|
||||
very least because i_mutex needs to be grabbed, and objects allocated.
|
||||
|
@ -336,9 +334,49 @@ or stored into. The result is massive improvements in performance and
|
|||
scalability of path resolution.
|
||||
|
||||
|
||||
Interesting statistics
|
||||
======================
|
||||
|
||||
The following table gives rcu lookup statistics for a few simple workloads
|
||||
(2s12c24t Westmere, debian non-graphical system). Ungraceful are attempts to
|
||||
drop rcu that fail due to d_seq failure and requiring the entire path lookup
|
||||
again. Other cases are successful rcu-drops that are required before the final
|
||||
element, nodentry for missing dentry, revalidate for filesystem revalidate
|
||||
routine requiring rcu drop, permission for permission check requiring drop,
|
||||
and link for symlink traversal requiring drop.
|
||||
|
||||
rcu-lookups restart nodentry link revalidate permission
|
||||
bootup 47121 0 4624 1010 10283 7852
|
||||
dbench 25386793 0 6778659(26.7%) 55 549 1156
|
||||
kbuild 2696672 10 64442(2.3%) 108764(4.0%) 1 1590
|
||||
git diff 39605 0 28 2 0 106
|
||||
vfstest 24185492 4945 708725(2.9%) 1076136(4.4%) 0 2651
|
||||
|
||||
What this shows is that failed rcu-walk lookups, ie. ones that are restarted
|
||||
entirely with ref-walk, are quite rare. Even the "vfstest" case which
|
||||
specifically has concurrent renames/mkdir/rmdir/ creat/unlink/etc to excercise
|
||||
such races is not showing a huge amount of restarts.
|
||||
|
||||
Dropping from rcu-walk to ref-walk mean that we have encountered a dentry where
|
||||
the reference count needs to be taken for some reason. This is either because
|
||||
we have reached the target of the path walk, or because we have encountered a
|
||||
condition that can't be resolved in rcu-walk mode. Ideally, we drop rcu-walk
|
||||
only when we have reached the target dentry, so the other statistics show where
|
||||
this does not happen.
|
||||
|
||||
Note that a graceful drop from rcu-walk mode due to something such as the
|
||||
dentry not existing (which can be common) is not necessarily a failure of
|
||||
rcu-walk scheme, because some elements of the path may have been walked in
|
||||
rcu-walk mode. The further we get from common path elements (such as cwd or
|
||||
root), the less contended the dentry is likely to be. The closer we are to
|
||||
common path elements, the more likely they will exist in dentry cache.
|
||||
|
||||
|
||||
Papers and other documentation on dcache locking
|
||||
================================================
|
||||
|
||||
1. Scaling dcache with RCU (http://linuxjournal.com/article.php?sid=7124).
|
||||
|
||||
2. http://lse.sourceforge.net/locking/dcache/dcache.html
|
||||
|
||||
|
||||
|
|
|
@ -379,4 +379,9 @@ where possible.
|
|||
the filesystem provides it), which requires dropping out of rcu-walk mode. This
|
||||
may now be called in rcu-walk mode (nd->flags & LOOKUP_RCU). -ECHILD should be
|
||||
returned if the filesystem cannot handle rcu-walk. See
|
||||
Documentation/filesystems/vfs.txt for more details.
|
||||
|
||||
permission and check_acl are inode permission checks that are called
|
||||
on many or all directory inodes on the way down a path walk (to check for
|
||||
exec permission). These must now be rcu-walk aware (flags & IPERM_RCU). See
|
||||
Documentation/filesystems/vfs.txt for more details.
|
||||
|
|
|
@ -325,7 +325,8 @@ struct inode_operations {
|
|||
void * (*follow_link) (struct dentry *, struct nameidata *);
|
||||
void (*put_link) (struct dentry *, struct nameidata *, void *);
|
||||
void (*truncate) (struct inode *);
|
||||
int (*permission) (struct inode *, int, struct nameidata *);
|
||||
int (*permission) (struct inode *, int, unsigned int);
|
||||
int (*check_acl)(struct inode *, int, unsigned int);
|
||||
int (*setattr) (struct dentry *, struct iattr *);
|
||||
int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
|
||||
int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
|
||||
|
@ -414,6 +415,13 @@ otherwise noted.
|
|||
permission: called by the VFS to check for access rights on a POSIX-like
|
||||
filesystem.
|
||||
|
||||
May be called in rcu-walk mode (flags & IPERM_RCU). If in rcu-walk
|
||||
mode, the filesystem must check the permission without blocking or
|
||||
storing to the inode.
|
||||
|
||||
If a situation is encountered that rcu-walk cannot handle, return
|
||||
-ECHILD and it will be called again in ref-walk mode.
|
||||
|
||||
setattr: called by the VFS to set attributes for a file. This method
|
||||
is called by chmod(2) and related system calls.
|
||||
|
||||
|
|
|
@ -407,11 +407,14 @@ smb_file_release(struct inode *inode, struct file * file)
|
|||
* privileges, so we need our own check for this.
|
||||
*/
|
||||
static int
|
||||
smb_file_permission(struct inode *inode, int mask)
|
||||
smb_file_permission(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
int mode = inode->i_mode;
|
||||
int error = 0;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
VERBOSE("mode=%x, mask=%x\n", mode, mask);
|
||||
|
||||
/* Look at user permissions */
|
||||
|
|
|
@ -91,11 +91,14 @@ static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type)
|
|||
return acl;
|
||||
}
|
||||
|
||||
int v9fs_check_acl(struct inode *inode, int mask)
|
||||
int v9fs_check_acl(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
struct v9fs_session_info *v9ses;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
v9ses = v9fs_inode2v9ses(inode);
|
||||
if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) {
|
||||
/*
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
#ifdef CONFIG_9P_FS_POSIX_ACL
|
||||
extern int v9fs_get_acl(struct inode *, struct p9_fid *);
|
||||
extern int v9fs_check_acl(struct inode *inode, int mask);
|
||||
extern int v9fs_check_acl(struct inode *inode, int mask, unsigned int flags);
|
||||
extern int v9fs_acl_chmod(struct dentry *);
|
||||
extern int v9fs_set_create_acl(struct dentry *,
|
||||
struct posix_acl *, struct posix_acl *);
|
||||
|
|
|
@ -624,7 +624,7 @@ extern void afs_clear_permits(struct afs_vnode *);
|
|||
extern void afs_cache_permit(struct afs_vnode *, struct key *, long);
|
||||
extern void afs_zap_permits(struct rcu_head *);
|
||||
extern struct key *afs_request_key(struct afs_cell *);
|
||||
extern int afs_permission(struct inode *, int);
|
||||
extern int afs_permission(struct inode *, int, unsigned int);
|
||||
|
||||
/*
|
||||
* server.c
|
||||
|
|
|
@ -285,13 +285,16 @@ static int afs_check_permit(struct afs_vnode *vnode, struct key *key,
|
|||
* - AFS ACLs are attached to directories only, and a file is controlled by its
|
||||
* parent directory's ACL
|
||||
*/
|
||||
int afs_permission(struct inode *inode, int mask)
|
||||
int afs_permission(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
struct afs_vnode *vnode = AFS_FS_I(inode);
|
||||
afs_access_t uninitialized_var(access);
|
||||
struct key *key;
|
||||
int ret;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
_enter("{{%x:%u},%lx},%x,",
|
||||
vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask);
|
||||
|
||||
|
@ -347,7 +350,7 @@ int afs_permission(struct inode *inode, int mask)
|
|||
}
|
||||
|
||||
key_put(key);
|
||||
ret = generic_permission(inode, mask, NULL);
|
||||
ret = generic_permission(inode, mask, flags, NULL);
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -229,8 +229,11 @@ static int bad_inode_readlink(struct dentry *dentry, char __user *buffer,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
static int bad_inode_permission(struct inode *inode, int mask)
|
||||
static int bad_inode_permission(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
|
|
@ -185,13 +185,15 @@ static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_check_acl(struct inode *inode, int mask)
|
||||
int btrfs_check_acl(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int error = -EAGAIN;
|
||||
|
||||
acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS);
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
if (acl) {
|
||||
|
|
|
@ -2544,7 +2544,7 @@ int btrfs_sync_fs(struct super_block *sb, int wait);
|
|||
|
||||
/* acl.c */
|
||||
#ifdef CONFIG_BTRFS_FS_POSIX_ACL
|
||||
int btrfs_check_acl(struct inode *inode, int mask);
|
||||
int btrfs_check_acl(struct inode *inode, int mask, unsigned int flags);
|
||||
#else
|
||||
#define btrfs_check_acl NULL
|
||||
#endif
|
||||
|
|
|
@ -7211,11 +7211,14 @@ static int btrfs_set_page_dirty(struct page *page)
|
|||
return __set_page_dirty_nobuffers(page);
|
||||
}
|
||||
|
||||
static int btrfs_permission(struct inode *inode, int mask)
|
||||
static int btrfs_permission(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
if ((BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) && (mask & MAY_WRITE))
|
||||
return -EACCES;
|
||||
return generic_permission(inode, mask, btrfs_check_acl);
|
||||
return generic_permission(inode, mask, flags, btrfs_check_acl);
|
||||
}
|
||||
|
||||
static const struct inode_operations btrfs_dir_inode_operations = {
|
||||
|
|
|
@ -1781,12 +1781,17 @@ int ceph_do_getattr(struct inode *inode, int mask)
|
|||
* Check inode permissions. We verify we have a valid value for
|
||||
* the AUTH cap, then call the generic handler.
|
||||
*/
|
||||
int ceph_permission(struct inode *inode, int mask)
|
||||
int ceph_permission(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
int err = ceph_do_getattr(inode, CEPH_CAP_AUTH_SHARED);
|
||||
int err;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
err = ceph_do_getattr(inode, CEPH_CAP_AUTH_SHARED);
|
||||
|
||||
if (!err)
|
||||
err = generic_permission(inode, mask, NULL);
|
||||
err = generic_permission(inode, mask, flags, NULL);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -665,7 +665,7 @@ extern void ceph_queue_invalidate(struct inode *inode);
|
|||
extern void ceph_queue_writeback(struct inode *inode);
|
||||
|
||||
extern int ceph_do_getattr(struct inode *inode, int mask);
|
||||
extern int ceph_permission(struct inode *inode, int mask);
|
||||
extern int ceph_permission(struct inode *inode, int mask, unsigned int flags);
|
||||
extern int ceph_setattr(struct dentry *dentry, struct iattr *attr);
|
||||
extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
||||
struct kstat *stat);
|
||||
|
|
|
@ -283,10 +283,13 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cifs_permission(struct inode *inode, int mask)
|
||||
static int cifs_permission(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
cifs_sb = CIFS_SB(inode->i_sb);
|
||||
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) {
|
||||
|
@ -298,7 +301,7 @@ static int cifs_permission(struct inode *inode, int mask)
|
|||
on the client (above and beyond ACL on servers) for
|
||||
servers which do not support setting and viewing mode bits,
|
||||
so allowing client to check permissions is useful */
|
||||
return generic_permission(inode, mask, NULL);
|
||||
return generic_permission(inode, mask, flags, NULL);
|
||||
}
|
||||
|
||||
static struct kmem_cache *cifs_inode_cachep;
|
||||
|
|
|
@ -135,10 +135,13 @@ exit:
|
|||
}
|
||||
|
||||
|
||||
int coda_permission(struct inode *inode, int mask)
|
||||
int coda_permission(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
|
||||
|
||||
if (!mask)
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include <linux/coda_psdev.h>
|
||||
|
||||
/* pioctl ops */
|
||||
static int coda_ioctl_permission(struct inode *inode, int mask);
|
||||
static int coda_ioctl_permission(struct inode *inode, int mask, unsigned int flags);
|
||||
static long coda_pioctl(struct file *filp, unsigned int cmd,
|
||||
unsigned long user_data);
|
||||
|
||||
|
@ -41,8 +41,10 @@ const struct file_operations coda_ioctl_operations = {
|
|||
};
|
||||
|
||||
/* the coda pioctl inode ops */
|
||||
static int coda_ioctl_permission(struct inode *inode, int mask)
|
||||
static int coda_ioctl_permission(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
return (mask & MAY_EXEC) ? -EACCES : 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -980,8 +980,10 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
|
|||
}
|
||||
|
||||
static int
|
||||
ecryptfs_permission(struct inode *inode, int mask)
|
||||
ecryptfs_permission(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
return inode_permission(ecryptfs_inode_to_lower(inode), mask);
|
||||
}
|
||||
|
||||
|
|
|
@ -232,10 +232,14 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
|
|||
}
|
||||
|
||||
int
|
||||
ext2_check_acl(struct inode *inode, int mask)
|
||||
ext2_check_acl(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
struct posix_acl *acl = ext2_get_acl(inode, ACL_TYPE_ACCESS);
|
||||
struct posix_acl *acl;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
acl = ext2_get_acl(inode, ACL_TYPE_ACCESS);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
if (acl) {
|
||||
|
|
|
@ -54,7 +54,7 @@ static inline int ext2_acl_count(size_t size)
|
|||
#ifdef CONFIG_EXT2_FS_POSIX_ACL
|
||||
|
||||
/* acl.c */
|
||||
extern int ext2_check_acl (struct inode *, int);
|
||||
extern int ext2_check_acl (struct inode *, int, unsigned int);
|
||||
extern int ext2_acl_chmod (struct inode *);
|
||||
extern int ext2_init_acl (struct inode *, struct inode *);
|
||||
|
||||
|
|
|
@ -240,10 +240,14 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type,
|
|||
}
|
||||
|
||||
int
|
||||
ext3_check_acl(struct inode *inode, int mask)
|
||||
ext3_check_acl(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
struct posix_acl *acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);
|
||||
struct posix_acl *acl;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
if (acl) {
|
||||
|
|
|
@ -54,7 +54,7 @@ static inline int ext3_acl_count(size_t size)
|
|||
#ifdef CONFIG_EXT3_FS_POSIX_ACL
|
||||
|
||||
/* acl.c */
|
||||
extern int ext3_check_acl (struct inode *, int);
|
||||
extern int ext3_check_acl (struct inode *, int, unsigned int);
|
||||
extern int ext3_acl_chmod (struct inode *);
|
||||
extern int ext3_init_acl (handle_t *, struct inode *, struct inode *);
|
||||
|
||||
|
|
|
@ -238,10 +238,14 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type,
|
|||
}
|
||||
|
||||
int
|
||||
ext4_check_acl(struct inode *inode, int mask)
|
||||
ext4_check_acl(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
struct posix_acl *acl = ext4_get_acl(inode, ACL_TYPE_ACCESS);
|
||||
struct posix_acl *acl;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
acl = ext4_get_acl(inode, ACL_TYPE_ACCESS);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
if (acl) {
|
||||
|
|
|
@ -54,7 +54,7 @@ static inline int ext4_acl_count(size_t size)
|
|||
#ifdef CONFIG_EXT4_FS_POSIX_ACL
|
||||
|
||||
/* acl.c */
|
||||
extern int ext4_check_acl(struct inode *, int);
|
||||
extern int ext4_check_acl(struct inode *, int, unsigned int);
|
||||
extern int ext4_acl_chmod(struct inode *);
|
||||
extern int ext4_init_acl(handle_t *, struct inode *, struct inode *);
|
||||
|
||||
|
|
|
@ -985,12 +985,15 @@ static int fuse_access(struct inode *inode, int mask)
|
|||
* access request is sent. Execute permission is still checked
|
||||
* locally based on file mode.
|
||||
*/
|
||||
static int fuse_permission(struct inode *inode, int mask)
|
||||
static int fuse_permission(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
struct fuse_conn *fc = get_fuse_conn(inode);
|
||||
bool refreshed = false;
|
||||
int err = 0;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
if (!fuse_allow_task(fc, current))
|
||||
return -EACCES;
|
||||
|
||||
|
@ -1005,7 +1008,7 @@ static int fuse_permission(struct inode *inode, int mask)
|
|||
}
|
||||
|
||||
if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
|
||||
err = generic_permission(inode, mask, NULL);
|
||||
err = generic_permission(inode, mask, flags, NULL);
|
||||
|
||||
/* If permission is denied, try to refresh file
|
||||
attributes. This is also needed, because the root
|
||||
|
@ -1013,7 +1016,8 @@ static int fuse_permission(struct inode *inode, int mask)
|
|||
if (err == -EACCES && !refreshed) {
|
||||
err = fuse_do_getattr(inode, NULL, NULL);
|
||||
if (!err)
|
||||
err = generic_permission(inode, mask, NULL);
|
||||
err = generic_permission(inode, mask,
|
||||
flags, NULL);
|
||||
}
|
||||
|
||||
/* Note: the opposite of the above test does not
|
||||
|
|
|
@ -190,10 +190,14 @@ generic_acl_chmod(struct inode *inode)
|
|||
}
|
||||
|
||||
int
|
||||
generic_check_acl(struct inode *inode, int mask)
|
||||
generic_check_acl(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
struct posix_acl *acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
|
||||
struct posix_acl *acl;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
|
||||
if (acl) {
|
||||
int error = posix_acl_permission(inode, acl, mask);
|
||||
posix_acl_release(acl);
|
||||
|
|
|
@ -75,11 +75,14 @@ static struct posix_acl *gfs2_acl_get(struct gfs2_inode *ip, int type)
|
|||
* Returns: errno
|
||||
*/
|
||||
|
||||
int gfs2_check_acl(struct inode *inode, int mask)
|
||||
int gfs2_check_acl(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int error;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
acl = gfs2_acl_get(GFS2_I(inode), ACL_TYPE_ACCESS);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#define GFS2_POSIX_ACL_DEFAULT "posix_acl_default"
|
||||
#define GFS2_ACL_MAX_ENTRIES 25
|
||||
|
||||
extern int gfs2_check_acl(struct inode *inode, int mask);
|
||||
extern int gfs2_check_acl(struct inode *inode, int mask, unsigned int);
|
||||
extern int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode);
|
||||
extern int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr);
|
||||
extern const struct xattr_handler gfs2_xattr_system_handler;
|
||||
|
|
|
@ -241,7 +241,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
|
|||
!capable(CAP_LINUX_IMMUTABLE))
|
||||
goto out;
|
||||
if (!IS_IMMUTABLE(inode)) {
|
||||
error = gfs2_permission(inode, MAY_WRITE);
|
||||
error = gfs2_permission(inode, MAY_WRITE, 0);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -509,7 +509,7 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
|
|||
}
|
||||
|
||||
if (!is_root) {
|
||||
error = gfs2_permission(dir, MAY_EXEC);
|
||||
error = gfs2_permission(dir, MAY_EXEC, 0);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
|
@ -539,7 +539,7 @@ static int create_ok(struct gfs2_inode *dip, const struct qstr *name,
|
|||
{
|
||||
int error;
|
||||
|
||||
error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC);
|
||||
error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, 0);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
|
|||
extern struct inode *gfs2_createi(struct gfs2_holder *ghs,
|
||||
const struct qstr *name,
|
||||
unsigned int mode, dev_t dev);
|
||||
extern int gfs2_permission(struct inode *inode, int mask);
|
||||
extern int gfs2_permission(struct inode *inode, int mask, unsigned int flags);
|
||||
extern int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr);
|
||||
extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name);
|
||||
extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf);
|
||||
|
|
|
@ -166,7 +166,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
|
|||
if (error)
|
||||
goto out_child;
|
||||
|
||||
error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC);
|
||||
error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC, 0);
|
||||
if (error)
|
||||
goto out_gunlock;
|
||||
|
||||
|
@ -289,7 +289,7 @@ static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
|
|||
if (IS_APPEND(&dip->i_inode))
|
||||
return -EPERM;
|
||||
|
||||
error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC);
|
||||
error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, 0);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -822,7 +822,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
error = gfs2_permission(ndir, MAY_WRITE | MAY_EXEC);
|
||||
error = gfs2_permission(ndir, MAY_WRITE | MAY_EXEC, 0);
|
||||
if (error)
|
||||
goto out_gunlock;
|
||||
|
||||
|
@ -857,7 +857,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
|
|||
/* Check out the dir to be renamed */
|
||||
|
||||
if (dir_rename) {
|
||||
error = gfs2_permission(odentry->d_inode, MAY_WRITE);
|
||||
error = gfs2_permission(odentry->d_inode, MAY_WRITE, 0);
|
||||
if (error)
|
||||
goto out_gunlock;
|
||||
}
|
||||
|
@ -1041,13 +1041,17 @@ static void gfs2_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
|
|||
* Returns: errno
|
||||
*/
|
||||
|
||||
int gfs2_permission(struct inode *inode, int mask)
|
||||
int gfs2_permission(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct gfs2_inode *ip;
|
||||
struct gfs2_holder i_gh;
|
||||
int error;
|
||||
int unlock = 0;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
ip = GFS2_I(inode);
|
||||
if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) {
|
||||
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
|
||||
if (error)
|
||||
|
@ -1058,7 +1062,7 @@ int gfs2_permission(struct inode *inode, int mask)
|
|||
if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode))
|
||||
error = -EACCES;
|
||||
else
|
||||
error = generic_permission(inode, mask, gfs2_check_acl);
|
||||
error = generic_permission(inode, mask, flags, gfs2_check_acl);
|
||||
if (unlock)
|
||||
gfs2_glock_dq_uninit(&i_gh);
|
||||
|
||||
|
|
|
@ -749,11 +749,14 @@ int hostfs_rename(struct inode *from_ino, struct dentry *from,
|
|||
return err;
|
||||
}
|
||||
|
||||
int hostfs_permission(struct inode *ino, int desired)
|
||||
int hostfs_permission(struct inode *ino, int desired, unsigned int flags)
|
||||
{
|
||||
char *name;
|
||||
int r = 0, w = 0, x = 0, err;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
if (desired & MAY_READ) r = 1;
|
||||
if (desired & MAY_WRITE) w = 1;
|
||||
if (desired & MAY_EXEC) x = 1;
|
||||
|
@ -768,7 +771,7 @@ int hostfs_permission(struct inode *ino, int desired)
|
|||
err = access_file(name, r, w, x);
|
||||
__putname(name);
|
||||
if (!err)
|
||||
err = generic_permission(ino, desired, NULL);
|
||||
err = generic_permission(ino, desired, flags, NULL);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -419,7 +419,7 @@ again:
|
|||
unlock_kernel();
|
||||
return -ENOSPC;
|
||||
}
|
||||
if (generic_permission(inode, MAY_WRITE, NULL) ||
|
||||
if (generic_permission(inode, MAY_WRITE, 0, NULL) ||
|
||||
!S_ISREG(inode->i_mode) ||
|
||||
get_write_access(inode)) {
|
||||
d_rehash(dentry);
|
||||
|
|
|
@ -259,11 +259,14 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
|
|||
return rc;
|
||||
}
|
||||
|
||||
int jffs2_check_acl(struct inode *inode, int mask)
|
||||
int jffs2_check_acl(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int rc;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
|
|
|
@ -26,7 +26,7 @@ struct jffs2_acl_header {
|
|||
|
||||
#ifdef CONFIG_JFFS2_FS_POSIX_ACL
|
||||
|
||||
extern int jffs2_check_acl(struct inode *, int);
|
||||
extern int jffs2_check_acl(struct inode *, int, unsigned int);
|
||||
extern int jffs2_acl_chmod(struct inode *);
|
||||
extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *);
|
||||
extern int jffs2_init_acl_post(struct inode *);
|
||||
|
|
|
@ -114,10 +114,14 @@ out:
|
|||
return rc;
|
||||
}
|
||||
|
||||
int jfs_check_acl(struct inode *inode, int mask)
|
||||
int jfs_check_acl(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
struct posix_acl *acl = jfs_get_acl(inode, ACL_TYPE_ACCESS);
|
||||
struct posix_acl *acl;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
acl = jfs_get_acl(inode, ACL_TYPE_ACCESS);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
if (acl) {
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#ifdef CONFIG_JFS_POSIX_ACL
|
||||
|
||||
int jfs_check_acl(struct inode *, int);
|
||||
int jfs_check_acl(struct inode *, int, unsigned int flags);
|
||||
int jfs_init_acl(tid_t, struct inode *, struct inode *);
|
||||
int jfs_acl_chmod(struct inode *inode);
|
||||
|
||||
|
|
|
@ -555,9 +555,11 @@ static int logfs_symlink(struct inode *dir, struct dentry *dentry,
|
|||
return __logfs_create(dir, dentry, inode, target, destlen);
|
||||
}
|
||||
|
||||
static int logfs_permission(struct inode *inode, int mask)
|
||||
static int logfs_permission(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
return generic_permission(inode, mask, NULL);
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
return generic_permission(inode, mask, flags, NULL);
|
||||
}
|
||||
|
||||
static int logfs_link(struct dentry *old_dentry, struct inode *dir,
|
||||
|
|
69
fs/namei.c
69
fs/namei.c
|
@ -169,8 +169,8 @@ EXPORT_SYMBOL(putname);
|
|||
/*
|
||||
* This does basic POSIX ACL permission checking
|
||||
*/
|
||||
static inline int __acl_permission_check(struct inode *inode, int mask,
|
||||
int (*check_acl)(struct inode *inode, int mask), int rcu)
|
||||
static int acl_permission_check(struct inode *inode, int mask, unsigned int flags,
|
||||
int (*check_acl)(struct inode *inode, int mask, unsigned int flags))
|
||||
{
|
||||
umode_t mode = inode->i_mode;
|
||||
|
||||
|
@ -180,14 +180,10 @@ static inline int __acl_permission_check(struct inode *inode, int mask,
|
|||
mode >>= 6;
|
||||
else {
|
||||
if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) {
|
||||
if (rcu) {
|
||||
return -ECHILD;
|
||||
} else {
|
||||
int error = check_acl(inode, mask);
|
||||
int error = check_acl(inode, mask, flags);
|
||||
if (error != -EAGAIN)
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
if (in_group_p(inode->i_gid))
|
||||
mode >>= 3;
|
||||
|
@ -201,32 +197,31 @@ static inline int __acl_permission_check(struct inode *inode, int mask,
|
|||
return -EACCES;
|
||||
}
|
||||
|
||||
static inline int acl_permission_check(struct inode *inode, int mask,
|
||||
int (*check_acl)(struct inode *inode, int mask))
|
||||
{
|
||||
return __acl_permission_check(inode, mask, check_acl, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* generic_permission - check for access rights on a Posix-like filesystem
|
||||
* @inode: inode to check access rights for
|
||||
* @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
|
||||
* @check_acl: optional callback to check for Posix ACLs
|
||||
* @flags IPERM_FLAG_ flags.
|
||||
*
|
||||
* Used to check for read/write/execute permissions on a file.
|
||||
* We use "fsuid" for this, letting us set arbitrary permissions
|
||||
* for filesystem access without changing the "normal" uids which
|
||||
* are used for other things..
|
||||
* are used for other things.
|
||||
*
|
||||
* generic_permission is rcu-walk aware. It returns -ECHILD in case an rcu-walk
|
||||
* request cannot be satisfied (eg. requires blocking or too much complexity).
|
||||
* It would then be called again in ref-walk mode.
|
||||
*/
|
||||
int generic_permission(struct inode *inode, int mask,
|
||||
int (*check_acl)(struct inode *inode, int mask))
|
||||
int generic_permission(struct inode *inode, int mask, unsigned int flags,
|
||||
int (*check_acl)(struct inode *inode, int mask, unsigned int flags))
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Do the basic POSIX ACL permission checks.
|
||||
*/
|
||||
ret = acl_permission_check(inode, mask, check_acl);
|
||||
ret = acl_permission_check(inode, mask, flags, check_acl);
|
||||
if (ret != -EACCES)
|
||||
return ret;
|
||||
|
||||
|
@ -281,9 +276,10 @@ int inode_permission(struct inode *inode, int mask)
|
|||
}
|
||||
|
||||
if (inode->i_op->permission)
|
||||
retval = inode->i_op->permission(inode, mask);
|
||||
retval = inode->i_op->permission(inode, mask, 0);
|
||||
else
|
||||
retval = generic_permission(inode, mask, inode->i_op->check_acl);
|
||||
retval = generic_permission(inode, mask, 0,
|
||||
inode->i_op->check_acl);
|
||||
|
||||
if (retval)
|
||||
return retval;
|
||||
|
@ -668,22 +664,19 @@ force_reval_path(struct path *path, struct nameidata *nd)
|
|||
* short-cut DAC fails, then call ->permission() to do more
|
||||
* complete permission check.
|
||||
*/
|
||||
static inline int __exec_permission(struct inode *inode, int rcu)
|
||||
static inline int exec_permission(struct inode *inode, unsigned int flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (inode->i_op->permission) {
|
||||
if (rcu)
|
||||
return -ECHILD;
|
||||
ret = inode->i_op->permission(inode, MAY_EXEC);
|
||||
if (!ret)
|
||||
goto ok;
|
||||
return ret;
|
||||
ret = inode->i_op->permission(inode, MAY_EXEC, flags);
|
||||
} else {
|
||||
ret = acl_permission_check(inode, MAY_EXEC, flags,
|
||||
inode->i_op->check_acl);
|
||||
}
|
||||
ret = __acl_permission_check(inode, MAY_EXEC, inode->i_op->check_acl, rcu);
|
||||
if (!ret)
|
||||
if (likely(!ret))
|
||||
goto ok;
|
||||
if (rcu && ret == -ECHILD)
|
||||
if (ret == -ECHILD)
|
||||
return ret;
|
||||
|
||||
if (capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH))
|
||||
|
@ -691,17 +684,7 @@ static inline int __exec_permission(struct inode *inode, int rcu)
|
|||
|
||||
return ret;
|
||||
ok:
|
||||
return security_inode_exec_permission(inode, rcu);
|
||||
}
|
||||
|
||||
static int exec_permission(struct inode *inode)
|
||||
{
|
||||
return __exec_permission(inode, 0);
|
||||
}
|
||||
|
||||
static int exec_permission_rcu(struct inode *inode)
|
||||
{
|
||||
return __exec_permission(inode, 1);
|
||||
return security_inode_exec_permission(inode, flags);
|
||||
}
|
||||
|
||||
static __always_inline void set_root(struct nameidata *nd)
|
||||
|
@ -1165,7 +1148,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
|
|||
|
||||
nd->flags |= LOOKUP_CONTINUE;
|
||||
if (nd->flags & LOOKUP_RCU) {
|
||||
err = exec_permission_rcu(nd->inode);
|
||||
err = exec_permission(nd->inode, IPERM_FLAG_RCU);
|
||||
if (err == -ECHILD) {
|
||||
if (nameidata_drop_rcu(nd))
|
||||
return -ECHILD;
|
||||
|
@ -1173,7 +1156,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
|
|||
}
|
||||
} else {
|
||||
exec_again:
|
||||
err = exec_permission(nd->inode);
|
||||
err = exec_permission(nd->inode, 0);
|
||||
}
|
||||
if (err)
|
||||
break;
|
||||
|
@ -1620,7 +1603,7 @@ static struct dentry *__lookup_hash(struct qstr *name,
|
|||
struct dentry *dentry;
|
||||
int err;
|
||||
|
||||
err = exec_permission(inode);
|
||||
err = exec_permission(inode, 0);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
|
|
|
@ -2189,11 +2189,14 @@ int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags)
|
|||
return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags));
|
||||
}
|
||||
|
||||
int nfs_permission(struct inode *inode, int mask)
|
||||
int nfs_permission(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
struct rpc_cred *cred;
|
||||
int res = 0;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
nfs_inc_stats(inode, NFSIOS_VFSACCESS);
|
||||
|
||||
if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
|
||||
|
@ -2241,7 +2244,7 @@ out:
|
|||
out_notsup:
|
||||
res = nfs_revalidate_inode(NFS_SERVER(inode), inode);
|
||||
if (res == 0)
|
||||
res = generic_permission(inode, mask, NULL);
|
||||
res = generic_permission(inode, mask, flags, NULL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
@ -785,15 +785,19 @@ out_err:
|
|||
return err;
|
||||
}
|
||||
|
||||
int nilfs_permission(struct inode *inode, int mask)
|
||||
int nilfs_permission(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
struct nilfs_root *root = NILFS_I(inode)->i_root;
|
||||
struct nilfs_root *root;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
root = NILFS_I(inode)->i_root;
|
||||
if ((mask & MAY_WRITE) && root &&
|
||||
root->cno != NILFS_CPTREE_CURRENT_CNO)
|
||||
return -EROFS; /* snapshot is not writable */
|
||||
|
||||
return generic_permission(inode, mask, NULL);
|
||||
return generic_permission(inode, mask, flags, NULL);
|
||||
}
|
||||
|
||||
int nilfs_load_inode_block(struct nilfs_sb_info *sbi, struct inode *inode,
|
||||
|
|
|
@ -256,7 +256,7 @@ extern void nilfs_update_inode(struct inode *, struct buffer_head *);
|
|||
extern void nilfs_truncate(struct inode *);
|
||||
extern void nilfs_evict_inode(struct inode *);
|
||||
extern int nilfs_setattr(struct dentry *, struct iattr *);
|
||||
int nilfs_permission(struct inode *inode, int mask);
|
||||
int nilfs_permission(struct inode *inode, int mask, unsigned int flags);
|
||||
extern int nilfs_load_inode_block(struct nilfs_sb_info *, struct inode *,
|
||||
struct buffer_head **);
|
||||
extern int nilfs_inode_dirty(struct inode *);
|
||||
|
|
|
@ -291,13 +291,17 @@ static int ocfs2_set_acl(handle_t *handle,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int ocfs2_check_acl(struct inode *inode, int mask)
|
||||
int ocfs2_check_acl(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||||
struct ocfs2_super *osb;
|
||||
struct buffer_head *di_bh = NULL;
|
||||
struct posix_acl *acl;
|
||||
int ret = -EAGAIN;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
osb = OCFS2_SB(inode->i_sb);
|
||||
if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ struct ocfs2_acl_entry {
|
|||
__le32 e_id;
|
||||
};
|
||||
|
||||
extern int ocfs2_check_acl(struct inode *, int);
|
||||
extern int ocfs2_check_acl(struct inode *, int, unsigned int);
|
||||
extern int ocfs2_acl_chmod(struct inode *);
|
||||
extern int ocfs2_init_acl(handle_t *, struct inode *, struct inode *,
|
||||
struct buffer_head *, struct buffer_head *,
|
||||
|
|
|
@ -1307,10 +1307,13 @@ bail:
|
|||
return err;
|
||||
}
|
||||
|
||||
int ocfs2_permission(struct inode *inode, int mask)
|
||||
int ocfs2_permission(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
mlog_entry_void();
|
||||
|
||||
ret = ocfs2_inode_lock(inode, NULL, 0);
|
||||
|
@ -1320,7 +1323,7 @@ int ocfs2_permission(struct inode *inode, int mask)
|
|||
goto out;
|
||||
}
|
||||
|
||||
ret = generic_permission(inode, mask, ocfs2_check_acl);
|
||||
ret = generic_permission(inode, mask, flags, ocfs2_check_acl);
|
||||
|
||||
ocfs2_inode_unlock(inode, 0);
|
||||
out:
|
||||
|
|
|
@ -61,7 +61,7 @@ int ocfs2_zero_extend(struct inode *inode, struct buffer_head *di_bh,
|
|||
int ocfs2_setattr(struct dentry *dentry, struct iattr *attr);
|
||||
int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
||||
struct kstat *stat);
|
||||
int ocfs2_permission(struct inode *inode, int mask);
|
||||
int ocfs2_permission(struct inode *inode, int mask, unsigned int flags);
|
||||
|
||||
int ocfs2_should_update_atime(struct inode *inode,
|
||||
struct vfsmount *vfsmnt);
|
||||
|
|
|
@ -2114,11 +2114,13 @@ static const struct file_operations proc_fd_operations = {
|
|||
* /proc/pid/fd needs a special permission handler so that a process can still
|
||||
* access /proc/self/fd after it has executed a setuid().
|
||||
*/
|
||||
static int proc_fd_permission(struct inode *inode, int mask)
|
||||
static int proc_fd_permission(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = generic_permission(inode, mask, NULL);
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
rv = generic_permission(inode, mask, flags, NULL);
|
||||
if (rv == 0)
|
||||
return 0;
|
||||
if (task_pid(current) == proc_pid(inode))
|
||||
|
|
|
@ -295,7 +295,7 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int proc_sys_permission(struct inode *inode, int mask)
|
||||
static int proc_sys_permission(struct inode *inode, int mask,unsigned int flags)
|
||||
{
|
||||
/*
|
||||
* sysctl entries that are not writeable,
|
||||
|
@ -305,6 +305,9 @@ static int proc_sys_permission(struct inode *inode, int mask)
|
|||
struct ctl_table *table;
|
||||
int error;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
/* Executable files are not allowed under /proc/sys/ */
|
||||
if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))
|
||||
return -EACCES;
|
||||
|
|
|
@ -870,11 +870,14 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
static int reiserfs_check_acl(struct inode *inode, int mask)
|
||||
static int reiserfs_check_acl(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int error = -EAGAIN; /* do regular unix permission checks by default */
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
|
||||
|
||||
if (acl) {
|
||||
|
@ -951,8 +954,10 @@ static int xattr_mount_check(struct super_block *s)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int reiserfs_permission(struct inode *inode, int mask)
|
||||
int reiserfs_permission(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
/*
|
||||
* We don't do permission checks on the internal objects.
|
||||
* Permissions are determined by the "owning" object.
|
||||
|
@ -965,9 +970,10 @@ int reiserfs_permission(struct inode *inode, int mask)
|
|||
* Stat data v1 doesn't support ACLs.
|
||||
*/
|
||||
if (get_inode_sd_version(inode) != STAT_DATA_V1)
|
||||
return generic_permission(inode, mask, reiserfs_check_acl);
|
||||
return generic_permission(inode, mask, flags,
|
||||
reiserfs_check_acl);
|
||||
#endif
|
||||
return generic_permission(inode, mask, NULL);
|
||||
return generic_permission(inode, mask, flags, NULL);
|
||||
}
|
||||
|
||||
static int xattr_hide_revalidate(struct dentry *dentry, struct nameidata *nd)
|
||||
|
|
|
@ -348,13 +348,18 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const cha
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
int sysfs_permission(struct inode *inode, int mask)
|
||||
int sysfs_permission(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
struct sysfs_dirent *sd = inode->i_private;
|
||||
struct sysfs_dirent *sd;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
sd = inode->i_private;
|
||||
|
||||
mutex_lock(&sysfs_mutex);
|
||||
sysfs_refresh_inode(sd, inode);
|
||||
mutex_unlock(&sysfs_mutex);
|
||||
|
||||
return generic_permission(inode, mask, NULL);
|
||||
return generic_permission(inode, mask, flags, NULL);
|
||||
}
|
||||
|
|
|
@ -200,7 +200,7 @@ static inline void __sysfs_put(struct sysfs_dirent *sd)
|
|||
struct inode *sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd);
|
||||
void sysfs_evict_inode(struct inode *inode);
|
||||
int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr);
|
||||
int sysfs_permission(struct inode *inode, int mask);
|
||||
int sysfs_permission(struct inode *inode, int mask, unsigned int flags);
|
||||
int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
|
||||
int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
|
||||
int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value,
|
||||
|
|
|
@ -219,12 +219,16 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
|
|||
}
|
||||
|
||||
int
|
||||
xfs_check_acl(struct inode *inode, int mask)
|
||||
xfs_check_acl(struct inode *inode, int mask, unsigned int flags)
|
||||
{
|
||||
struct xfs_inode *ip = XFS_I(inode);
|
||||
struct xfs_inode *ip;
|
||||
struct posix_acl *acl;
|
||||
int error = -EAGAIN;
|
||||
|
||||
if (flags & IPERM_FLAG_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
ip = XFS_I(inode);
|
||||
trace_xfs_check_acl(ip);
|
||||
|
||||
/*
|
||||
|
|
|
@ -42,7 +42,7 @@ struct xfs_acl {
|
|||
#define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1)
|
||||
|
||||
#ifdef CONFIG_XFS_POSIX_ACL
|
||||
extern int xfs_check_acl(struct inode *inode, int mask);
|
||||
extern int xfs_check_acl(struct inode *inode, int mask, unsigned int flags);
|
||||
extern struct posix_acl *xfs_get_acl(struct inode *inode, int type);
|
||||
extern int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl);
|
||||
extern int xfs_acl_chmod(struct inode *inode);
|
||||
|
|
|
@ -37,7 +37,7 @@ extern const struct file_operations coda_ioctl_operations;
|
|||
/* operations shared over more than one file */
|
||||
int coda_open(struct inode *i, struct file *f);
|
||||
int coda_release(struct inode *i, struct file *f);
|
||||
int coda_permission(struct inode *inode, int mask);
|
||||
int coda_permission(struct inode *inode, int mask, unsigned int flags);
|
||||
int coda_revalidate_inode(struct dentry *);
|
||||
int coda_getattr(struct vfsmount *, struct dentry *, struct kstat *);
|
||||
int coda_setattr(struct dentry *, struct iattr *);
|
||||
|
|
|
@ -1550,11 +1550,13 @@ struct file_operations {
|
|||
int (*setlease)(struct file *, long, struct file_lock **);
|
||||
};
|
||||
|
||||
#define IPERM_FLAG_RCU 0x0001
|
||||
|
||||
struct inode_operations {
|
||||
struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
|
||||
void * (*follow_link) (struct dentry *, struct nameidata *);
|
||||
int (*permission) (struct inode *, int);
|
||||
int (*check_acl)(struct inode *, int);
|
||||
int (*permission) (struct inode *, int, unsigned int);
|
||||
int (*check_acl)(struct inode *, int, unsigned int);
|
||||
|
||||
int (*readlink) (struct dentry *, char __user *,int);
|
||||
void (*put_link) (struct dentry *, struct nameidata *, void *);
|
||||
|
@ -2165,8 +2167,8 @@ extern sector_t bmap(struct inode *, sector_t);
|
|||
#endif
|
||||
extern int notify_change(struct dentry *, struct iattr *);
|
||||
extern int inode_permission(struct inode *, int);
|
||||
extern int generic_permission(struct inode *, int,
|
||||
int (*check_acl)(struct inode *, int));
|
||||
extern int generic_permission(struct inode *, int, unsigned int,
|
||||
int (*check_acl)(struct inode *, int, unsigned int));
|
||||
|
||||
static inline bool execute_ok(struct inode *inode)
|
||||
{
|
||||
|
|
|
@ -10,6 +10,6 @@ extern const struct xattr_handler generic_acl_default_handler;
|
|||
|
||||
int generic_acl_init(struct inode *, struct inode *);
|
||||
int generic_acl_chmod(struct inode *);
|
||||
int generic_check_acl(struct inode *inode, int mask);
|
||||
int generic_check_acl(struct inode *inode, int mask, unsigned int flags);
|
||||
|
||||
#endif /* LINUX_GENERIC_ACL_H */
|
||||
|
|
|
@ -351,7 +351,7 @@ extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
|
|||
extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
|
||||
extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
|
||||
extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
|
||||
extern int nfs_permission(struct inode *, int);
|
||||
extern int nfs_permission(struct inode *, int, unsigned int);
|
||||
extern int nfs_open(struct inode *, struct file *);
|
||||
extern int nfs_release(struct inode *, struct file *);
|
||||
extern int nfs_attribute_timeout(struct inode *inode);
|
||||
|
|
|
@ -41,7 +41,7 @@ int reiserfs_xattr_init(struct super_block *sb, int mount_flags);
|
|||
int reiserfs_lookup_privroot(struct super_block *sb);
|
||||
int reiserfs_delete_xattrs(struct inode *inode);
|
||||
int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs);
|
||||
int reiserfs_permission(struct inode *inode, int mask);
|
||||
int reiserfs_permission(struct inode *inode, int mask, unsigned int flags);
|
||||
|
||||
#ifdef CONFIG_REISERFS_FS_XATTR
|
||||
#define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir)
|
||||
|
|
Loading…
Reference in New Issue