[PATCH 3.2 145/152] fs: Give dentry to inode_change_ok() instead of inode

From: Ben Hutchings
Date: Sun Nov 13 2016 - 21:10:25 EST


3.2.84-rc1 review patch. If anyone has any objections, please let me know.

------------------

From: Jan Kara <jack@xxxxxxx>

commit 31051c85b5e2aaaf6315f74c72a732673632a905 upstream.

inode_change_ok() will be resposible for clearing capabilities and IMA
extended attributes and as such will need dentry. Give it as an argument
to inode_change_ok() instead of an inode. Also rename inode_change_ok()
to setattr_prepare() to better relect that it does also some
modifications in addition to checks.

Reviewed-by: Christoph Hellwig <hch@xxxxxx>
Signed-off-by: Jan Kara <jack@xxxxxxx>
[bwh: Backported to 3.2:
- Drop changes to f2fs, lustre, orangefs, overlayfs
- Adjust filenames, context
- In nfsd, pass dentry to nfsd_sanitize_attrs()
- In xfs, pass dentry to xfs_change_file_space(), xfs_set_mode(),
xfs_setattr_nonsize(), and xfs_setattr_size()
- Update ext3 as well
- Mark pohmelfs as BROKEN; it's long dead upstream]
Signed-off-by: Ben Hutchings <ben@xxxxxxxxxxxxxxx>
---
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -288,8 +288,8 @@ implementing on-disk size changes. Star
and vmtruncate, and the reorder the vmtruncate + foofs_vmtruncate sequence to
be in order of zeroing blocks using block_truncate_page or similar helpers,
size update and on finally on-disk truncation which should not fail.
-inode_change_ok now includes the size checks for ATTR_SIZE and must be called
-in the beginning of ->setattr unconditionally.
+setattr_prepare (which used to be inode_change_ok) now includes the size checks
+for ATTR_SIZE and must be called in the beginning of ->setattr unconditionally.

[mandatory]

--- a/drivers/staging/pohmelfs/Kconfig
+++ b/drivers/staging/pohmelfs/Kconfig
@@ -1,5 +1,6 @@
config POHMELFS
tristate "POHMELFS filesystem support"
+ depends on BROKEN
depends on NET
select CONNECTOR
select CRYPTO
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -1068,7 +1068,7 @@ static int v9fs_vfs_setattr(struct dentr
struct p9_wstat wstat;

P9_DPRINTK(P9_DEBUG_VFS, "\n");
- retval = inode_change_ok(dentry->d_inode, iattr);
+ retval = setattr_prepare(dentry, iattr);
if (retval)
return retval;

--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -538,7 +538,7 @@ int v9fs_vfs_setattr_dotl(struct dentry

P9_DPRINTK(P9_DEBUG_VFS, "\n");

- retval = inode_change_ok(dentry->d_inode, iattr);
+ retval = setattr_prepare(dentry, iattr);
if (retval)
return retval;

--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -298,7 +298,7 @@ adfs_notify_change(struct dentry *dentry
unsigned int ia_valid = attr->ia_valid;
int error;

- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);

/*
* we can't change the UID or GID of any file -
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -222,7 +222,7 @@ affs_notify_change(struct dentry *dentry

pr_debug("AFFS: notify_change(%lu,0x%x)\n",inode->i_ino,attr->ia_valid);

- error = inode_change_ok(inode,attr);
+ error = setattr_prepare(dentry, attr);
if (error)
goto out;

--- a/fs/attr.c
+++ b/fs/attr.c
@@ -16,19 +16,22 @@
#include <linux/evm.h>

/**
- * inode_change_ok - check if attribute changes to an inode are allowed
- * @inode: inode to check
+ * setattr_prepare - check if attribute changes to a dentry are allowed
+ * @dentry: dentry to check
* @attr: attributes to change
*
* Check if we are allowed to change the attributes contained in @attr
- * in the given inode. This includes the normal unix access permission
- * checks, as well as checks for rlimits and others.
+ * in the given dentry. This includes the normal unix access permission
+ * checks, as well as checks for rlimits and others. The function also clears
+ * SGID bit from mode if user is not allowed to set it. Also file capabilities
+ * and IMA extended attributes are cleared if ATTR_KILL_PRIV is set.
*
* Should be called as the first thing in ->setattr implementations,
* possibly after taking additional locks.
*/
-int inode_change_ok(const struct inode *inode, struct iattr *attr)
+int setattr_prepare(struct dentry *dentry, struct iattr *attr)
{
+ struct inode *inode = dentry->d_inode;
unsigned int ia_valid = attr->ia_valid;

/*
@@ -76,7 +79,7 @@ int inode_change_ok(const struct inode *

return 0;
}
-EXPORT_SYMBOL(inode_change_ok);
+EXPORT_SYMBOL(setattr_prepare);

/**
* inode_newsize_ok - may this inode be truncated to a given size
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3533,7 +3533,7 @@ static int btrfs_setattr(struct dentry *
if (btrfs_root_readonly(root))
return -EROFS;

- err = inode_change_ok(inode, attr);
+ err = setattr_prepare(dentry, attr);
if (err)
return err;

--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -1541,7 +1541,7 @@ int ceph_setattr(struct dentry *dentry,

__ceph_do_pending_vmtruncate(inode);

- err = inode_change_ok(inode, attr);
+ err = setattr_prepare(dentry, attr);
if (err != 0)
return err;

--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1948,7 +1948,7 @@ cifs_setattr_unix(struct dentry *direntr
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
attrs->ia_valid |= ATTR_FORCE;

- rc = inode_change_ok(inode, attrs);
+ rc = setattr_prepare(direntry, attrs);
if (rc < 0)
goto out;

@@ -2089,7 +2089,7 @@ cifs_setattr_nounix(struct dentry *diren
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
attrs->ia_valid |= ATTR_FORCE;

- rc = inode_change_ok(inode, attrs);
+ rc = setattr_prepare(direntry, attrs);
if (rc < 0) {
FreeXid(xid);
return rc;
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -1026,7 +1026,7 @@ static int ecryptfs_setattr(struct dentr
}
mutex_unlock(&crypt_stat->cs_mutex);

- rc = inode_change_ok(inode, ia);
+ rc = setattr_prepare(dentry, ia);
if (rc)
goto out;
if (ia->ia_valid & ATTR_SIZE) {
--- a/fs/exofs/inode.c
+++ b/fs/exofs/inode.c
@@ -1018,7 +1018,7 @@ int exofs_setattr(struct dentry *dentry,
if (unlikely(error))
return error;

- error = inode_change_ok(inode, iattr);
+ error = setattr_prepare(dentry, iattr);
if (unlikely(error))
return error;

--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1530,7 +1530,7 @@ int ext2_setattr(struct dentry *dentry,
struct inode *inode = dentry->d_inode;
int error;

- error = inode_change_ok(inode, iattr);
+ error = setattr_prepare(dentry, iattr);
if (error)
return error;

--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -3271,7 +3271,7 @@ int ext3_setattr(struct dentry *dentry,
int error, rc = 0;
const unsigned int ia_valid = attr->ia_valid;

- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;

--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4291,7 +4291,7 @@ int ext4_setattr(struct dentry *dentry,
int orphan = 0;
const unsigned int ia_valid = attr->ia_valid;

- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;

--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -382,7 +382,7 @@ int fat_setattr(struct dentry *dentry, s
attr->ia_valid &= ~TIMES_SET_FLAGS;
}

- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
attr->ia_valid = ia_valid;
if (error) {
if (sbi->options.quiet)
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1298,7 +1298,7 @@ static int fuse_do_setattr(struct dentry
if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
attr->ia_valid |= ATTR_FORCE;

- err = inode_change_ok(inode, attr);
+ err = setattr_prepare(entry, attr);
if (err)
return err;

--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -1646,7 +1646,7 @@ static int gfs2_setattr(struct dentry *d
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
goto out;

- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
goto out;

--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -588,7 +588,7 @@ int hfs_inode_setattr(struct dentry *den
struct hfs_sb_info *hsb = HFS_SB(inode->i_sb);
int error;

- error = inode_change_ok(inode, attr); /* basic permission checks */
+ error = setattr_prepare(dentry, attr); /* basic permission checks */
if (error)
return error;

--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -292,7 +292,7 @@ static int hfsplus_setattr(struct dentry
struct inode *inode = dentry->d_inode;
int error;

- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;

--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -792,7 +792,7 @@ int hostfs_setattr(struct dentry *dentry

int fd = HOSTFS_I(inode)->fd;

- err = inode_change_ok(inode, attr);
+ err = setattr_prepare(dentry, attr);
if (err)
return err;

--- a/fs/hpfs/inode.c
+++ b/fs/hpfs/inode.c
@@ -268,7 +268,7 @@ int hpfs_setattr(struct dentry *dentry,
if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size > inode->i_size)
goto out_unlock;

- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
goto out_unlock;

--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -422,7 +422,7 @@ static int hugetlbfs_setattr(struct dent

BUG_ON(!inode);

- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;

--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -186,7 +186,7 @@ int jffs2_setattr(struct dentry *dentry,
{
int rc;

- rc = inode_change_ok(dentry->d_inode, iattr);
+ rc = setattr_prepare(dentry, iattr);
if (rc)
return rc;

--- a/fs/jfs/file.c
+++ b/fs/jfs/file.c
@@ -102,7 +102,7 @@ int jfs_setattr(struct dentry *dentry, s
struct inode *inode = dentry->d_inode;
int rc;

- rc = inode_change_ok(inode, iattr);
+ rc = setattr_prepare(dentry, iattr);
if (rc)
return rc;

--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -364,7 +364,7 @@ int simple_setattr(struct dentry *dentry

WARN_ON_ONCE(inode->i_op->truncate);

- error = inode_change_ok(inode, iattr);
+ error = setattr_prepare(dentry, iattr);
if (error)
return error;

--- a/fs/logfs/file.c
+++ b/fs/logfs/file.c
@@ -241,7 +241,7 @@ static int logfs_setattr(struct dentry *
struct inode *inode = dentry->d_inode;
int err = 0;

- err = inode_change_ok(inode, attr);
+ err = setattr_prepare(dentry, attr);
if (err)
return err;

--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -28,7 +28,7 @@ static int minix_setattr(struct dentry *
struct inode *inode = dentry->d_inode;
int error;

- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;

--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -880,7 +880,7 @@ int ncp_notify_change(struct dentry *den
/* ageing the dentry to force validation */
ncp_age_dentry(server, dentry);

- result = inode_change_ok(inode, attr);
+ result = setattr_prepare(dentry, attr);
if (result < 0)
goto out;

--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -301,17 +301,19 @@ commit_metadata(struct svc_fh *fhp)
* NFS semantics and what Linux expects.
*/
static void
-nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap)
+nfsd_sanitize_attrs(struct dentry *dentry, struct iattr *iap)
{
+ struct inode *inode = dentry->d_inode;
+
/*
* NFSv2 does not differentiate between "set-[ac]time-to-now"
* which only requires access, and "set-[ac]time-to-X" which
* requires ownership.
* So if it looks like it might be "set both to the same time which
- * is close to now", and if inode_change_ok fails, then we
+ * is close to now", and if setattr_prepare fails, then we
* convert to "set to now" instead of "set to explicit time"
*
- * We only call inode_change_ok as the last test as technically
+ * We only call setattr_prepare as the last test as technically
* it is not an interface that we should be using.
*/
#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
@@ -329,7 +331,7 @@ nfsd_sanitize_attrs(struct inode *inode,
if (delta < 0)
delta = -delta;
if (delta < MAX_TOUCH_TIME_ERROR &&
- inode_change_ok(inode, iap) != 0) {
+ setattr_prepare(dentry, iap) != 0) {
/*
* Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME.
* This will cause notify_change to set these times
@@ -437,7 +439,7 @@ nfsd_setattr(struct svc_rqst *rqstp, str
if (!iap->ia_valid)
goto out;

- nfsd_sanitize_attrs(inode, iap);
+ nfsd_sanitize_attrs(dentry, iap);

/*
* The size case is special, it changes the file in addition to the
--- a/fs/nilfs2/inode.c
+++ b/fs/nilfs2/inode.c
@@ -792,7 +792,7 @@ int nilfs_setattr(struct dentry *dentry,
struct super_block *sb = inode->i_sb;
int err;

- err = inode_change_ok(inode, iattr);
+ err = setattr_prepare(dentry, iattr);
if (err)
return err;

--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -2890,7 +2890,7 @@ int ntfs_setattr(struct dentry *dentry,
int err;
unsigned int ia_valid = attr->ia_valid;

- err = inode_change_ok(vi, attr);
+ err = setattr_prepare(dentry, attr);
if (err)
goto out;
/* We do not support NTFS ACLs yet. */
--- a/fs/ocfs2/dlmfs/dlmfs.c
+++ b/fs/ocfs2/dlmfs/dlmfs.c
@@ -212,7 +212,7 @@ static int dlmfs_file_setattr(struct den
struct inode *inode = dentry->d_inode;

attr->ia_valid &= ~ATTR_SIZE;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;

--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1127,7 +1127,7 @@ int ocfs2_setattr(struct dentry *dentry,
if (!(attr->ia_valid & OCFS2_VALID_ATTRS))
return 0;

- status = inode_change_ok(inode, attr);
+ status = setattr_prepare(dentry, attr);
if (status)
return status;

--- a/fs/omfs/file.c
+++ b/fs/omfs/file.c
@@ -345,7 +345,7 @@ static int omfs_setattr(struct dentry *d
struct inode *inode = dentry->d_inode;
int error;

- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;

--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -558,7 +558,7 @@ int proc_setattr(struct dentry *dentry,
if (attr->ia_valid & ATTR_MODE)
return -EPERM;

- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;

--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -257,7 +257,7 @@ static int proc_notify_change(struct den
struct proc_dir_entry *de = PDE(inode);
int error;

- error = inode_change_ok(inode, iattr);
+ error = setattr_prepare(dentry, iattr);
if (error)
return error;

--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -387,7 +387,7 @@ static int proc_sys_setattr(struct dentr
if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
return -EPERM;

- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;

--- a/fs/ramfs/file-nommu.c
+++ b/fs/ramfs/file-nommu.c
@@ -164,7 +164,7 @@ static int ramfs_nommu_setattr(struct de
int ret = 0;

/* POSIX UID/GID verification for setting inode attributes */
- ret = inode_change_ok(inode, ia);
+ ret = setattr_prepare(dentry, ia);
if (ret)
return ret;

--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -3107,7 +3107,7 @@ int reiserfs_setattr(struct dentry *dent
int depth;
int error;

- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;

--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -114,7 +114,7 @@ int sysfs_setattr(struct dentry *dentry,
return -EINVAL;

mutex_lock(&sysfs_mutex);
- error = inode_change_ok(inode, iattr);
+ error = setattr_prepare(dentry, iattr);
if (error)
goto out;

--- a/fs/sysv/file.c
+++ b/fs/sysv/file.c
@@ -35,7 +35,7 @@ static int sysv_setattr(struct dentry *d
struct inode *inode = dentry->d_inode;
int error;

- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;

--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1260,7 +1260,7 @@ int ubifs_setattr(struct dentry *dentry,

dbg_gen("ino %lu, mode %#x, ia_valid %#x",
inode->i_ino, inode->i_mode, attr->ia_valid);
- err = inode_change_ok(inode, attr);
+ err = setattr_prepare(dentry, attr);
if (err)
return err;

--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -251,7 +251,7 @@ static int udf_setattr(struct dentry *de
struct inode *inode = dentry->d_inode;
int error;

- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;

--- a/fs/ufs/truncate.c
+++ b/fs/ufs/truncate.c
@@ -496,7 +496,7 @@ int ufs_setattr(struct dentry *dentry, s
unsigned int ia_valid = attr->ia_valid;
int error;

- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;

--- a/fs/utimes.c
+++ b/fs/utimes.c
@@ -80,7 +80,7 @@ static int utimes_common(struct path *pa
newattrs.ia_valid |= ATTR_MTIME_SET;
}
/*
- * Tell inode_change_ok(), that this is an explicit time
+ * Tell setattr_prepare(), that this is an explicit time
* update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET
* were used.
*/
@@ -89,7 +89,7 @@ static int utimes_common(struct path *pa
/*
* If times is NULL (or both times are UTIME_NOW),
* then we need to check permissions, because
- * inode_change_ok() won't do it.
+ * setattr_prepare() won't do it.
*/
error = -EACCES;
if (IS_IMMUTABLE(inode))
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -223,7 +223,7 @@ xfs_set_acl(struct inode *inode, int typ
}

static int
-xfs_set_mode(struct inode *inode, umode_t mode)
+xfs_set_mode(struct dentry *dentry, struct inode *inode, umode_t mode)
{
int error = 0;

@@ -234,7 +234,8 @@ xfs_set_mode(struct inode *inode, umode_
iattr.ia_mode = mode;
iattr.ia_ctime = current_fs_time(inode->i_sb);

- error = -xfs_setattr_nonsize(XFS_I(inode), &iattr, XFS_ATTR_NOACL);
+ error = -xfs_setattr_nonsize(dentry, XFS_I(inode), &iattr,
+ XFS_ATTR_NOACL);
}

return error;
@@ -290,7 +291,7 @@ xfs_inherit_acl(struct inode *inode, str
if (error > 0)
inherit = 1;

- error = xfs_set_mode(inode, mode);
+ error = xfs_set_mode(NULL, inode, mode);
if (error)
goto out;

@@ -394,7 +395,7 @@ xfs_xattr_acl_set(struct dentry *dentry,
return error;
}

- error = xfs_set_mode(inode, mode);
+ error = xfs_set_mode(dentry, inode, mode);
if (error)
goto out_release;
}
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -1026,7 +1026,8 @@ xfs_file_fallocate(
if (file->f_flags & O_DSYNC)
attr_flags |= XFS_ATTR_SYNC;

- error = -xfs_change_file_space(ip, cmd, &bf, 0, attr_flags);
+ error = -xfs_change_file_space(file->f_dentry, cmd, &bf, 0,
+ attr_flags);
if (error)
goto out_unlock;

@@ -1036,7 +1037,8 @@ xfs_file_fallocate(

iattr.ia_valid = ATTR_SIZE;
iattr.ia_size = new_size;
- error = -xfs_setattr_size(ip, &iattr, XFS_ATTR_NOLOCK);
+ error = -xfs_setattr_size(file->f_dentry, &iattr,
+ XFS_ATTR_NOLOCK);
}

out_unlock:
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -632,7 +632,8 @@ xfs_ioc_space(
if (ioflags & IO_INVIS)
attr_flags |= XFS_ATTR_DMI;

- error = xfs_change_file_space(ip, cmd, bf, filp->f_pos, attr_flags);
+ error = xfs_change_file_space(filp->f_dentry, cmd, bf, filp->f_pos,
+ attr_flags);
return -error;
}

--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -531,6 +531,7 @@ xfs_setattr_mode(

int
xfs_setattr_nonsize(
+ struct dentry *dentry,
struct xfs_inode *ip,
struct iattr *iattr,
int flags)
@@ -553,9 +554,15 @@ xfs_setattr_nonsize(
if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);

- error = -inode_change_ok(inode, iattr);
- if (error)
- return XFS_ERROR(error);
+ /*
+ * dentry can be NULL only when we're called from xfs_inherit_acl(),
+ * in which case no permission checks are needed
+ */
+ if (dentry) {
+ error = -setattr_prepare(dentry, iattr);
+ if (error)
+ return XFS_ERROR(error);
+ }

ASSERT((mask & ATTR_SIZE) == 0);

@@ -755,12 +762,13 @@ out_dqrele:
*/
int
xfs_setattr_size(
- struct xfs_inode *ip,
+ struct dentry *dentry,
struct iattr *iattr,
int flags)
{
+ struct inode *inode = dentry->d_inode;
+ struct xfs_inode *ip = XFS_I(inode);
struct xfs_mount *mp = ip->i_mount;
- struct inode *inode = VFS_I(ip);
int mask = iattr->ia_valid;
struct xfs_trans *tp;
int error;
@@ -776,7 +784,7 @@ xfs_setattr_size(
if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);

- error = -inode_change_ok(inode, iattr);
+ error = -setattr_prepare(dentry, iattr);
if (error)
return XFS_ERROR(error);

@@ -802,7 +810,7 @@ xfs_setattr_size(
*/
xfs_iunlock(ip, lock_flags);
iattr->ia_valid &= ~ATTR_SIZE;
- return xfs_setattr_nonsize(ip, iattr, 0);
+ return xfs_setattr_nonsize(dentry, ip, iattr, 0);
}

/*
@@ -950,8 +958,8 @@ xfs_vn_setattr(
struct iattr *iattr)
{
if (iattr->ia_valid & ATTR_SIZE)
- return -xfs_setattr_size(XFS_I(dentry->d_inode), iattr, 0);
- return -xfs_setattr_nonsize(XFS_I(dentry->d_inode), iattr, 0);
+ return -xfs_setattr_size(dentry, iattr, 0);
+ return -xfs_setattr_nonsize(dentry, XFS_I(dentry->d_inode), iattr, 0);
}

#define XFS_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR)
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -2234,12 +2234,13 @@ xfs_free_file_space(
*/
int
xfs_change_file_space(
- xfs_inode_t *ip,
+ struct dentry *dentry,
int cmd,
xfs_flock64_t *bf,
xfs_off_t offset,
int attr_flags)
{
+ xfs_inode_t *ip = XFS_I(dentry->d_inode);
xfs_mount_t *mp = ip->i_mount;
int clrprealloc;
int error;
@@ -2329,7 +2330,7 @@ xfs_change_file_space(
iattr.ia_valid = ATTR_SIZE;
iattr.ia_size = startoffset;

- error = xfs_setattr_size(ip, &iattr, attr_flags);
+ error = xfs_setattr_size(dentry, &iattr, attr_flags);

if (error)
return error;
--- a/fs/xfs/xfs_vnodeops.h
+++ b/fs/xfs/xfs_vnodeops.h
@@ -13,8 +13,9 @@ struct xfs_inode;
struct xfs_iomap;


-int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap, int flags);
-int xfs_setattr_size(struct xfs_inode *ip, struct iattr *vap, int flags);
+int xfs_setattr_nonsize(struct dentry *dentry, struct xfs_inode *ip,
+ struct iattr *vap, int flags);
+int xfs_setattr_size(struct dentry *dentry, struct iattr *vap, int flags);
#define XFS_ATTR_DMI 0x01 /* invocation from a DMI function */
#define XFS_ATTR_NONBLOCK 0x02 /* return EAGAIN if operation would block */
#define XFS_ATTR_NOLOCK 0x04 /* Don't grab any conflicting locks */
@@ -37,7 +38,7 @@ int xfs_readdir(struct xfs_inode *dp, vo
int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name,
const char *target_path, mode_t mode, struct xfs_inode **ipp);
int xfs_set_dmattrs(struct xfs_inode *ip, u_int evmask, u_int16_t state);
-int xfs_change_file_space(struct xfs_inode *ip, int cmd,
+int xfs_change_file_space(struct dentry *dentry, int cmd,
xfs_flock64_t *bf, xfs_off_t offset, int attr_flags);
int xfs_rename(struct xfs_inode *src_dp, struct xfs_name *src_name,
struct xfs_inode *src_ip, struct xfs_inode *target_dp,
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2615,7 +2615,7 @@ extern int buffer_migrate_page(struct ad
#define buffer_migrate_page NULL
#endif

-extern int inode_change_ok(const struct inode *, struct iattr *);
+extern int setattr_prepare(struct dentry *, struct iattr *);
extern int inode_newsize_ok(const struct inode *, loff_t offset);
extern void setattr_copy(struct inode *inode, const struct iattr *attr);

--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -562,7 +562,7 @@ static int shmem_setattr(struct dentry *
struct inode *inode = dentry->d_inode;
int error;

- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;