@@ -157,7 +157,7 @@ static int dev_mkdir(const char *name, umode_t mode)
if (IS_ERR(dentry))
return PTR_ERR(dentry);
- err = vfs_mkdir(path.dentry->d_inode, dentry, mode);
+ err = vfs_mkdir(path.dentry, dentry, mode);
if (!err)
/* mark as kernel-created inode */
dentry->d_inode->i_private = &thread;
@@ -207,7 +207,7 @@ static int handle_create(const char *nodename, umode_t mode, kuid_t uid,
if (IS_ERR(dentry))
return PTR_ERR(dentry);
- err = vfs_mknod(path.dentry->d_inode, dentry, mode, dev->devt);
+ err = vfs_mknod(path.dentry, dentry, mode, dev->devt);
if (!err) {
struct iattr newattrs;
@@ -237,7 +237,7 @@ static int dev_rmdir(const char *name)
return PTR_ERR(dentry);
if (dentry->d_inode) {
if (dentry->d_inode->i_private == &thread)
- err = vfs_rmdir(parent.dentry->d_inode, dentry);
+ err = vfs_rmdir(parent.dentry, dentry);
else
err = -EPERM;
} else {
@@ -324,7 +324,7 @@ static int handle_remove(const char *nodename, struct device *dev)
mutex_lock(&dentry->d_inode->i_mutex);
notify_change(dentry, &newattrs, NULL);
mutex_unlock(&dentry->d_inode->i_mutex);
- err = vfs_unlink(parent.dentry->d_inode, dentry, NULL);
+ err = vfs_unlink(parent.dentry, dentry, NULL);
if (!err || err == -ENOENT)
deleted = 1;
}
@@ -1951,8 +1951,8 @@ static int ll_swap_layouts(struct file *file1, struct file *file2,
if (!S_ISREG(llss->inode2->i_mode))
GOTO(free, rc = -EINVAL);
- if (inode_permission(llss->inode1, MAY_WRITE) ||
- inode_permission(llss->inode2, MAY_WRITE))
+ if (inode_permission(file1->f_dentry, llss->inode1, MAY_WRITE) ||
+ inode_permission(file2->f_dentry, llss->inode2, MAY_WRITE))
GOTO(free, rc = -EPERM);
if (llss->inode2->i_sb != llss->inode1->i_sb)
@@ -3079,7 +3079,7 @@ struct posix_acl * ll_get_acl(struct inode *inode, int type)
}
-int ll_inode_permission(struct inode *inode, int mask)
+int ll_inode_permission(struct dentry *dentry, struct inode *inode, int mask)
{
int rc = 0;
@@ -799,7 +799,7 @@ int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat);
struct ll_file_data *ll_file_data_get(void);
struct posix_acl * ll_get_acl(struct inode *inode, int type);
-int ll_inode_permission(struct inode *inode, int mask);
+int ll_inode_permission(struct dentry *dentry, struct inode *inode, int mask);
int ll_lov_setstripe_ea_info(struct inode *inode, struct file *file,
int flags, struct lov_user_md *lum,
@@ -222,8 +222,8 @@ int lustre_rename(struct dentry *dir, struct vfsmount *mnt,
if (IS_ERR(dchild_new))
GOTO(put_old, err = PTR_ERR(dchild_new));
- err = ll_vfs_rename(dir->d_inode, dchild_old, mnt,
- dir->d_inode, dchild_new, mnt, NULL);
+ err = ll_vfs_rename(dir, dchild_old, mnt,
+ dir, dchild_new, mnt, NULL);
dput(dchild_new);
put_old:
@@ -626,7 +626,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 dentry *, struct inode *, int);
/*
* server.c
@@ -285,7 +285,7 @@ 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 dentry *dentry, struct inode *inode, int mask)
{
struct afs_vnode *vnode = AFS_FS_I(inode);
afs_access_t uninitialized_var(access);
@@ -230,7 +230,7 @@ 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 dentry *dentry, struct inode *inode, int mask)
{
return -EIO;
}
@@ -8817,7 +8817,7 @@ 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 dentry *dentry, struct inode *inode, int mask)
{
struct btrfs_root *root = BTRFS_I(inode)->root;
umode_t mode = inode->i_mode;
@@ -716,9 +716,10 @@ static inline int btrfs_check_sticky(struct inode *dir, struct inode *inode)
* nfs_async_unlink().
*/
-static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir)
+static int btrfs_may_delete(struct dentry *parent, struct dentry *victim, int isdir)
{
int error;
+ struct inode *dir = parent->d_inode;
if (!victim->d_inode)
return -ENOENT;
@@ -726,7 +727,7 @@ static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir)
BUG_ON(victim->d_parent->d_inode != dir);
audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
- error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
+ error = inode_permission(parent, dir, MAY_WRITE | MAY_EXEC);
if (error)
return error;
if (IS_APPEND(dir))
@@ -750,13 +751,14 @@ static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir)
}
/* copy of may_create in fs/namei.c() */
-static inline int btrfs_may_create(struct inode *dir, struct dentry *child)
+static inline int btrfs_may_create(struct dentry *parent, struct dentry *child)
{
+ struct inode *dir = parent->d_inode;
if (child->d_inode)
return -EEXIST;
if (IS_DEADDIR(dir))
return -ENOENT;
- return inode_permission(dir, MAY_WRITE | MAY_EXEC);
+ return inode_permission(parent, dir, MAY_WRITE | MAY_EXEC);
}
/*
@@ -787,7 +789,7 @@ static noinline int btrfs_mksubvol(struct path *parent,
if (dentry->d_inode)
goto out_dput;
- error = btrfs_may_create(dir, dentry);
+ error = btrfs_may_create(parent->dentry, dentry);
if (error)
goto out_dput;
@@ -2213,13 +2215,13 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
if (root == dest)
goto out_dput;
- err = inode_permission(inode, MAY_WRITE | MAY_EXEC);
+ err = inode_permission(dentry, inode, MAY_WRITE | MAY_EXEC);
if (err)
goto out_dput;
}
/* check if subvolume may be deleted by a user */
- err = btrfs_may_delete(dir, dentry, 1);
+ err = btrfs_may_delete(parent, dentry, 1);
if (err)
goto out_dput;
@@ -294,7 +294,7 @@ static int cachefiles_bury_object(struct cachefiles_cache *cache,
if (ret < 0) {
cachefiles_io_error(cache, "Unlink security error");
} else {
- ret = vfs_unlink(dir->d_inode, rep, NULL);
+ ret = vfs_unlink(dir, rep, NULL);
if (preemptive)
cachefiles_mark_object_buried(cache, rep);
@@ -395,8 +395,7 @@ try_again:
if (ret < 0) {
cachefiles_io_error(cache, "Rename security error %d", ret);
} else {
- ret = vfs_rename(dir->d_inode, rep,
- cache->graveyard->d_inode, grave, NULL);
+ ret = vfs_rename(dir, rep, cache->graveyard, grave, NULL);
if (ret != 0 && ret != -ENOMEM)
cachefiles_io_error(cache,
"Rename failed with error %d", ret);
@@ -537,7 +536,7 @@ lookup_again:
if (ret < 0)
goto create_error;
start = jiffies;
- ret = vfs_mkdir(dir->d_inode, next, 0);
+ ret = vfs_mkdir(dir, next, 0);
cachefiles_hist(cachefiles_mkdir_histogram, start);
if (ret < 0)
goto create_error;
@@ -566,7 +565,7 @@ lookup_again:
if (ret < 0)
goto create_error;
start = jiffies;
- ret = vfs_create(dir->d_inode, next, S_IFREG, true);
+ ret = vfs_create(dir, next, S_IFREG, true);
cachefiles_hist(cachefiles_create_histogram, start);
if (ret < 0)
goto create_error;
@@ -755,7 +754,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
ret = security_path_mkdir(&path, subdir, 0700);
if (ret < 0)
goto mkdir_error;
- ret = vfs_mkdir(dir->d_inode, subdir, 0700);
+ ret = vfs_mkdir(dir, subdir, 0700);
if (ret < 0)
goto mkdir_error;
@@ -1875,7 +1875,7 @@ 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 dentry *dentry, struct inode *inode, int mask)
{
int err;
@@ -716,7 +716,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 dentry *, struct inode *inode, int mask);
extern int ceph_setattr(struct dentry *dentry, struct iattr *attr);
extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat);
@@ -211,7 +211,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
return 0;
}
-static int cifs_permission(struct inode *inode, int mask)
+static int cifs_permission(struct dentry *dentry, struct inode *inode, int mask)
{
struct cifs_sb_info *cifs_sb;
@@ -39,7 +39,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 dentry *dentry, struct inode *inode, int mask);
int coda_revalidate_inode(struct inode *);
int coda_getattr(struct vfsmount *, struct dentry *, struct kstat *);
int coda_setattr(struct dentry *, struct iattr *);
@@ -128,7 +128,7 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, unsig
}
-int coda_permission(struct inode *inode, int mask)
+int coda_permission(struct dentry *dentry, struct inode *inode, int mask)
{
int error;
@@ -24,7 +24,7 @@
#include "coda_linux.h"
/* pioctl ops */
-static int coda_ioctl_permission(struct inode *inode, int mask);
+static int coda_ioctl_permission(struct dentry *dentry, struct inode *inode, int mask);
static long coda_pioctl(struct file *filp, unsigned int cmd,
unsigned long user_data);
@@ -41,7 +41,7 @@ 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 dentry *dentry, struct inode *inode, int mask)
{
return (mask & MAY_EXEC) ? -EACCES : 0;
}
@@ -153,7 +153,7 @@ static int ecryptfs_do_unlink(struct inode *dir, struct dentry *dentry,
dget(lower_dentry);
lower_dir_dentry = lock_parent(lower_dentry);
- rc = vfs_unlink(lower_dir_inode, lower_dentry, NULL);
+ rc = vfs_unlink(lower_dir_dentry, lower_dentry, NULL);
if (rc) {
printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc);
goto out_unlock;
@@ -198,7 +198,7 @@ ecryptfs_do_create(struct inode *directory_inode,
inode = ERR_CAST(lower_dir_dentry);
goto out;
}
- rc = vfs_create(lower_dir_dentry->d_inode, lower_dentry, mode, true);
+ rc = vfs_create(lower_dir_dentry, lower_dentry, mode, true);
if (rc) {
printk(KERN_ERR "%s: Failure to create dentry in lower fs; "
"rc = [%d]\n", __func__, rc);
@@ -208,7 +208,7 @@ ecryptfs_do_create(struct inode *directory_inode,
inode = __ecryptfs_get_inode(lower_dentry->d_inode,
directory_inode->i_sb);
if (IS_ERR(inode)) {
- vfs_unlink(lower_dir_dentry->d_inode, lower_dentry, NULL);
+ vfs_unlink(lower_dir_dentry, lower_dentry, NULL);
goto out_lock;
}
fsstack_copy_attr_times(directory_inode, lower_dir_dentry->d_inode);
@@ -474,8 +474,7 @@ static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir,
dget(lower_old_dentry);
dget(lower_new_dentry);
lower_dir_dentry = lock_parent(lower_new_dentry);
- rc = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode,
- lower_new_dentry, NULL);
+ rc = vfs_link(lower_old_dentry, lower_dir_dentry, lower_new_dentry, NULL);
if (rc || !lower_new_dentry->d_inode)
goto out_lock;
rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb);
@@ -520,8 +519,7 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
strlen(symname));
if (rc)
goto out_lock;
- rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry,
- encoded_symname);
+ rc = vfs_symlink(lower_dir_dentry, lower_dentry, encoded_symname);
kfree(encoded_symname);
if (rc || !lower_dentry->d_inode)
goto out_lock;
@@ -546,7 +544,7 @@ static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
lower_dentry = ecryptfs_dentry_to_lower(dentry);
lower_dir_dentry = lock_parent(lower_dentry);
- rc = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, mode);
+ rc = vfs_mkdir(lower_dir_dentry, lower_dentry, mode);
if (rc || !lower_dentry->d_inode)
goto out;
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb);
@@ -572,7 +570,7 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
dget(dentry);
lower_dir_dentry = lock_parent(lower_dentry);
dget(lower_dentry);
- rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry);
+ rc = vfs_rmdir(lower_dir_dentry, lower_dentry);
dput(lower_dentry);
if (!rc && dentry->d_inode)
clear_nlink(dentry->d_inode);
@@ -594,7 +592,7 @@ ecryptfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev
lower_dentry = ecryptfs_dentry_to_lower(dentry);
lower_dir_dentry = lock_parent(lower_dentry);
- rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, mode, dev);
+ rc = vfs_mknod(lower_dir_dentry, lower_dentry, mode, dev);
if (rc || !lower_dentry->d_inode)
goto out;
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb);
@@ -639,8 +637,8 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
rc = -ENOTEMPTY;
goto out_lock;
}
- rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry,
- lower_new_dir_dentry->d_inode, lower_new_dentry,
+ rc = vfs_rename(lower_old_dir_dentry, lower_old_dentry,
+ lower_new_dir_dentry, lower_new_dentry,
NULL);
if (rc)
goto out_lock;
@@ -884,9 +882,9 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
}
static int
-ecryptfs_permission(struct inode *inode, int mask)
+ecryptfs_permission(struct dentry *dentry, struct inode *inode, int mask)
{
- return inode_permission(ecryptfs_inode_to_lower(inode), mask);
+ return inode_permission(ecryptfs_dentry_to_lower(dentry), ecryptfs_inode_to_lower(inode), mask);
}
/**
@@ -1100,7 +1100,7 @@ EXPORT_SYMBOL(flush_old_exec);
void would_dump(struct linux_binprm *bprm, struct file *file)
{
- if (inode_permission(file_inode(file), MAY_READ) < 0)
+ if (inode_permission(file->f_path.dentry, file_inode(file), MAY_READ) < 0)
bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
}
EXPORT_SYMBOL(would_dump);
@@ -1095,7 +1095,7 @@ static int fuse_perm_getattr(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 dentry *dentry, struct inode *inode, int mask)
{
struct fuse_conn *fc = get_fuse_conn(inode);
bool refreshed = false;
@@ -1890,8 +1890,13 @@ out:
return ret;
}
+static int gfs2_vfs_permission(struct dentry *dentry, struct inode *inode, int mask)
+{
+ return gfs2_permission(inode, mask);
+}
+
const struct inode_operations gfs2_file_iops = {
- .permission = gfs2_permission,
+ .permission = gfs2_vfs_permission,
.setattr = gfs2_setattr,
.getattr = gfs2_getattr,
.setxattr = gfs2_setxattr,
@@ -1913,7 +1918,7 @@ const struct inode_operations gfs2_dir_iops = {
.rmdir = gfs2_unlink,
.mknod = gfs2_mknod,
.rename = gfs2_rename,
- .permission = gfs2_permission,
+ .permission = gfs2_vfs_permission,
.setattr = gfs2_setattr,
.getattr = gfs2_getattr,
.setxattr = gfs2_setxattr,
@@ -1930,7 +1935,7 @@ const struct inode_operations gfs2_symlink_iops = {
.readlink = generic_readlink,
.follow_link = gfs2_follow_link,
.put_link = kfree_put_link,
- .permission = gfs2_permission,
+ .permission = gfs2_vfs_permission,
.setattr = gfs2_setattr,
.getattr = gfs2_getattr,
.setxattr = gfs2_setxattr,
@@ -759,7 +759,7 @@ static int hostfs_rename(struct inode *from_ino, struct dentry *from,
return err;
}
-static int hostfs_permission(struct inode *ino, int desired)
+static int hostfs_permission(struct dentry *dentry, struct inode *ino, int desired)
{
char *name;
int r = 0, w = 0, x = 0, err;
@@ -42,7 +42,6 @@ extern void __init chrdev_init(void);
/*
* namei.c
*/
-extern int __inode_permission(struct inode *, int);
extern int user_path_mountpoint_at(int, const char __user *, unsigned int, struct path *);
extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
const char *, unsigned int, struct path *);
@@ -360,7 +360,7 @@ void kernfs_evict_inode(struct inode *inode)
kernfs_put(kn);
}
-int kernfs_iop_permission(struct inode *inode, int mask)
+int kernfs_iop_permission(struct dentry *dentry, struct inode *inode, int mask)
{
struct kernfs_node *kn;
@@ -78,7 +78,7 @@ extern struct kmem_cache *kernfs_node_cache;
*/
struct inode *kernfs_get_inode(struct super_block *sb, struct kernfs_node *kn);
void kernfs_evict_inode(struct inode *inode);
-int kernfs_iop_permission(struct inode *inode, int mask);
+int kernfs_iop_permission(struct dentry *dentry, struct inode *inode, int mask);
int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr);
int kernfs_iop_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat);
@@ -335,11 +335,11 @@ int generic_permission(struct inode *inode, int mask)
* flag in inode->i_opflags, that says "this has not special
* permission function, use the fast case".
*/
-static inline int do_inode_permission(struct inode *inode, int mask)
+static inline int do_inode_permission(struct dentry *dentry, struct inode *inode, int mask)
{
if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) {
if (likely(inode->i_op->permission))
- return inode->i_op->permission(inode, mask);
+ return inode->i_op->permission(dentry, inode, mask);
/* This gets set once for the inode lifetime */
spin_lock(&inode->i_lock);
@@ -361,7 +361,7 @@ static inline int do_inode_permission(struct inode *inode, int mask)
* This does not check for a read-only file system. You probably want
* inode_permission().
*/
-int __inode_permission(struct inode *inode, int mask)
+static int __inode_permission(struct dentry *dentry, struct inode *inode, int mask)
{
int retval;
@@ -373,7 +373,7 @@ int __inode_permission(struct inode *inode, int mask)
return -EACCES;
}
- retval = do_inode_permission(inode, mask);
+ retval = do_inode_permission(dentry, inode, mask);
if (retval)
return retval;
@@ -416,14 +416,14 @@ static int sb_permission(struct super_block *sb, struct inode *inode, int mask)
*
* When checking for MAY_APPEND, MAY_WRITE must also be set in @mask.
*/
-int inode_permission(struct inode *inode, int mask)
+int inode_permission(struct dentry *dentry, struct inode *inode, int mask)
{
int retval;
retval = sb_permission(inode->i_sb, inode, mask);
if (retval)
return retval;
- return __inode_permission(inode, mask);
+ return __inode_permission(dentry, inode, mask);
}
/**
@@ -729,7 +729,7 @@ static inline int may_follow_link(struct path *link, struct nameidata *nd)
*
* Otherwise returns true.
*/
-static bool safe_hardlink_source(struct inode *inode)
+static bool safe_hardlink_source(struct dentry *dentry, struct inode *inode)
{
umode_t mode = inode->i_mode;
@@ -746,7 +746,7 @@ static bool safe_hardlink_source(struct inode *inode)
return false;
/* Hardlinking to unreadable or unwritable sources is dangerous. */
- if (inode_permission(inode, MAY_READ | MAY_WRITE))
+ if (inode_permission(dentry, inode, MAY_READ | MAY_WRITE))
return false;
return true;
@@ -778,7 +778,7 @@ static int may_linkat(struct path *link)
/* Source inode owner (or CAP_FOWNER) can hardlink all they like,
* otherwise, it must be a safe source.
*/
- if (uid_eq(cred->fsuid, inode->i_uid) || safe_hardlink_source(inode) ||
+ if (uid_eq(cred->fsuid, inode->i_uid) || safe_hardlink_source(link->dentry, inode) ||
capable(CAP_FOWNER))
return 0;
@@ -1442,13 +1442,13 @@ static int lookup_slow(struct nameidata *nd, struct path *path)
static inline int may_lookup(struct nameidata *nd)
{
if (nd->flags & LOOKUP_RCU) {
- int err = inode_permission(nd->inode, MAY_EXEC|MAY_NOT_BLOCK);
+ int err = inode_permission(nd->path.dentry, nd->inode, MAY_EXEC|MAY_NOT_BLOCK);
if (err != -ECHILD)
return err;
if (unlazy_walk(nd, NULL))
return -ECHILD;
}
- return inode_permission(nd->inode, MAY_EXEC);
+ return inode_permission(nd->path.dentry, nd->inode, MAY_EXEC);
}
static inline int handle_dots(struct nameidata *nd, int type)
@@ -1792,7 +1792,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
if (*name) {
if (!d_is_directory(root))
return -ENOTDIR;
- retval = inode_permission(inode, MAY_EXEC);
+ retval = inode_permission(root, inode, MAY_EXEC);
if (retval)
return retval;
}
@@ -2078,7 +2078,7 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
return ERR_PTR(err);
}
- err = inode_permission(base->d_inode, MAY_EXEC);
+ err = inode_permission(base, base->d_inode, MAY_EXEC);
if (err)
return ERR_PTR(err);
@@ -2365,8 +2365,9 @@ static inline int check_sticky(struct inode *dir, struct inode *inode)
* 10. We don't allow removal of NFS sillyrenamed files; it's handled by
* nfs_async_unlink().
*/
-static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
+static int may_delete(struct dentry *parent, struct dentry *victim, bool isdir)
{
+ struct inode *dir = parent->d_inode;
struct inode *inode = victim->d_inode;
int error;
@@ -2377,7 +2378,7 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
BUG_ON(victim->d_parent->d_inode != dir);
audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
- error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
+ error = inode_permission(parent, dir, MAY_WRITE | MAY_EXEC);
if (error)
return error;
if (IS_APPEND(dir))
@@ -2408,14 +2409,15 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
* 3. We should have write and exec permissions on dir
* 4. We can't do it if dir is immutable (done in permission())
*/
-static inline int may_create(struct inode *dir, struct dentry *child)
+static inline int may_create(struct dentry *parent, struct dentry *child)
{
+ struct inode *dir = parent->d_inode;
audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE);
if (child->d_inode)
return -EEXIST;
if (IS_DEADDIR(dir))
return -ENOENT;
- return inode_permission(dir, MAY_WRITE | MAY_EXEC);
+ return inode_permission(parent, dir, MAY_WRITE | MAY_EXEC);
}
/*
@@ -2460,10 +2462,11 @@ void unlock_rename(struct dentry *p1, struct dentry *p2)
}
}
-int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+int vfs_create(struct dentry *parent, struct dentry *dentry, umode_t mode,
bool want_excl)
{
- int error = may_create(dir, dentry);
+ struct inode *dir = parent->d_inode;
+ int error = may_create(parent, dentry);
if (error)
return error;
@@ -2511,7 +2514,7 @@ static int may_open(struct path *path, int acc_mode, int flag)
break;
}
- error = inode_permission(inode, acc_mode);
+ error = inode_permission(dentry, inode, acc_mode);
if (error)
return error;
@@ -2567,7 +2570,7 @@ static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode)
if (error)
return error;
- error = inode_permission(dir->dentry->d_inode, MAY_WRITE | MAY_EXEC);
+ error = inode_permission(dir->dentry, dir->dentry->d_inode, MAY_WRITE | MAY_EXEC);
if (error)
return error;
@@ -2812,8 +2815,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
error = security_path_mknod(&nd->path, dentry, mode, 0);
if (error)
goto out_dput;
- error = vfs_create(dir->d_inode, dentry, mode,
- nd->flags & LOOKUP_EXCL);
+ error = vfs_create(dir, dentry, mode, nd->flags & LOOKUP_EXCL);
if (error)
goto out_dput;
}
@@ -3077,10 +3079,10 @@ static int do_tmpfile(int dfd, struct filename *pathname,
if (unlikely(error))
goto out;
/* we want directory to be writable */
- error = inode_permission(nd->inode, MAY_WRITE | MAY_EXEC);
+ dentry = nd->path.dentry;
+ error = inode_permission(dentry, nd->inode, MAY_WRITE | MAY_EXEC);
if (error)
goto out2;
- dentry = nd->path.dentry;
dir = dentry->d_inode;
if (!dir->i_op->tmpfile) {
error = -EOPNOTSUPP;
@@ -3323,9 +3325,10 @@ struct dentry *user_path_create(int dfd, const char __user *pathname,
}
EXPORT_SYMBOL(user_path_create);
-int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
+int vfs_mknod(struct dentry *parent, struct dentry *dentry, umode_t mode, dev_t dev)
{
- int error = may_create(dir, dentry);
+ struct inode *dir;
+ int error = may_create(parent, dentry);
if (error)
return error;
@@ -3333,6 +3336,7 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))
return -EPERM;
+ dir = parent->d_inode;
if (!dir->i_op->mknod)
return -EPERM;
@@ -3390,14 +3394,14 @@ retry:
goto out;
switch (mode & S_IFMT) {
case 0: case S_IFREG:
- error = vfs_create(path.dentry->d_inode,dentry,mode,true);
+ error = vfs_create(path.dentry,dentry,mode,true);
break;
case S_IFCHR: case S_IFBLK:
- error = vfs_mknod(path.dentry->d_inode,dentry,mode,
+ error = vfs_mknod(path.dentry,dentry,mode,
new_decode_dev(dev));
break;
case S_IFIFO: case S_IFSOCK:
- error = vfs_mknod(path.dentry->d_inode,dentry,mode,0);
+ error = vfs_mknod(path.dentry,dentry,mode,0);
break;
}
out:
@@ -3414,14 +3418,16 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d
return sys_mknodat(AT_FDCWD, filename, mode, dev);
}
-int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+int vfs_mkdir(struct dentry *parent, struct dentry *dentry, umode_t mode)
{
- int error = may_create(dir, dentry);
- unsigned max_links = dir->i_sb->s_max_links;
+ struct inode *dir;
+ unsigned max_links;
+ int error = may_create(parent, dentry);
if (error)
return error;
+ dir = parent->d_inode;
if (!dir->i_op->mkdir)
return -EPERM;
@@ -3430,6 +3436,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
if (error)
return error;
+ max_links = dir->i_sb->s_max_links;
if (max_links && dir->i_nlink >= max_links)
return -EMLINK;
@@ -3455,7 +3462,7 @@ retry:
mode &= ~current_umask();
error = security_path_mkdir(&path, dentry, mode);
if (!error)
- error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
+ error = vfs_mkdir(path.dentry, dentry, mode);
done_path_create(&path, dentry);
if (retry_estale(error, lookup_flags)) {
lookup_flags |= LOOKUP_REVAL;
@@ -3493,13 +3500,15 @@ void dentry_unhash(struct dentry *dentry)
spin_unlock(&dentry->d_lock);
}
-int vfs_rmdir(struct inode *dir, struct dentry *dentry)
+int vfs_rmdir(struct dentry *parent, struct dentry *dentry)
{
- int error = may_delete(dir, dentry, 1);
+ struct inode *dir;
+ int error = may_delete(parent, dentry, 1);
if (error)
return error;
+ dir = parent->d_inode;
if (!dir->i_op->rmdir)
return -EPERM;
@@ -3571,7 +3580,7 @@ retry:
error = security_path_rmdir(&nd.path, dentry);
if (error)
goto exit3;
- error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
+ error = vfs_rmdir(nd.path.dentry, dentry);
exit3:
dput(dentry);
exit2:
@@ -3610,10 +3619,11 @@ SYSCALL_DEFINE1(rmdir, const char __user *, pathname)
* be appropriate for callers that expect the underlying filesystem not
* to be NFS exported.
*/
-int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegated_inode)
+int vfs_unlink(struct dentry *parent, struct dentry *dentry, struct inode **delegated_inode)
{
+ struct inode *dir = parent->d_inode;
struct inode *target = dentry->d_inode;
- int error = may_delete(dir, dentry, 0);
+ int error = may_delete(parent, dentry, 0);
if (error)
return error;
@@ -3690,7 +3700,7 @@ retry_deleg:
error = security_path_unlink(&nd.path, dentry);
if (error)
goto exit2;
- error = vfs_unlink(nd.path.dentry->d_inode, dentry, &delegated_inode);
+ error = vfs_unlink(nd.path.dentry, dentry, &delegated_inode);
exit2:
dput(dentry);
}
@@ -3740,13 +3750,15 @@ SYSCALL_DEFINE1(unlink, const char __user *, pathname)
return do_unlinkat(AT_FDCWD, pathname);
}
-int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
+int vfs_symlink(struct dentry *parent, struct dentry *dentry, const char *oldname)
{
- int error = may_create(dir, dentry);
+ struct inode *dir;
+ int error = may_create(parent, dentry);
if (error)
return error;
+ dir = parent->d_inode;
if (!dir->i_op->symlink)
return -EPERM;
@@ -3780,7 +3792,7 @@ retry:
error = security_path_symlink(&path, dentry, from->name);
if (!error)
- error = vfs_symlink(path.dentry->d_inode, dentry, from->name);
+ error = vfs_symlink(path.dentry, dentry, from->name);
done_path_create(&path, dentry);
if (retry_estale(error, lookup_flags)) {
lookup_flags |= LOOKUP_REVAL;
@@ -3815,8 +3827,9 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn
* be appropriate for callers that expect the underlying filesystem not
* to be NFS exported.
*/
-int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, struct inode **delegated_inode)
+int vfs_link(struct dentry *old_dentry, struct dentry *new_parent, struct dentry *new_dentry, struct inode **delegated_inode)
{
+ struct inode *dir = new_parent->d_inode;
struct inode *inode = old_dentry->d_inode;
unsigned max_links = dir->i_sb->s_max_links;
int error;
@@ -3824,7 +3837,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
if (!inode)
return -ENOENT;
- error = may_create(dir, new_dentry);
+ error = may_create(new_parent, new_dentry);
if (error)
return error;
@@ -3921,7 +3934,7 @@ retry:
error = security_path_link(old_path.dentry, &new_path, new_dentry);
if (error)
goto out_dput;
- error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry, &delegated_inode);
+ error = vfs_link(old_path.dentry, new_path.dentry, new_dentry, &delegated_inode);
out_dput:
done_path_create(&new_path, new_dentry);
if (delegated_inode) {
@@ -3987,7 +4000,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
* we'll need to flip '..'.
*/
if (new_dir != old_dir) {
- error = inode_permission(old_dentry->d_inode, MAY_WRITE);
+ error = inode_permission(old_dentry, old_dentry->d_inode, MAY_WRITE);
if (error)
return error;
}
@@ -4091,28 +4104,31 @@ out:
* be appropriate for callers that expect the underlying filesystem not
* to be NFS exported.
*/
-int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry,
+int vfs_rename(struct dentry *old_parent, struct dentry *old_dentry,
+ struct dentry *new_parent, struct dentry *new_dentry,
struct inode **delegated_inode)
{
int error;
+ struct inode *old_dir, *new_dir;
int is_dir = d_is_directory(old_dentry) || d_is_autodir(old_dentry);
const unsigned char *old_name;
if (old_dentry->d_inode == new_dentry->d_inode)
return 0;
- error = may_delete(old_dir, old_dentry, is_dir);
+ error = may_delete(old_parent, old_dentry, is_dir);
if (error)
return error;
if (!new_dentry->d_inode)
- error = may_create(new_dir, new_dentry);
+ error = may_create(new_parent, new_dentry);
else
- error = may_delete(new_dir, new_dentry, is_dir);
+ error = may_delete(new_parent, new_dentry, is_dir);
if (error)
return error;
+ old_dir = old_parent->d_inode;
+ new_dir = new_parent->d_inode;
if (!old_dir->i_op->rename)
return -EPERM;
@@ -4213,9 +4229,9 @@ retry_deleg:
&newnd.path, new_dentry);
if (error)
goto exit5;
- error = vfs_rename(old_dir->d_inode, old_dentry,
- new_dir->d_inode, new_dentry,
- &delegated_inode);
+ error = vfs_rename(old_dir, old_dentry,
+ new_dir, new_dentry,
+ &delegated_inode);
exit5:
dput(new_dentry);
exit4:
@@ -872,7 +872,8 @@ long ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (ret)
goto out;
need_drop_write = 1;
- ret = inode_permission(inode, MAY_WRITE);
+ // Why not just check f_mode & FMODE_WRITE?
+ ret = inode_permission(filp->f_path.dentry, inode, MAY_WRITE);
if (ret)
goto outDropWrite;
break;
@@ -884,7 +885,8 @@ long ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
case NCP_IOC_GETMOUNTUID64:
case NCP_IOC_GETROOT:
case NCP_IOC_SIGN_WANTED:
- ret = inode_permission(inode, MAY_READ);
+ // Why not just check f_mode & FMODE_READ?
+ ret = inode_permission(filp->f_path.dentry, inode, MAY_READ);
if (ret)
goto out;
break;
@@ -2269,7 +2269,7 @@ int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags)
}
EXPORT_SYMBOL_GPL(nfs_may_open);
-int nfs_permission(struct inode *inode, int mask)
+int nfs_permission(struct dentry *dentry, struct inode *inode, int mask)
{
struct rpc_cred *cred;
int res = 0;
@@ -209,7 +209,7 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
* as well be forgiving and just succeed silently.
*/
goto out_put;
- status = vfs_mkdir(dir->d_inode, dentry, S_IRWXU);
+ status = vfs_mkdir(dir, dentry, S_IRWXU);
out_put:
dput(dentry);
out_unlock:
@@ -323,7 +323,7 @@ nfsd4_unlink_clid_dir(char *name, int namlen, struct nfsd_net *nn)
status = -ENOENT;
if (!dentry->d_inode)
goto out;
- status = vfs_rmdir(dir->d_inode, dentry);
+ status = vfs_rmdir(dir, dentry);
out:
dput(dentry);
out_unlock:
@@ -383,7 +383,7 @@ purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
if (nfs4_has_reclaimed_state(child->d_name.name, nn))
return 0;
- status = vfs_rmdir(parent->d_inode, child);
+ status = vfs_rmdir(parent, child);
if (status)
printk("failed to remove client recovery directory %pd\n",
child);
@@ -38,7 +38,7 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry)
/* make sure parents give x permission to user */
int err;
parent = dget_parent(tdentry);
- err = inode_permission(parent->d_inode, MAY_EXEC);
+ err = inode_permission(parent, parent->d_inode, MAY_EXEC);
if (err < 0) {
dput(parent);
break;
@@ -1220,18 +1220,18 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
host_err = 0;
switch (type) {
case S_IFREG:
- host_err = vfs_create(dirp, dchild, iap->ia_mode, true);
+ host_err = vfs_create(dentry, dchild, iap->ia_mode, true);
if (!host_err)
nfsd_check_ignore_resizing(iap);
break;
case S_IFDIR:
- host_err = vfs_mkdir(dirp, dchild, iap->ia_mode);
+ host_err = vfs_mkdir(dentry, dchild, iap->ia_mode);
break;
case S_IFCHR:
case S_IFBLK:
case S_IFIFO:
case S_IFSOCK:
- host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
+ host_err = vfs_mknod(dentry, dchild, iap->ia_mode, rdev);
break;
}
if (host_err < 0)
@@ -1388,7 +1388,7 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
goto out;
}
- host_err = vfs_create(dirp, dchild, iap->ia_mode, true);
+ host_err = vfs_create(dentry, dchild, iap->ia_mode, true);
if (host_err < 0) {
fh_drop_write(fhp);
goto out_nfserr;
@@ -1528,11 +1528,11 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
else {
strncpy(path_alloced, path, plen);
path_alloced[plen] = 0;
- host_err = vfs_symlink(dentry->d_inode, dnew, path_alloced);
+ host_err = vfs_symlink(dentry, dnew, path_alloced);
kfree(path_alloced);
}
} else
- host_err = vfs_symlink(dentry->d_inode, dnew, path);
+ host_err = vfs_symlink(dentry, dnew, path);
err = nfserrno(host_err);
if (!err)
err = nfserrno(commit_metadata(fhp));
@@ -1560,7 +1560,6 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
char *name, int len, struct svc_fh *tfhp)
{
struct dentry *ddir, *dnew, *dold;
- struct inode *dirp;
__be32 err;
int host_err;
@@ -1588,7 +1587,6 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
fh_lock_nested(ffhp, I_MUTEX_PARENT);
ddir = ffhp->fh_dentry;
- dirp = ddir->d_inode;
dnew = lookup_one_len(name, ddir, len);
host_err = PTR_ERR(dnew);
@@ -1600,7 +1598,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
err = nfserr_noent;
if (!dold->d_inode)
goto out_dput;
- host_err = vfs_link(dold, dirp, dnew, NULL);
+ host_err = vfs_link(dold, ddir, dnew, NULL);
if (!host_err) {
err = nfserrno(commit_metadata(ffhp));
if (!err)
@@ -1633,7 +1631,6 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
struct svc_fh *tfhp, char *tname, int tlen)
{
struct dentry *fdentry, *tdentry, *odentry, *ndentry, *trap;
- struct inode *fdir, *tdir;
__be32 err;
int host_err;
@@ -1645,10 +1642,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
goto out;
fdentry = ffhp->fh_dentry;
- fdir = fdentry->d_inode;
-
tdentry = tfhp->fh_dentry;
- tdir = tdentry->d_inode;
err = nfserr_perm;
if (!flen || isdotent(fname, flen) || !tlen || isdotent(tname, tlen))
@@ -1693,7 +1687,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
if (ffhp->fh_export->ex_path.dentry != tfhp->fh_export->ex_path.dentry)
goto out_dput_new;
- host_err = vfs_rename(fdir, odentry, tdir, ndentry, NULL);
+ host_err = vfs_rename(fdentry, odentry, tdentry, ndentry, NULL);
if (!host_err) {
host_err = commit_metadata(tfhp);
if (!host_err)
@@ -1729,7 +1723,6 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
char *fname, int flen)
{
struct dentry *dentry, *rdentry;
- struct inode *dirp;
__be32 err;
int host_err;
@@ -1746,7 +1739,6 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
fh_lock_nested(fhp, I_MUTEX_PARENT);
dentry = fhp->fh_dentry;
- dirp = dentry->d_inode;
rdentry = lookup_one_len(fname, dentry, flen);
host_err = PTR_ERR(rdentry);
@@ -1763,9 +1755,9 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
type = rdentry->d_inode->i_mode & S_IFMT;
if (type != S_IFDIR)
- host_err = vfs_unlink(dirp, rdentry, NULL);
+ host_err = vfs_unlink(dentry, rdentry, NULL);
else
- host_err = vfs_rmdir(dirp, rdentry);
+ host_err = vfs_rmdir(dentry, rdentry);
if (!host_err)
host_err = commit_metadata(fhp);
dput(rdentry);
@@ -2036,13 +2028,13 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
return 0;
/* This assumes NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */
- err = inode_permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC));
+ err = inode_permission(dentry, inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC));
/* Allow read access to binaries even when mode 111 */
if (err == -EACCES && S_ISREG(inode->i_mode) &&
(acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE) ||
acc == (NFSD_MAY_READ | NFSD_MAY_READ_IF_EXEC)))
- err = inode_permission(inode, MAY_EXEC);
+ err = inode_permission(dentry, inode, MAY_EXEC);
return err? nfserrno(err) : 0;
}
@@ -850,7 +850,7 @@ out_err:
return err;
}
-int nilfs_permission(struct inode *inode, int mask)
+int nilfs_permission(struct dentry *dentry, struct inode *inode, int mask)
{
struct nilfs_root *root = NILFS_I(inode)->i_root;
if ((mask & MAY_WRITE) && root &&
@@ -278,7 +278,7 @@ extern void nilfs_truncate(struct inode *);
extern void nilfs_evict_inode(struct inode *);
extern int nilfs_setattr(struct dentry *, struct iattr *);
extern void nilfs_write_failed(struct address_space *mapping, loff_t to);
-int nilfs_permission(struct inode *inode, int mask);
+int nilfs_permission(struct dentry *dentry, struct inode *inode, int mask);
int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh);
extern int nilfs_inode_dirty(struct inode *);
int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty);
@@ -490,7 +490,7 @@ static int fanotify_find_path(int dfd, const char __user *filename,
}
/* you can only watch an inode if you have read permissions on it */
- ret = inode_permission(path->dentry->d_inode, MAY_READ);
+ ret = inode_permission(path->dentry, path->dentry->d_inode, MAY_READ);
if (ret)
path_put(path);
out:
@@ -338,7 +338,7 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns
if (error)
return error;
/* you can only watch an inode if you have read permissions on it */
- error = inode_permission(path->dentry->d_inode, MAY_READ);
+ error = inode_permission(path->dentry, path->dentry->d_inode, MAY_READ);
if (error)
path_put(path);
return error;
@@ -1269,7 +1269,7 @@ bail:
return err;
}
-int ocfs2_permission(struct inode *inode, int mask)
+int ocfs2_permission(struct dentry *dentry, struct inode *inode, int mask)
{
int ret;
@@ -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 dentry *dentry, struct inode *inode, int mask);
int ocfs2_should_update_atime(struct inode *inode,
struct vfsmount *vfsmnt);
@@ -4350,13 +4350,15 @@ out:
*/
/* copied from may_create in VFS. */
-static inline int ocfs2_may_create(struct inode *dir, struct dentry *child)
+static inline int ocfs2_may_create(struct dentry *parent, struct dentry *child)
{
+ struct inode *dir = parent->d_inode;
+
if (child->d_inode)
return -EEXIST;
if (IS_DEADDIR(dir))
return -ENOENT;
- return inode_permission(dir, MAY_WRITE | MAY_EXEC);
+ return inode_permission(parent, dir, MAY_WRITE | MAY_EXEC);
}
/**
@@ -4367,16 +4369,17 @@ static inline int ocfs2_may_create(struct inode *dir, struct dentry *child)
* @new_dentry: target dentry
* @preserve: if true, preserve all file attributes
*/
-static int ocfs2_vfs_reflink(struct dentry *old_dentry, struct inode *dir,
+static int ocfs2_vfs_reflink(struct dentry *old_dentry, struct dentry *new_parent,
struct dentry *new_dentry, bool preserve)
{
+ struct inode *dir = new_parent->d_inode;
struct inode *inode = old_dentry->d_inode;
int error;
if (!inode)
return -ENOENT;
- error = ocfs2_may_create(dir, new_dentry);
+ error = ocfs2_may_create(new_parent, new_dentry);
if (error)
return error;
@@ -4410,7 +4413,7 @@ static int ocfs2_vfs_reflink(struct dentry *old_dentry, struct inode *dir,
* file.
*/
if (!preserve) {
- error = inode_permission(inode, MAY_READ);
+ error = inode_permission(old_dentry, inode, MAY_READ);
if (error)
return error;
}
@@ -4458,7 +4461,7 @@ int ocfs2_reflink_ioctl(struct inode *inode,
}
error = ocfs2_vfs_reflink(old_path.dentry,
- new_path.dentry->d_inode,
+ new_path.dentry,
new_dentry, preserve);
out_dput:
done_path_create(&new_path, new_dentry);
@@ -65,10 +65,12 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
long vfs_truncate(struct path *path, loff_t length)
{
+ struct dentry *dentry;
struct inode *inode;
long error;
- inode = path->dentry->d_inode;
+ dentry = path->dentry;
+ inode = dentry->d_inode;
/* For directories it's -EISDIR, for other non-regulars - -EINVAL */
if (S_ISDIR(inode->i_mode))
@@ -80,7 +82,7 @@ long vfs_truncate(struct path *path, loff_t length)
if (error)
goto out;
- error = inode_permission(inode, MAY_WRITE);
+ error = inode_permission(dentry, inode, MAY_WRITE);
if (error)
goto mnt_drop_write_and_out;
@@ -344,7 +346,7 @@ retry:
goto out_path_release;
}
- res = inode_permission(inode, mode | MAY_ACCESS);
+ res = inode_permission(path.dentry, inode, mode | MAY_ACCESS);
/* SuS v2 requires we report a read only fs too */
if (res || !(mode & S_IWOTH) || special_file(inode->i_mode))
goto out_path_release;
@@ -388,7 +390,7 @@ retry:
if (error)
goto out;
- error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
+ error = inode_permission(path.dentry, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
if (error)
goto dput_and_out;
@@ -420,7 +422,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd)
if (!S_ISDIR(inode->i_mode))
goto out_putf;
- error = inode_permission(inode, MAY_EXEC | MAY_CHDIR);
+ error = inode_permission(f.file->f_path.dentry, inode, MAY_EXEC | MAY_CHDIR);
if (!error)
set_fs_pwd(current->fs, &f.file->f_path);
out_putf:
@@ -439,7 +441,7 @@ retry:
if (error)
goto out;
- error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
+ error = inode_permission(path.dentry, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
if (error)
goto dput_and_out;
@@ -596,7 +596,7 @@ static bool has_pid_permissions(struct pid_namespace *pid,
}
-static int proc_pid_permission(struct inode *inode, int mask)
+static int proc_pid_permission(struct dentry *dentry, struct inode *inode, int mask)
{
struct pid_namespace *pid = inode->i_sb->s_fs_info;
struct task_struct *task;
@@ -281,7 +281,7 @@ static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry,
* /proc/pid/fd needs a special permission handler so that a process can still
* access /proc/self/fd after it has executed a setuid().
*/
-int proc_fd_permission(struct inode *inode, int mask)
+int proc_fd_permission(struct dentry *dentry, struct inode *inode, int mask)
{
int rv = generic_permission(inode, mask);
if (rv == 0)
@@ -9,7 +9,7 @@ extern const struct inode_operations proc_fd_inode_operations;
extern const struct file_operations proc_fdinfo_operations;
extern const struct inode_operations proc_fdinfo_inode_operations;
-extern int proc_fd_permission(struct inode *inode, int mask);
+extern int proc_fd_permission(struct dentry *dentry, struct inode *inode, int mask);
static inline int proc_fd(struct inode *inode)
{
@@ -680,7 +680,7 @@ static int proc_sys_readdir(struct file *file, struct dir_context *ctx)
return 0;
}
-static int proc_sys_permission(struct inode *inode, int mask)
+static int proc_sys_permission(struct dentry *dentry, struct inode *inode, int mask)
{
/*
* sysctl entries that are not writeable,
@@ -930,7 +930,7 @@ static int xattr_mount_check(struct super_block *s)
return 0;
}
-int reiserfs_permission(struct inode *inode, int mask)
+int reiserfs_permission(struct dentry *dentry, struct inode *inode, int mask)
{
/*
* We don't do permission checks on the internal objects.
@@ -15,7 +15,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 dentry *dentry, struct inode *inode, int mask);
#ifdef CONFIG_REISERFS_FS_XATTR
#define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir)
@@ -182,7 +182,7 @@ long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
long old_block, new_block;
int result = -EINVAL;
- if (inode_permission(inode, MAY_READ) != 0) {
+ if (inode_permission(filp->f_path.dentry, inode, MAY_READ) != 0) {
udf_debug("no permission to access inode %lu\n", inode->i_ino);
result = -EPERM;
goto out;
@@ -97,7 +97,7 @@ static int utimes_common(struct path *path, struct timespec *times)
goto mnt_drop_write_and_out;
if (!inode_owner_or_capable(inode)) {
- error = inode_permission(inode, MAY_WRITE);
+ error = inode_permission(path->dentry, inode, MAY_WRITE);
if (error)
goto mnt_drop_write_and_out;
}
@@ -29,7 +29,7 @@
* because different namespaces have very different rules.
*/
static int
-xattr_permission(struct inode *inode, const char *name, int mask)
+xattr_permission(struct dentry *dentry, struct inode *inode, const char *name, int mask)
{
/*
* We can never set or remove an extended attribute on a read-only
@@ -70,7 +70,7 @@ xattr_permission(struct inode *inode, const char *name, int mask)
return -EPERM;
}
- return inode_permission(inode, mask);
+ return inode_permission(dentry, inode, mask);
}
/**
@@ -125,7 +125,7 @@ vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
struct inode *inode = dentry->d_inode;
int error;
- error = xattr_permission(inode, name, MAY_WRITE);
+ error = xattr_permission(dentry, inode, name, MAY_WRITE);
if (error)
return error;
@@ -185,7 +185,7 @@ vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value,
char *value = *xattr_value;
int error;
- error = xattr_permission(inode, name, MAY_READ);
+ error = xattr_permission(dentry, inode, name, MAY_READ);
if (error)
return error;
@@ -233,7 +233,7 @@ vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
struct inode *inode = dentry->d_inode;
int error;
- error = xattr_permission(inode, name, MAY_READ);
+ error = xattr_permission(dentry, inode, name, MAY_READ);
if (error)
return error;
@@ -292,7 +292,7 @@ vfs_removexattr(struct dentry *dentry, const char *name)
if (!inode->i_op->removexattr)
return -EOPNOTSUPP;
- error = xattr_permission(inode, name, MAY_WRITE);
+ error = xattr_permission(dentry, inode, name, MAY_WRITE);
if (error)
return error;
@@ -1449,14 +1449,14 @@ extern bool inode_owner_or_capable(const struct inode *inode);
/*
* VFS helper functions..
*/
-extern int vfs_create(struct inode *, struct dentry *, umode_t, bool);
-extern int vfs_mkdir(struct inode *, struct dentry *, umode_t);
-extern int vfs_mknod(struct inode *, struct dentry *, umode_t, dev_t);
-extern int vfs_symlink(struct inode *, struct dentry *, const char *);
-extern int vfs_link(struct dentry *, struct inode *, struct dentry *, struct inode **);
-extern int vfs_rmdir(struct inode *, struct dentry *);
-extern int vfs_unlink(struct inode *, struct dentry *, struct inode **);
-extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *, struct inode **);
+extern int vfs_create(struct dentry *, struct dentry *, umode_t, bool);
+extern int vfs_mkdir(struct dentry *, struct dentry *, umode_t);
+extern int vfs_mknod(struct dentry *, struct dentry *, umode_t, dev_t);
+extern int vfs_symlink(struct dentry *, struct dentry *, const char *);
+extern int vfs_link(struct dentry *, struct dentry *, struct dentry *, struct inode **);
+extern int vfs_rmdir(struct dentry *, struct dentry *);
+extern int vfs_unlink(struct dentry *, struct dentry *, struct inode **);
+extern int vfs_rename(struct dentry *, struct dentry *, struct dentry *, struct dentry *, struct inode **);
/*
* VFS dentry helper functions.
@@ -1552,7 +1552,7 @@ struct file_operations {
struct inode_operations {
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
void * (*follow_link) (struct dentry *, struct nameidata *);
- int (*permission) (struct inode *, int);
+ int (*permission) (struct dentry *, struct inode *, int);
struct posix_acl * (*get_acl)(struct inode *, int);
int (*readlink) (struct dentry *, char __user *,int);
@@ -2280,7 +2280,7 @@ extern void emergency_remount(void);
extern sector_t bmap(struct inode *, sector_t);
#endif
extern int notify_change(struct dentry *, struct iattr *, struct inode **);
-extern int inode_permission(struct inode *, int);
+extern int inode_permission(struct dentry *, struct inode *, int);
extern int generic_permission(struct inode *, int);
static inline bool execute_ok(struct inode *inode)
@@ -345,7 +345,7 @@ extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fa
extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
extern void nfs_access_set_mask(struct nfs_access_entry *, u32);
-extern int nfs_permission(struct inode *, int);
+extern int nfs_permission(struct dentry *, struct inode *, 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);
@@ -728,7 +728,7 @@ static int mq_attr_ok(struct ipc_namespace *ipc_ns, struct mq_attr *attr)
/*
* Invoked when creating a new queue via sys_mq_open
*/
-static struct file *do_create(struct ipc_namespace *ipc_ns, struct inode *dir,
+static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *parent,
struct path *path, int oflag, umode_t mode,
struct mq_attr *attr)
{
@@ -754,7 +754,7 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct inode *dir,
}
mode &= ~current_umask();
- ret = vfs_create(dir, path->dentry, mode, true);
+ ret = vfs_create(parent, path->dentry, mode, true);
path->dentry->d_fsdata = NULL;
if (ret)
return ERR_PTR(ret);
@@ -770,7 +770,7 @@ static struct file *do_open(struct path *path, int oflag)
if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY))
return ERR_PTR(-EINVAL);
acc = oflag2acc[oflag & O_ACCMODE];
- if (inode_permission(path->dentry->d_inode, acc))
+ if (inode_permission(path->dentry, path->dentry->d_inode, acc))
return ERR_PTR(-EACCES);
return dentry_open(path, oflag, current_cred());
}
@@ -824,7 +824,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
goto out;
}
audit_inode_parent_hidden(name, root);
- filp = do_create(ipc_ns, root->d_inode,
+ filp = do_create(ipc_ns, root,
&path, oflag, mode,
u_attr ? &attr : NULL);
}
@@ -886,7 +886,7 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
err = -ENOENT;
} else {
ihold(inode);
- err = vfs_unlink(dentry->d_parent->d_inode, dentry, NULL);
+ err = vfs_unlink(dentry->d_parent, dentry, NULL);
}
dput(dentry);
@@ -1650,7 +1650,7 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
exe.file->f_path.mnt->mnt_flags & MNT_NOEXEC)
goto exit;
- err = inode_permission(inode, MAY_EXEC);
+ err = inode_permission(exe.file->f_path.dentry, inode, MAY_EXEC);
if (err)
goto exit;
@@ -6147,7 +6147,7 @@ static int memcg_write_event_control(struct cgroup_subsys_state *css,
/* the process need read permission on control file */
/* AV: shouldn't we check that it's been opened for read instead? */
- ret = inode_permission(file_inode(cfile.file), MAY_READ);
+ ret = inode_permission(cfile.file->f_path.dentry, file_inode(cfile.file), MAY_READ);
if (ret < 0)
goto out_put_cfile;
@@ -785,7 +785,7 @@ static struct sock *unix_find_other(struct net *net,
if (err)
goto fail;
inode = path.dentry->d_inode;
- err = inode_permission(inode, MAY_WRITE);
+ err = inode_permission(path.dentry, inode, MAY_WRITE);
if (err)
goto put_fail;
@@ -845,7 +845,7 @@ static int unix_mknod(const char *sun_path, umode_t mode, struct path *res)
*/
err = security_path_mknod(&path, dentry, mode, 0);
if (!err) {
- err = vfs_mknod(path.dentry->d_inode, dentry, mode, 0);
+ err = vfs_mknod(path.dentry, dentry, mode, 0);
if (!err) {
res->mnt = mntget(path.mnt);
res->dentry = dget(dentry);
@@ -639,7 +639,7 @@ static int probe_sysfs_permissions(struct pci_dev *dev)
inode = path.dentry->d_inode;
- r = inode_permission(inode, MAY_READ | MAY_WRITE | MAY_ACCESS);
+ r = inode_permission(path.dentry, inode, MAY_READ | MAY_WRITE | MAY_ACCESS);
path_put(&path);
if (r)
return r;