Commit 1025774c authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Al Viro

remove inode_setattr

Replace inode_setattr with opencoded variants of it in all callers.  This
moves the remaining call to vmtruncate into the filesystem methods where it
can be replaced with the proper truncate sequence.

In a few cases it was obvious that we would never end up calling vmtruncate
so it was left out in the opencoded variant:

 spufs: explicitly checks for ATTR_SIZE earlier
 btrfs,hugetlbfs,logfs,dlmfs: explicitly clears ATTR_SIZE earlier
 ufs: contains an opencoded simple_seattr + truncate that sets the filesize just above

In addition to that ncpfs called inode_setattr with handcrafted iattrs,
which allowed to trim down the opencoded variant.
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent eef2380c
......@@ -110,7 +110,9 @@ spufs_setattr(struct dentry *dentry, struct iattr *attr)
if ((attr->ia_valid & ATTR_SIZE) &&
(attr->ia_size != inode->i_size))
return -EINVAL;
return inode_setattr(inode, attr);
setattr_copy(inode, attr);
mark_inode_dirty(inode);
return 0;
}
......
......@@ -968,12 +968,18 @@ int pohmelfs_setattr_raw(struct inode *inode, struct iattr *attr)
goto err_out_exit;
}
err = inode_setattr(inode, attr);
if (err) {
dprintk("%s: ino: %llu, failed to set the attributes.\n", __func__, POHMELFS_I(inode)->ino);
goto err_out_exit;
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
err = vmtruncate(inode, attr->ia_size);
if (err) {
dprintk("%s: ino: %llu, failed to set the attributes.\n", __func__, POHMELFS_I(inode)->ino);
goto err_out_exit;
}
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
dprintk("%s: ino: %llu, mode: %o -> %o, uid: %u -> %u, gid: %u -> %u, size: %llu -> %llu.\n",
__func__, POHMELFS_I(inode)->ino, inode->i_mode, attr->ia_mode,
inode->i_uid, attr->ia_uid, inode->i_gid, attr->ia_gid, inode->i_size, attr->ia_size);
......
......@@ -896,10 +896,19 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
}
retval = p9_client_wstat(fid, &wstat);
if (retval >= 0)
retval = inode_setattr(dentry->d_inode, iattr);
if (retval < 0)
return retval;
if ((iattr->ia_valid & ATTR_SIZE) &&
iattr->ia_size != i_size_read(dentry->d_inode)) {
retval = vmtruncate(dentry->d_inode, iattr->ia_size);
if (retval)
return retval;
}
return retval;
setattr_copy(dentry->d_inode, iattr);
mark_inode_dirty(dentry->d_inode);
return 0;
}
/**
......
......@@ -235,8 +235,17 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr)
goto out;
}
error = inode_setattr(inode, attr);
if (!error && (attr->ia_valid & ATTR_MODE))
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
error = vmtruncate(inode, attr->ia_size);
if (error)
return error;
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
if (attr->ia_valid & ATTR_MODE)
mode_to_prot(inode);
out:
return error;
......
......@@ -146,31 +146,6 @@ void setattr_copy(struct inode *inode, const struct iattr *attr)
}
EXPORT_SYMBOL(setattr_copy);
/*
* note this function is deprecated, the new truncate sequence should be
* used instead -- see eg. simple_setsize, setattr_copy.
*/
int inode_setattr(struct inode *inode, const struct iattr *attr)
{
unsigned int ia_valid = attr->ia_valid;
if (ia_valid & ATTR_SIZE &&
attr->ia_size != i_size_read(inode)) {
int error;
error = vmtruncate(inode, attr->ia_size);
if (error)
return error;
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
return 0;
}
EXPORT_SYMBOL(inode_setattr);
int notify_change(struct dentry * dentry, struct iattr * attr)
{
struct inode *inode = dentry->d_inode;
......
......@@ -3656,13 +3656,15 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
if (err)
return err;
}
attr->ia_valid &= ~ATTR_SIZE;
if (attr->ia_valid)
err = inode_setattr(inode, attr);
if (attr->ia_valid) {
setattr_copy(inode, attr);
mark_inode_dirty(inode);
if (attr->ia_valid & ATTR_MODE)
err = btrfs_acl_chmod(inode);
}
if (!err && ((attr->ia_valid & ATTR_MODE)))
err = btrfs_acl_chmod(inode);
return err;
}
......
......@@ -1889,18 +1889,27 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
CIFS_MOUNT_MAP_SPECIAL_CHR);
}
if (!rc) {
rc = inode_setattr(inode, attrs);
if (rc)
goto out;
/* force revalidate when any of these times are set since some
of the fs types (eg ext3, fat) do not have fine enough
time granularity to match protocol, and we do not have a
a way (yet) to query the server fs's time granularity (and
whether it rounds times down).
*/
if (!rc && (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME)))
cifsInode->time = 0;
if ((attrs->ia_valid & ATTR_SIZE) &&
attrs->ia_size != i_size_read(inode)) {
rc = vmtruncate(inode, attrs->ia_size);
if (rc)
goto out;
}
setattr_copy(inode, attrs);
mark_inode_dirty(inode);
/* force revalidate when any of these times are set since some
of the fs types (eg ext3, fat) do not have fine enough
time granularity to match protocol, and we do not have a
a way (yet) to query the server fs's time granularity (and
whether it rounds times down).
*/
if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME))
cifsInode->time = 0;
out:
kfree(args);
kfree(full_path);
......@@ -2040,8 +2049,20 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
/* do not need local check to inode_check_ok since the server does
that */
if (!rc)
rc = inode_setattr(inode, attrs);
if (rc)
goto cifs_setattr_exit;
if ((attrs->ia_valid & ATTR_SIZE) &&
attrs->ia_size != i_size_read(inode)) {
rc = vmtruncate(inode, attrs->ia_size);
if (rc)
goto cifs_setattr_exit;
}
setattr_copy(inode, attrs);
mark_inode_dirty(inode);
return 0;
cifs_setattr_exit:
kfree(full_path);
FreeXid(xid);
......
......@@ -887,8 +887,18 @@ int exofs_setattr(struct dentry *dentry, struct iattr *iattr)
if (error)
return error;
error = inode_setattr(inode, iattr);
return error;
if ((iattr->ia_valid & ATTR_SIZE) &&
iattr->ia_size != i_size_read(inode)) {
int error;
error = vmtruncate(inode, iattr->ia_size);
if (error)
return error;
}
setattr_copy(inode, iattr);
mark_inode_dirty(inode);
return 0;
}
static const struct osd_attr g_attr_inode_file_layout = ATTR_DEF(
......
......@@ -3208,9 +3208,17 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
ext3_journal_stop(handle);
}
rc = inode_setattr(inode, attr);
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
rc = vmtruncate(inode, attr->ia_size);
if (rc)
goto err_out;
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
if (!rc && (ia_valid & ATTR_MODE))
if (ia_valid & ATTR_MODE)
rc = ext3_acl_chmod(inode);
err_out:
......
......@@ -5539,11 +5539,19 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
ext4_truncate(inode);
}
rc = inode_setattr(inode, attr);
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode))
rc = vmtruncate(inode, attr->ia_size);
/* If inode_setattr's call to ext4_truncate failed to get a
* transaction handle at all, we need to clean up the in-core
* orphan list manually. */
if (!rc) {
setattr_copy(inode, attr);
mark_inode_dirty(inode);
}
/*
* If the call to ext4_truncate failed to get a transaction handle at
* all, we need to clean up the in-core orphan list manually.
*/
if (inode->i_nlink)
ext4_orphan_del(NULL, inode);
......
......@@ -991,18 +991,29 @@ fail:
static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
{
struct inode *inode = &ip->i_inode;
struct buffer_head *dibh;
int error;
error = gfs2_meta_inode_buffer(ip, &dibh);
if (!error) {
error = inode_setattr(&ip->i_inode, attr);
gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error);
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
if (error)
return error;
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
error = vmtruncate(inode, attr->ia_size);
if (error)
return error;
}
return error;
setattr_copy(inode, attr);
mark_inode_dirty(inode);
gfs2_assert_warn(GFS2_SB(inode), !error);
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
return 0;
}
/**
......
......@@ -1136,8 +1136,16 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
if (error)
goto out_end_trans;
error = inode_setattr(inode, attr);
gfs2_assert_warn(sdp, !error);
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
int error;
error = vmtruncate(inode, attr->ia_size);
gfs2_assert_warn(sdp, !error);
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
......
......@@ -1296,6 +1296,7 @@ fail:
int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
{
struct inode *inode = &ip->i_inode;
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_ea_location el;
struct buffer_head *dibh;
......@@ -1321,14 +1322,25 @@ int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
return error;
error = gfs2_meta_inode_buffer(ip, &dibh);
if (!error) {
error = inode_setattr(&ip->i_inode, attr);
gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error);
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
if (error)
goto out_trans_end;
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
int error;
error = vmtruncate(inode, attr->ia_size);
gfs2_assert_warn(GFS2_SB(inode), !error);
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
out_trans_end:
gfs2_trans_end(sdp);
return error;
}
......
......@@ -612,10 +612,16 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr)
attr->ia_mode = inode->i_mode & ~S_IWUGO;
attr->ia_mode &= S_ISDIR(inode->i_mode) ? ~hsb->s_dir_umask: ~hsb->s_file_umask;
}
error = inode_setattr(inode, attr);
if (error)
return error;
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
error = vmtruncate(inode, attr->ia_size);
if (error)
return error;
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
return 0;
}
......
......@@ -298,7 +298,17 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
error = inode_change_ok(inode, attr);
if (error)
return error;
return inode_setattr(inode, attr);
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
error = vmtruncate(inode, attr->ia_size);
if (error)
return error;
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
return 0;
}
static const struct inode_operations hfsplus_file_inode_operations = {
......
......@@ -849,13 +849,14 @@ int hostfs_permission(struct inode *ino, int desired)
int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
{
struct inode *inode = dentry->d_inode;
struct hostfs_iattr attrs;
char *name;
int err;
int fd = HOSTFS_I(dentry->d_inode)->fd;
int fd = HOSTFS_I(inode)->fd;
err = inode_change_ok(dentry->d_inode, attr);
err = inode_change_ok(inode, attr);
if (err)
return err;
......@@ -905,7 +906,18 @@ int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
if (err)
return err;
return inode_setattr(dentry->d_inode, attr);
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
int error;
error = vmtruncate(inode, attr->ia_size);
if (err)
return err;
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
return 0;
}
static const struct inode_operations hostfs_iops = {
......
......@@ -277,9 +277,15 @@ int hpfs_setattr(struct dentry *dentry, struct iattr *attr)
if (error)
goto out_unlock;
error = inode_setattr(inode, attr);
if (error)
goto out_unlock;
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
error = vmtruncate(inode, attr->ia_size);
if (error)
return error;
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
hpfs_write_inode(inode);
......
......@@ -448,19 +448,20 @@ static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr)
error = inode_change_ok(inode, attr);
if (error)
goto out;
return error;
if (ia_valid & ATTR_SIZE) {
error = -EINVAL;
if (!(attr->ia_size & ~huge_page_mask(h)))
error = hugetlb_vmtruncate(inode, attr->ia_size);
if (attr->ia_size & ~huge_page_mask(h))
return -EINVAL;
error = hugetlb_vmtruncate(inode, attr->ia_size);
if (error)
goto out;
attr->ia_valid &= ~ATTR_SIZE;
return error;
}
error = inode_setattr(inode, attr);
out:
return error;
setattr_copy(inode, attr);
mark_inode_dirty(inode);
return 0;
}
static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid,
......
......@@ -17,6 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/quotaops.h>
#include "jfs_incore.h"
......@@ -107,11 +108,18 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
return rc;
}
rc = inode_setattr(inode, iattr);
if ((iattr->ia_valid & ATTR_SIZE) &&
iattr->ia_size != i_size_read(inode)) {
rc = vmtruncate(inode, iattr->ia_size);
if (rc)
return rc;
}
if (!rc && (iattr->ia_valid & ATTR_MODE))
rc = jfs_acl_chmod(inode);
setattr_copy(inode, iattr);
mark_inode_dirty(inode);
if (iattr->ia_valid & ATTR_MODE)
rc = jfs_acl_chmod(inode);
return rc;
}
......
......@@ -232,15 +232,19 @@ static int logfs_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = dentry->d_inode;
int err = 0;
if (attr->ia_valid & ATTR_SIZE)
if (attr->ia_valid & ATTR_SIZE) {
err = logfs_truncate(inode, attr->ia_size);
attr->ia_valid &= ~ATTR_SIZE;
if (err)
return err;
}
if (!err)
err = inode_change_ok(inode, attr);
if (!err)
err = inode_setattr(inode, attr);
return err;
err = inode_change_ok(inode, attr);
if (err)
return err;
setattr_copy(inode, attr);
mark_inode_dirty(inode);
return 0;
}
const struct inode_operations logfs_reg_iops = {
......
......@@ -31,7 +31,17 @@ static int minix_setattr(struct dentry *dentry, struct iattr *attr)
error = inode_change_ok(inode, attr);
if (error)
return error;
return inode_setattr(inode, attr);
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
error = vmtruncate(inode, attr->ia_size);
if (error)
return error;
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
return 0;
}
const struct inode_operations minix_file_inode_operations = {
......
......@@ -924,9 +924,8 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
tmpattr.ia_valid = ATTR_MODE;
tmpattr.ia_mode = attr->ia_mode;
result = inode_setattr(inode, &tmpattr);
if (result)
goto out;
setattr_copy(inode, &tmpattr);
mark_inode_dirty(inode);
}
}
#endif
......@@ -954,15 +953,12 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
result = ncp_make_closed(inode);
if (result)
goto out;
{
struct iattr tmpattr;
tmpattr.ia_valid = ATTR_SIZE;
tmpattr.ia_size = attr->ia_size;
result = inode_setattr(inode, &tmpattr);
if (attr->ia_size != i_size_read(inode)) {
result = vmtruncate(inode, attr->ia_size);
if (result)
goto out;
mark_inode_dirty(inode);
}
}
if ((attr->ia_valid & ATTR_CTIME) != 0) {
......@@ -1002,8 +998,12 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
NCP_FINFO(inode)->nwattr = info.attributes;
#endif
}
if (!result)
result = inode_setattr(inode, attr);
if (result)
goto out;
setattr_copy(inode, attr);
mark_inode_dirty(inode);
out:
unlock_kernel();
return result;
......
......@@ -656,14 +656,27 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr)
err = nilfs_transaction_begin(sb, &ti, 0);
if (unlikely(err))
return err;
err = inode_setattr(inode, iattr);
if (!err && (iattr->ia_valid & ATTR_MODE))
if ((iattr->ia_valid & ATTR_SIZE) &&
iattr->ia_size != i_size_read(inode)) {
err = vmtruncate(inode, iattr->ia_size);
if (unlikely(err))
goto out_err;
}
setattr_copy(inode, iattr);
mark_inode_dirty(inode);
if (iattr->ia_valid & ATTR_MODE) {
err = nilfs_acl_chmod(inode);
if (likely(!err))
err = nilfs_transaction_commit(sb);
else
nilfs_transaction_abort(sb);
if (unlikely(err))
goto out_err;
}
return nilfs_transaction_commit(sb);
out_err:
nilfs_transaction_abort(sb);
return err;
}
......
......@@ -2879,9 +2879,6 @@ void ntfs_truncate_vfs(struct inode *vi) {
*
* Called with ->i_mutex held. For the ATTR_SIZE (i.e. ->truncate) case, also
* called with ->i_alloc_sem held for writing.
*
* Basically this is a copy of generic notify_change() and inode_setattr()
* functionality, except we intercept and abort changes in i_size.
*/
int ntfs_setattr(struct dentry *dentry, struct iattr *attr)
{
......
......@@ -214,10 +214,12 @@ static int dlmfs_file_setattr(struct dentry *dentry, struct iattr *attr)
attr->ia_valid &= ~ATTR_SIZE;
error = inode_change_ok(inode, attr);
if (!error)
error = inode_setattr(inode, attr);
if (error)
return error;
return error;
setattr_copy(inode, attr);
mark_inode_dirty(inode);
return 0;
}
static unsigned int dlmfs_file_poll(struct file *file, poll_table *wait)
......
......@@ -1238,13 +1238,21 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
* Otherwise, we could get into problems with truncate as
* ip_alloc_sem is used there to protect against i_size
* changes.
*
* XXX: this means the conditional below can probably be removed.
*/
status = inode_setattr(inode, attr);
if (status < 0) {
mlog_errno(status);
goto bail_commit;
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
status = vmtruncate(inode, attr->ia_size);
if (status) {
mlog_errno(status);
goto bail_commit;
}
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
status = ocfs2_mark_inode_dirty(handle, inode, bh);
if (status < 0)
mlog_errno(status);
......
......@@ -349,7 +349,17 @@ static int omfs_setattr(struct dentry *dentry, struct iattr *attr)
error = inode_change_ok(inode, attr);
if (error)
return error;
return inode_setattr(inode, attr);
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
error = vmtruncate(inode, attr->ia_size);
if (error)
return error;
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
return 0;
}
const struct inode_operations omfs_file_inops = {
......
......@@ -561,9 +561,19 @@ static int proc_setattr(struct dentry *dentry, struct iattr *attr)
return -EPERM;
error = inode_change_ok(inode, attr);
if (!error)
error = inode_setattr(inode, attr);
return error;