[patch 07/14] vfs: pass dentry to permission()

From: Miklos Szeredi
Date: Wed May 21 2008 - 13:19:42 EST


From: Miklos Szeredi <mszeredi@xxxxxxx>

The following patches clean up the i_op->permission() method and the
related VFS API.

Here's an overview of the changes:

- ->permission() is passed a dentry instead of an inode
- ->permission() is passed a integer flags parameter instead of a
nameidata pointer
- all nameidata pointer passing is removed from the permission API
- the check for execute bit on regular files is moved into ->permission()
- the permission() and vfs_permission() functions are consolidated to
a common path_permission() function
- file_permission() becomes just a helper to call path_permission()

This patch:

Rename permission() to dentry_permission() and pass a dentry to it
instead of an inode.

For ecryptfs this is done with a temparary hack using d_find_alias(),
which will be removed by the next patch.

Otherwise this can be trivially done by passing the dentry down to
functions calling permission().

Signed-off-by: Miklos Szeredi <mszeredi@xxxxxxx>
---
fs/ecryptfs/inode.c | 14 +++++-
fs/namei.c | 105 ++++++++++++++++++++++++++++------------------------
fs/nfsd/nfsfh.c | 2
fs/nfsd/vfs.c | 5 +-
fs/xattr.c | 12 +++--
include/linux/fs.h | 2
ipc/mqueue.c | 2
7 files changed, 81 insertions(+), 61 deletions(-)

Index: linux-2.6/fs/ecryptfs/inode.c
===================================================================
--- linux-2.6.orig/fs/ecryptfs/inode.c 2008-05-21 15:45:10.000000000 +0200
+++ linux-2.6/fs/ecryptfs/inode.c 2008-05-21 16:36:42.000000000 +0200
@@ -818,11 +818,19 @@ ecryptfs_permission(struct inode *inode,

nd->path.mnt = ecryptfs_dentry_to_lower_mnt(nd->path.dentry);
nd->path.dentry = ecryptfs_dentry_to_lower(nd->path.dentry);
- rc = permission(ecryptfs_inode_to_lower(inode), mask, nd);
+ rc = dentry_permission(nd->path.dentry, mask, nd);
nd->path.mnt = vfsmnt_save;
nd->path.dentry = dentry_save;
- } else
- rc = permission(ecryptfs_inode_to_lower(inode), mask, NULL);
+ } else {
+ struct dentry *dentry = d_find_alias(inode);
+ struct dentry *lower_dentry;
+
+ rc = -ENOENT;
+ if (dentry) {
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ rc = dentry_permission(lower_dentry, mask, NULL);
+ }
+ }
return rc;
}

Index: linux-2.6/fs/namei.c
===================================================================
--- linux-2.6.orig/fs/namei.c 2008-05-21 15:45:10.000000000 +0200
+++ linux-2.6/fs/namei.c 2008-05-21 16:36:07.000000000 +0200
@@ -226,8 +226,9 @@ int generic_permission(struct inode *ino
return -EACCES;
}

-int permission(struct inode *inode, int mask, struct nameidata *nd)
+int dentry_permission(struct dentry *dentry, int mask, struct nameidata *nd)
{
+ struct inode *inode = dentry->d_inode;
int retval, submask;
struct vfsmount *mnt = NULL;

@@ -301,7 +302,7 @@ int permission(struct inode *inode, int
*/
int vfs_permission(struct nameidata *nd, int mask)
{
- return permission(nd->path.dentry->d_inode, mask, nd);
+ return dentry_permission(nd->path.dentry, mask, nd);
}

/**
@@ -318,7 +319,7 @@ int vfs_permission(struct nameidata *nd,
*/
int file_permission(struct file *file, int mask)
{
- return permission(file->f_path.dentry->d_inode, mask, NULL);
+ return dentry_permission(file->f_path.dentry, mask, NULL);
}

/*
@@ -1341,7 +1342,7 @@ static struct dentry *lookup_hash(struct
{
int err;

- err = permission(nd->path.dentry->d_inode, MAY_EXEC, nd);
+ err = dentry_permission(nd->path.dentry, MAY_EXEC, nd);
if (err)
return ERR_PTR(err);
return __lookup_hash(&nd->last, nd->path.dentry, nd);
@@ -1389,7 +1390,7 @@ struct dentry *lookup_one_len(const char
if (err)
return ERR_PTR(err);

- err = permission(base->d_inode, MAY_EXEC, NULL);
+ err = dentry_permission(base, MAY_EXEC, NULL);
if (err)
return ERR_PTR(err);
return __lookup_hash(&this, base, NULL);
@@ -1469,8 +1470,10 @@ static inline int check_sticky(struct in
* 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,int isdir)
+static int may_delete(struct dentry *dir_dentry, struct dentry *victim,
+ int isdir)
{
+ struct inode *dir = dir_dentry->d_inode;
int error;

if (!victim->d_inode)
@@ -1479,7 +1482,7 @@ static int may_delete(struct inode *dir,
BUG_ON(victim->d_parent->d_inode != dir);
audit_inode_child(victim->d_name.name, victim, dir);

- error = permission(dir,MAY_WRITE | MAY_EXEC, NULL);
+ error = dentry_permission(dir_dentry, MAY_WRITE | MAY_EXEC, NULL);
if (error)
return error;
if (IS_APPEND(dir))
@@ -1509,14 +1512,14 @@ static int may_delete(struct inode *dir,
* 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 *dir_dentry, struct dentry *child,
struct nameidata *nd)
{
if (child->d_inode)
return -EEXIST;
- if (IS_DEADDIR(dir))
+ if (IS_DEADDIR(dir_dentry->d_inode))
return -ENOENT;
- return permission(dir,MAY_WRITE | MAY_EXEC, nd);
+ return dentry_permission(dir_dentry, MAY_WRITE | MAY_EXEC, nd);
}

/*
@@ -1579,10 +1582,11 @@ void unlock_rename(struct dentry *p1, st
}
}

-static int vfs_create(struct inode *dir, struct dentry *dentry, int mode,
- struct nameidata *nd)
+static int vfs_create(struct dentry *dir_dentry, struct dentry *dentry,
+ int mode, struct nameidata *nd)
{
- int error = may_create(dir, dentry, nd);
+ struct inode *dir = dir_dentry->d_inode;
+ int error = may_create(dir_dentry, dentry, nd);

if (error)
return error;
@@ -1607,7 +1611,7 @@ int path_create(struct path *dir_path, s
int error = mnt_want_write(dir_path->mnt);

if (!error) {
- error = vfs_create(dir_path->dentry->d_inode, dentry, mode, nd);
+ error = vfs_create(dir_path->dentry, dentry, mode, nd);
mnt_drop_write(dir_path->mnt);
}

@@ -1708,7 +1712,7 @@ static int __open_namei_create(struct na

if (!IS_POSIXACL(dir->d_inode))
mode &= ~current->fs->umask;
- error = vfs_create(dir->d_inode, path->dentry, mode, nd);
+ error = vfs_create(dir, path->dentry, mode, nd);
mutex_unlock(&dir->d_inode->i_mutex);
dput(nd->path.dentry);
nd->path.dentry = path->dentry;
@@ -2034,9 +2038,11 @@ fail:
}
EXPORT_SYMBOL_GPL(lookup_create);

-static int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+static int vfs_mknod(struct dentry *dir_dentry, struct dentry *dentry,
+ int mode, dev_t dev)
{
- int error = may_create(dir, dentry, NULL);
+ struct inode *dir = dir_dentry->d_inode;
+ int error = may_create(dir_dentry, dentry, NULL);

if (error)
return error;
@@ -2068,7 +2074,7 @@ int path_mknod(struct path *dir_path, st
int error = mnt_want_write(dir_path->mnt);

if (!error) {
- error = vfs_mknod(dir_path->dentry->d_inode, dentry, mode, dev);
+ error = vfs_mknod(dir_path->dentry, dentry, mode, dev);
mnt_drop_write(dir_path->mnt);
}

@@ -2131,9 +2137,10 @@ asmlinkage long sys_mknod(const char __u
return sys_mknodat(AT_FDCWD, filename, mode, dev);
}

-static int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+static int vfs_mkdir(struct dentry *dir_dentry, struct dentry *dentry, int mode)
{
- int error = may_create(dir, dentry, NULL);
+ struct inode *dir = dir_dentry->d_inode;
+ int error = may_create(dir_dentry, dentry, NULL);

if (error)
return error;
@@ -2158,7 +2165,7 @@ int path_mkdir(struct path *dir_path, st
int error = mnt_want_write(dir_path->mnt);

if (!error) {
- error = vfs_mkdir(dir_path->dentry->d_inode, dentry, mode);
+ error = vfs_mkdir(dir_path->dentry, dentry, mode);
mnt_drop_write(dir_path->mnt);
}

@@ -2231,9 +2238,10 @@ void dentry_unhash(struct dentry *dentry
spin_unlock(&dcache_lock);
}

-static int vfs_rmdir(struct inode *dir, struct dentry *dentry)
+static int vfs_rmdir(struct dentry *dir_dentry, struct dentry *dentry)
{
- int error = may_delete(dir, dentry, 1);
+ struct inode *dir = dir_dentry->d_inode;
+ int error = may_delete(dir_dentry, dentry, 1);

if (error)
return error;
@@ -2269,7 +2277,7 @@ int path_rmdir(struct path *dir_path, st
int error = mnt_want_write(dir_path->mnt);

if (!error) {
- error = vfs_rmdir(dir_path->dentry->d_inode, dentry);
+ error = vfs_rmdir(dir_path->dentry, dentry);
mnt_drop_write(dir_path->mnt);
}

@@ -2324,9 +2332,10 @@ asmlinkage long sys_rmdir(const char __u
return do_rmdir(AT_FDCWD, pathname);
}

-static int vfs_unlink(struct inode *dir, struct dentry *dentry)
+static int vfs_unlink(struct dentry *dir_dentry, struct dentry *dentry)
{
- int error = may_delete(dir, dentry, 0);
+ struct inode *dir = dir_dentry->d_inode;
+ int error = may_delete(dir_dentry, dentry, 0);

if (error)
return error;
@@ -2360,7 +2369,7 @@ int path_unlink(struct path *dir_path, s
int error = mnt_want_write(dir_path->mnt);

if (!error) {
- error = vfs_unlink(dir_path->dentry->d_inode, dentry);
+ error = vfs_unlink(dir_path->dentry, dentry);
mnt_drop_write(dir_path->mnt);
}

@@ -2437,9 +2446,11 @@ asmlinkage long sys_unlink(const char __
return do_unlinkat(AT_FDCWD, pathname);
}

-static int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
+static int vfs_symlink(struct dentry *dir_dentry, struct dentry *dentry,
+ const char *oldname)
{
- int error = may_create(dir, dentry, NULL);
+ struct inode *dir = dir_dentry->d_inode;
+ int error = may_create(dir_dentry, dentry, NULL);

if (error)
return error;
@@ -2464,9 +2475,7 @@ int path_symlink(struct path *dir_path,
int error = mnt_want_write(dir_path->mnt);

if (!error) {
- struct inode *dir = dir_path->dentry->d_inode;
-
- error = vfs_symlink(dir, dentry, oldname);
+ error = vfs_symlink(dir_path->dentry, dentry, oldname);
mnt_drop_write(dir_path->mnt);
}

@@ -2516,15 +2525,17 @@ asmlinkage long sys_symlink(const char _
return sys_symlinkat(oldname, AT_FDCWD, newname);
}

-static int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
+static int vfs_link(struct dentry *old_dentry, struct dentry *new_dir_dentry,
+ struct dentry *new_dentry)
{
+ struct inode *dir = new_dir_dentry->d_inode;
struct inode *inode = old_dentry->d_inode;
int error;

if (!inode)
return -ENOENT;

- error = may_create(dir, new_dentry, NULL);
+ error = may_create(new_dir_dentry, new_dentry, NULL);
if (error)
return error;

@@ -2560,9 +2571,7 @@ int path_link(struct dentry *old_dentry,
int error = mnt_want_write(dir_path->mnt);

if (!error) {
- struct inode *dir = dir_path->dentry->d_inode;
-
- error = vfs_link(old_dentry, dir, new_dentry);
+ error = vfs_link(old_dentry, dir_path->dentry, new_dentry);
mnt_drop_write(dir_path->mnt);
}

@@ -2672,7 +2681,7 @@ static int vfs_rename_dir(struct inode *
* we'll need to flip '..'.
*/
if (new_dir != old_dir) {
- error = permission(old_dentry->d_inode, MAY_WRITE, NULL);
+ error = dentry_permission(old_dentry, MAY_WRITE, NULL);
if (error)
return error;
}
@@ -2732,9 +2741,11 @@ static int vfs_rename_other(struct inode
return error;
}

-static int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+static int vfs_rename(struct dentry *old_dir_dentry, struct dentry *old_dentry,
+ struct dentry *new_dir_dentry, struct dentry *new_dentry)
{
+ struct inode *old_dir = old_dir_dentry->d_inode;
+ struct inode *new_dir = new_dir_dentry->d_inode;
int error;
int is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
const char *old_name;
@@ -2742,14 +2753,14 @@ static int vfs_rename(struct inode *old_
if (old_dentry->d_inode == new_dentry->d_inode)
return 0;

- error = may_delete(old_dir, old_dentry, is_dir);
+ error = may_delete(old_dir_dentry, old_dentry, is_dir);
if (error)
return error;

if (!new_dentry->d_inode)
- error = may_create(new_dir, new_dentry, NULL);
+ error = may_create(new_dir_dentry, new_dentry, NULL);
else
- error = may_delete(new_dir, new_dentry, is_dir);
+ error = may_delete(new_dir_dentry, new_dentry, is_dir);
if (error)
return error;

@@ -2785,10 +2796,8 @@ int path_rename(struct path *old_dir_pat

error = mnt_want_write(mnt);
if (!error) {
- struct inode *old_dir = old_dir_path->dentry->d_inode;
- struct inode *new_dir = new_dir_path->dentry->d_inode;
-
- error = vfs_rename(old_dir, old_dentry, new_dir, new_dentry);
+ error = vfs_rename(old_dir_path->dentry, old_dentry,
+ new_dir_path->dentry, new_dentry);
mnt_drop_write(mnt);
}

@@ -3041,7 +3050,7 @@ EXPORT_SYMBOL(page_symlink);
EXPORT_SYMBOL(page_symlink_inode_operations);
EXPORT_SYMBOL(path_lookup);
EXPORT_SYMBOL(vfs_path_lookup);
-EXPORT_SYMBOL(permission);
+EXPORT_SYMBOL(dentry_permission);
EXPORT_SYMBOL(vfs_permission);
EXPORT_SYMBOL(file_permission);
EXPORT_SYMBOL(unlock_rename);
Index: linux-2.6/fs/nfsd/nfsfh.c
===================================================================
--- linux-2.6.orig/fs/nfsd/nfsfh.c 2008-05-21 15:45:10.000000000 +0200
+++ linux-2.6/fs/nfsd/nfsfh.c 2008-05-21 16:36:07.000000000 +0200
@@ -51,7 +51,7 @@ static int nfsd_acceptable(void *expv, s
/* make sure parents give x permission to user */
int err;
parent = dget_parent(tdentry);
- err = permission(parent->d_inode, MAY_EXEC, NULL);
+ err = dentry_permission(parent, MAY_EXEC, NULL);
if (err < 0) {
dput(parent);
break;
Index: linux-2.6/fs/nfsd/vfs.c
===================================================================
--- linux-2.6.orig/fs/nfsd/vfs.c 2008-05-21 15:45:45.000000000 +0200
+++ linux-2.6/fs/nfsd/vfs.c 2008-05-21 16:36:07.000000000 +0200
@@ -1942,12 +1942,13 @@ nfsd_permission(struct svc_rqst *rqstp,
inode->i_uid == current->fsuid)
return 0;

- err = permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC), NULL);
+ err = dentry_permission(dentry, acc & (MAY_READ|MAY_WRITE|MAY_EXEC),
+ NULL);

/* Allow read access to binaries even when mode 111 */
if (err == -EACCES && S_ISREG(inode->i_mode) &&
acc == (MAY_READ | MAY_OWNER_OVERRIDE))
- err = permission(inode, MAY_EXEC, NULL);
+ err = dentry_permission(dentry, MAY_EXEC, NULL);

return err? nfserrno(err) : 0;
}
Index: linux-2.6/include/linux/fs.h
===================================================================
--- linux-2.6.orig/include/linux/fs.h 2008-05-21 15:45:10.000000000 +0200
+++ linux-2.6/include/linux/fs.h 2008-05-21 16:36:07.000000000 +0200
@@ -1758,7 +1758,7 @@ extern sector_t bmap(struct inode *, sec
#endif
extern int notify_change(struct dentry *, struct iattr *);
extern int path_setattr(struct path *, struct iattr *);
-extern int permission(struct inode *, int, struct nameidata *);
+extern int dentry_permission(struct dentry *, int, struct nameidata *);
extern int generic_permission(struct inode *, int,
int (*check_acl)(struct inode *, int));

Index: linux-2.6/fs/xattr.c
===================================================================
--- linux-2.6.orig/fs/xattr.c 2008-05-21 15:45:45.000000000 +0200
+++ linux-2.6/fs/xattr.c 2008-05-21 16:36:07.000000000 +0200
@@ -26,8 +26,10 @@
* because different namespaces have very different rules.
*/
static int
-xattr_permission(struct inode *inode, const char *name, int mask)
+xattr_permission(struct dentry *dentry, const char *name, int mask)
{
+ struct inode *inode = dentry->d_inode;
+
/*
* We can never set or remove an extended attribute on a read-only
* filesystem or on an immutable / append-only inode.
@@ -63,7 +65,7 @@ xattr_permission(struct inode *inode, co
return -EPERM;
}

- return permission(inode, mask, NULL);
+ return dentry_permission(dentry, mask, NULL);
}

static int
@@ -73,7 +75,7 @@ vfs_setxattr(struct dentry *dentry, cons
struct inode *inode = dentry->d_inode;
int error;

- error = xattr_permission(inode, name, MAY_WRITE);
+ error = xattr_permission(dentry, name, MAY_WRITE);
if (error)
return error;

@@ -150,7 +152,7 @@ path_getxattr(struct path *path, const c
struct inode *inode = dentry->d_inode;
int error;

- error = xattr_permission(inode, name, MAY_READ);
+ error = xattr_permission(dentry, name, MAY_READ);
if (error)
return error;

@@ -210,7 +212,7 @@ vfs_removexattr(struct dentry *dentry, c
if (!inode->i_op->removexattr)
return -EOPNOTSUPP;

- error = xattr_permission(inode, name, MAY_WRITE);
+ error = xattr_permission(dentry, name, MAY_WRITE);
if (error)
return error;

Index: linux-2.6/ipc/mqueue.c
===================================================================
--- linux-2.6.orig/ipc/mqueue.c 2008-05-21 15:45:10.000000000 +0200
+++ linux-2.6/ipc/mqueue.c 2008-05-21 16:36:07.000000000 +0200
@@ -653,7 +653,7 @@ static int oflag2acc[O_ACCMODE] = { MAY_
return ERR_PTR(-EINVAL);
}

- if (permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE], NULL)) {
+ if (dentry_permission(dentry, oflag2acc[oflag & O_ACCMODE], NULL)) {
dput(dentry);
mntput(mqueue_mnt);
return ERR_PTR(-EACCES);

--
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/