Merge remote-tracking branch 'jk/vfs' into work.misc

This commit is contained in:
Al Viro 2016-10-08 11:06:08 -04:00
commit e55f1d1d13
76 changed files with 296 additions and 225 deletions

View File

@ -287,8 +287,8 @@ implementing on-disk size changes. Start with a copy of the old inode_setattr
and vmtruncate, and the reorder the vmtruncate + foofs_vmtruncate sequence to and vmtruncate, and the reorder the vmtruncate + foofs_vmtruncate sequence to
be in order of zeroing blocks using block_truncate_page or similar helpers, 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. 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 setattr_prepare (which used to be inode_change_ok) now includes the size checks
in the beginning of ->setattr unconditionally. for ATTR_SIZE and must be called in the beginning of ->setattr unconditionally.
[mandatory] [mandatory]

View File

@ -1192,7 +1192,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import)
attr->ia_valid |= ATTR_MTIME | ATTR_CTIME; attr->ia_valid |= ATTR_MTIME | ATTR_CTIME;
} }
/* POSIX: check before ATTR_*TIME_SET set (from inode_change_ok) */ /* POSIX: check before ATTR_*TIME_SET set (from setattr_prepare) */
if (attr->ia_valid & TIMES_SET_FLAGS) { if (attr->ia_valid & TIMES_SET_FLAGS) {
if ((!uid_eq(current_fsuid(), inode->i_uid)) && if ((!uid_eq(current_fsuid(), inode->i_uid)) &&
!capable(CFS_CAP_FOWNER)) !capable(CFS_CAP_FOWNER))

View File

@ -276,32 +276,26 @@ static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
switch (handler->flags) { switch (handler->flags) {
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
if (acl) { if (acl) {
umode_t mode = inode->i_mode; struct iattr iattr;
retval = posix_acl_equiv_mode(acl, &mode);
if (retval < 0) retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
if (retval)
goto err_out; goto err_out;
else { if (!acl) {
struct iattr iattr; /*
if (retval == 0) { * ACL can be represented
/* * by the mode bits. So don't
* ACL can be represented * update ACL.
* by the mode bits. So don't
* update ACL.
*/
acl = NULL;
value = NULL;
size = 0;
}
/* Updte the mode bits */
iattr.ia_mode = ((mode & S_IALLUGO) |
(inode->i_mode & ~S_IALLUGO));
iattr.ia_valid = ATTR_MODE;
/* FIXME should we update ctime ?
* What is the following setxattr update the
* mode ?
*/ */
v9fs_vfs_setattr_dotl(dentry, &iattr); value = NULL;
size = 0;
} }
iattr.ia_valid = ATTR_MODE;
/* FIXME should we update ctime ?
* What is the following setxattr update the
* mode ?
*/
v9fs_vfs_setattr_dotl(dentry, &iattr);
} }
break; break;
case ACL_TYPE_DEFAULT: case ACL_TYPE_DEFAULT:

View File

@ -1094,7 +1094,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
struct p9_wstat wstat; struct p9_wstat wstat;
p9_debug(P9_DEBUG_VFS, "\n"); p9_debug(P9_DEBUG_VFS, "\n");
retval = inode_change_ok(d_inode(dentry), iattr); retval = setattr_prepare(dentry, iattr);
if (retval) if (retval)
return retval; return retval;

View File

@ -558,7 +558,7 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
p9_debug(P9_DEBUG_VFS, "\n"); p9_debug(P9_DEBUG_VFS, "\n");
retval = inode_change_ok(inode, iattr); retval = setattr_prepare(dentry, iattr);
if (retval) if (retval)
return retval; return retval;

View File

@ -303,7 +303,7 @@ adfs_notify_change(struct dentry *dentry, struct iattr *attr)
unsigned int ia_valid = attr->ia_valid; unsigned int ia_valid = attr->ia_valid;
int error; int error;
error = inode_change_ok(inode, attr); error = setattr_prepare(dentry, attr);
/* /*
* we can't change the UID or GID of any file - * we can't change the UID or GID of any file -

View File

@ -219,7 +219,7 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr)
pr_debug("notify_change(%lu,0x%x)\n", inode->i_ino, attr->ia_valid); pr_debug("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) if (error)
goto out; goto out;

View File

@ -17,19 +17,22 @@
#include <linux/ima.h> #include <linux/ima.h>
/** /**
* inode_change_ok - check if attribute changes to an inode are allowed * setattr_prepare - check if attribute changes to a dentry are allowed
* @inode: inode to check * @dentry: dentry to check
* @attr: attributes to change * @attr: attributes to change
* *
* Check if we are allowed to change the attributes contained in @attr * Check if we are allowed to change the attributes contained in @attr
* in the given inode. This includes the normal unix access permission * in the given dentry. This includes the normal unix access permission
* checks, as well as checks for rlimits and others. * 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, * Should be called as the first thing in ->setattr implementations,
* possibly after taking additional locks. * 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 = d_inode(dentry);
unsigned int ia_valid = attr->ia_valid; unsigned int ia_valid = attr->ia_valid;
/* /*
@ -44,7 +47,7 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
/* If force is set do it anyway. */ /* If force is set do it anyway. */
if (ia_valid & ATTR_FORCE) if (ia_valid & ATTR_FORCE)
return 0; goto kill_priv;
/* Make sure a caller can chown. */ /* Make sure a caller can chown. */
if ((ia_valid & ATTR_UID) && if ((ia_valid & ATTR_UID) &&
@ -77,9 +80,19 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
return -EPERM; return -EPERM;
} }
kill_priv:
/* User has permission for the change */
if (ia_valid & ATTR_KILL_PRIV) {
int error;
error = security_inode_killpriv(dentry);
if (error)
return error;
}
return 0; return 0;
} }
EXPORT_SYMBOL(inode_change_ok); EXPORT_SYMBOL(setattr_prepare);
/** /**
* inode_newsize_ok - may this inode be truncated to a given size * inode_newsize_ok - may this inode be truncated to a given size
@ -232,13 +245,11 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
if (!(ia_valid & ATTR_MTIME_SET)) if (!(ia_valid & ATTR_MTIME_SET))
attr->ia_mtime = now; attr->ia_mtime = now;
if (ia_valid & ATTR_KILL_PRIV) { if (ia_valid & ATTR_KILL_PRIV) {
attr->ia_valid &= ~ATTR_KILL_PRIV;
ia_valid &= ~ATTR_KILL_PRIV;
error = security_inode_need_killpriv(dentry); error = security_inode_need_killpriv(dentry);
if (error > 0) if (error < 0)
error = security_inode_killpriv(dentry);
if (error)
return error; return error;
if (error == 0)
ia_valid = attr->ia_valid &= ~ATTR_KILL_PRIV;
} }
/* /*

View File

@ -79,11 +79,9 @@ static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS; name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) { if (acl) {
ret = posix_acl_equiv_mode(acl, &inode->i_mode); ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
if (ret < 0) if (ret)
return ret; return ret;
if (ret == 0)
acl = NULL;
} }
ret = 0; ret = 0;
break; break;

View File

@ -5072,7 +5072,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
if (btrfs_root_readonly(root)) if (btrfs_root_readonly(root))
return -EROFS; return -EROFS;
err = inode_change_ok(inode, attr); err = setattr_prepare(dentry, attr);
if (err) if (err)
return err; return err;

View File

@ -95,11 +95,9 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS; name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) { if (acl) {
ret = posix_acl_equiv_mode(acl, &new_mode); ret = posix_acl_update_mode(inode, &new_mode, &acl);
if (ret < 0) if (ret)
goto out; goto out;
if (ret == 0)
acl = NULL;
} }
break; break;
case ACL_TYPE_DEFAULT: case ACL_TYPE_DEFAULT:
@ -127,6 +125,11 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
goto out_free; goto out_free;
} }
if (ceph_snap(inode) != CEPH_NOSNAP) {
ret = -EROFS;
goto out_free;
}
if (new_mode != old_mode) { if (new_mode != old_mode) {
newattrs.ia_mode = new_mode; newattrs.ia_mode = new_mode;
newattrs.ia_valid = ATTR_MODE; newattrs.ia_valid = ATTR_MODE;

View File

@ -1905,13 +1905,6 @@ int __ceph_setattr(struct inode *inode, struct iattr *attr)
int inode_dirty_flags = 0; int inode_dirty_flags = 0;
bool lock_snap_rwsem = false; bool lock_snap_rwsem = false;
if (ceph_snap(inode) != CEPH_NOSNAP)
return -EROFS;
err = inode_change_ok(inode, attr);
if (err != 0)
return err;
prealloc_cf = ceph_alloc_cap_flush(); prealloc_cf = ceph_alloc_cap_flush();
if (!prealloc_cf) if (!prealloc_cf)
return -ENOMEM; return -ENOMEM;
@ -2124,7 +2117,17 @@ int __ceph_setattr(struct inode *inode, struct iattr *attr)
*/ */
int ceph_setattr(struct dentry *dentry, struct iattr *attr) int ceph_setattr(struct dentry *dentry, struct iattr *attr)
{ {
return __ceph_setattr(d_inode(dentry), attr); struct inode *inode = d_inode(dentry);
int err;
if (ceph_snap(inode) != CEPH_NOSNAP)
return -EROFS;
err = setattr_prepare(dentry, attr);
if (err != 0)
return err;
return __ceph_setattr(inode, attr);
} }
/* /*

View File

@ -2154,7 +2154,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
attrs->ia_valid |= ATTR_FORCE; attrs->ia_valid |= ATTR_FORCE;
rc = inode_change_ok(inode, attrs); rc = setattr_prepare(direntry, attrs);
if (rc < 0) if (rc < 0)
goto out; goto out;
@ -2294,7 +2294,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
attrs->ia_valid |= ATTR_FORCE; attrs->ia_valid |= ATTR_FORCE;
rc = inode_change_ok(inode, attrs); rc = setattr_prepare(direntry, attrs);
if (rc < 0) { if (rc < 0) {
free_xid(xid); free_xid(xid);
return rc; return rc;

View File

@ -927,7 +927,7 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
} }
mutex_unlock(&crypt_stat->cs_mutex); mutex_unlock(&crypt_stat->cs_mutex);
rc = inode_change_ok(inode, ia); rc = setattr_prepare(dentry, ia);
if (rc) if (rc)
goto out; goto out;
if (ia->ia_valid & ATTR_SIZE) { if (ia->ia_valid & ATTR_SIZE) {

View File

@ -1034,7 +1034,7 @@ int exofs_setattr(struct dentry *dentry, struct iattr *iattr)
if (unlikely(error)) if (unlikely(error))
return error; return error;
error = inode_change_ok(inode, iattr); error = setattr_prepare(dentry, iattr);
if (unlikely(error)) if (unlikely(error))
return error; return error;

View File

@ -190,15 +190,11 @@ ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) { if (acl) {
error = posix_acl_equiv_mode(acl, &inode->i_mode); error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
if (error < 0) if (error)
return error; return error;
else { inode->i_ctime = CURRENT_TIME_SEC;
inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode);
mark_inode_dirty(inode);
if (error == 0)
acl = NULL;
}
} }
break; break;

View File

@ -465,6 +465,11 @@ struct inode *ext2_new_inode(struct inode *dir, umode_t mode,
for (i = 0; i < sbi->s_groups_count; i++) { for (i = 0; i < sbi->s_groups_count; i++) {
gdp = ext2_get_group_desc(sb, group, &bh2); gdp = ext2_get_group_desc(sb, group, &bh2);
if (!gdp) {
if (++group == sbi->s_groups_count)
group = 0;
continue;
}
brelse(bitmap_bh); brelse(bitmap_bh);
bitmap_bh = read_inode_bitmap(sb, group); bitmap_bh = read_inode_bitmap(sb, group);
if (!bitmap_bh) { if (!bitmap_bh) {

View File

@ -1580,7 +1580,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
int error; int error;
error = inode_change_ok(inode, iattr); error = setattr_prepare(dentry, iattr);
if (error) if (error)
return error; return error;

View File

@ -193,15 +193,11 @@ __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) { if (acl) {
error = posix_acl_equiv_mode(acl, &inode->i_mode); error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
if (error < 0) if (error)
return error; return error;
else { inode->i_ctime = ext4_current_time(inode);
inode->i_ctime = ext4_current_time(inode); ext4_mark_inode_dirty(handle, inode);
ext4_mark_inode_dirty(handle, inode);
if (error == 0)
acl = NULL;
}
} }
break; break;

View File

@ -5073,7 +5073,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
int orphan = 0; int orphan = 0;
const unsigned int ia_valid = attr->ia_valid; const unsigned int ia_valid = attr->ia_valid;
error = inode_change_ok(inode, attr); error = setattr_prepare(dentry, attr);
if (error) if (error)
return error; return error;

View File

@ -210,12 +210,10 @@ static int __f2fs_set_acl(struct inode *inode, int type,
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) { if (acl) {
error = posix_acl_equiv_mode(acl, &inode->i_mode); error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
if (error < 0) if (error)
return error; return error;
set_acl_inode(inode, inode->i_mode); set_acl_inode(inode, inode->i_mode);
if (error == 0)
acl = NULL;
} }
break; break;

View File

@ -680,7 +680,7 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
int err; int err;
err = inode_change_ok(inode, attr); err = setattr_prepare(dentry, attr);
if (err) if (err)
return err; return err;

View File

@ -450,7 +450,7 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
attr->ia_valid &= ~TIMES_SET_FLAGS; attr->ia_valid &= ~TIMES_SET_FLAGS;
} }
error = inode_change_ok(inode, attr); error = setattr_prepare(dentry, attr);
attr->ia_valid = ia_valid; attr->ia_valid = ia_valid;
if (error) { if (error) {
if (sbi->options.quiet) if (sbi->options.quiet)

View File

@ -1591,9 +1591,10 @@ int fuse_flush_times(struct inode *inode, struct fuse_file *ff)
* vmtruncate() doesn't allow for this case, so do the rlimit checking * vmtruncate() doesn't allow for this case, so do the rlimit checking
* and the actual truncation by hand. * and the actual truncation by hand.
*/ */
int fuse_do_setattr(struct inode *inode, struct iattr *attr, int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
struct file *file) struct file *file)
{ {
struct inode *inode = d_inode(dentry);
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_inode *fi = get_fuse_inode(inode); struct fuse_inode *fi = get_fuse_inode(inode);
FUSE_ARGS(args); FUSE_ARGS(args);
@ -1608,7 +1609,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
attr->ia_valid |= ATTR_FORCE; attr->ia_valid |= ATTR_FORCE;
err = inode_change_ok(inode, attr); err = setattr_prepare(dentry, attr);
if (err) if (err)
return err; return err;
@ -1707,9 +1708,9 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
return -EACCES; return -EACCES;
if (attr->ia_valid & ATTR_FILE) if (attr->ia_valid & ATTR_FILE)
return fuse_do_setattr(inode, attr, attr->ia_file); return fuse_do_setattr(entry, attr, attr->ia_file);
else else
return fuse_do_setattr(inode, attr, NULL); return fuse_do_setattr(entry, attr, NULL);
} }
static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,

View File

@ -2842,7 +2842,7 @@ static void fuse_do_truncate(struct file *file)
attr.ia_file = file; attr.ia_file = file;
attr.ia_valid |= ATTR_FILE; attr.ia_valid |= ATTR_FILE;
fuse_do_setattr(inode, &attr, file); fuse_do_setattr(file_dentry(file), &attr, file);
} }
static inline loff_t fuse_round_up(loff_t off) static inline loff_t fuse_round_up(loff_t off)

View File

@ -958,7 +958,7 @@ bool fuse_write_update_size(struct inode *inode, loff_t pos);
int fuse_flush_times(struct inode *inode, struct fuse_file *ff); int fuse_flush_times(struct inode *inode, struct fuse_file *ff);
int fuse_write_inode(struct inode *inode, struct writeback_control *wbc); int fuse_write_inode(struct inode *inode, struct writeback_control *wbc);
int fuse_do_setattr(struct inode *inode, struct iattr *attr, int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
struct file *file); struct file *file);
void fuse_set_initialized(struct fuse_conn *fc); void fuse_set_initialized(struct fuse_conn *fc);

View File

@ -92,17 +92,11 @@ int __gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
if (type == ACL_TYPE_ACCESS) { if (type == ACL_TYPE_ACCESS) {
umode_t mode = inode->i_mode; umode_t mode = inode->i_mode;
error = posix_acl_equiv_mode(acl, &mode); error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
if (error < 0) if (error)
return error; return error;
if (mode != inode->i_mode)
if (error == 0)
acl = NULL;
if (mode != inode->i_mode) {
inode->i_mode = mode;
mark_inode_dirty(inode); mark_inode_dirty(inode);
}
} }
if (acl) { if (acl) {

View File

@ -1932,7 +1932,7 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
goto out; goto out;
error = inode_change_ok(inode, attr); error = setattr_prepare(dentry, attr);
if (error) if (error)
goto out; goto out;

View File

@ -605,7 +605,7 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr)
struct hfs_sb_info *hsb = HFS_SB(inode->i_sb); struct hfs_sb_info *hsb = HFS_SB(inode->i_sb);
int error; int error;
error = inode_change_ok(inode, attr); /* basic permission checks */ error = setattr_prepare(dentry, attr); /* basic permission checks */
if (error) if (error)
return error; return error;

View File

@ -245,7 +245,7 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
int error; int error;
error = inode_change_ok(inode, attr); error = setattr_prepare(dentry, attr);
if (error) if (error)
return error; return error;

View File

@ -65,8 +65,8 @@ int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
xattr_name = XATTR_NAME_POSIX_ACL_ACCESS; xattr_name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) { if (acl) {
err = posix_acl_equiv_mode(acl, &inode->i_mode); err = posix_acl_update_mode(inode, &inode->i_mode, &acl);
if (err < 0) if (err)
return err; return err;
} }
err = 0; err = 0;

View File

@ -812,7 +812,7 @@ static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
int fd = HOSTFS_I(inode)->fd; int fd = HOSTFS_I(inode)->fd;
err = inode_change_ok(inode, attr); err = setattr_prepare(dentry, attr);
if (err) if (err)
return err; return err;

View File

@ -273,7 +273,7 @@ int hpfs_setattr(struct dentry *dentry, struct iattr *attr)
if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size > inode->i_size) if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size > inode->i_size)
goto out_unlock; goto out_unlock;
error = inode_change_ok(inode, attr); error = setattr_prepare(dentry, attr);
if (error) if (error)
goto out_unlock; goto out_unlock;

View File

@ -672,7 +672,7 @@ static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr)
BUG_ON(!inode); BUG_ON(!inode);
error = inode_change_ok(inode, attr); error = setattr_prepare(dentry, attr);
if (error) if (error)
return error; return error;

View File

@ -233,9 +233,10 @@ int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
xprefix = JFFS2_XPREFIX_ACL_ACCESS; xprefix = JFFS2_XPREFIX_ACL_ACCESS;
if (acl) { if (acl) {
umode_t mode = inode->i_mode; umode_t mode;
rc = posix_acl_equiv_mode(acl, &mode);
if (rc < 0) rc = posix_acl_update_mode(inode, &mode, &acl);
if (rc)
return rc; return rc;
if (inode->i_mode != mode) { if (inode->i_mode != mode) {
struct iattr attr; struct iattr attr;
@ -247,8 +248,6 @@ int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
if (rc < 0) if (rc < 0)
return rc; return rc;
} }
if (rc == 0)
acl = NULL;
} }
break; break;
case ACL_TYPE_DEFAULT: case ACL_TYPE_DEFAULT:

View File

@ -193,7 +193,7 @@ int jffs2_setattr(struct dentry *dentry, struct iattr *iattr)
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
int rc; int rc;
rc = inode_change_ok(inode, iattr); rc = setattr_prepare(dentry, iattr);
if (rc) if (rc)
return rc; return rc;

View File

@ -78,13 +78,11 @@ static int __jfs_set_acl(tid_t tid, struct inode *inode, int type,
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
ea_name = XATTR_NAME_POSIX_ACL_ACCESS; ea_name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) { if (acl) {
rc = posix_acl_equiv_mode(acl, &inode->i_mode); rc = posix_acl_update_mode(inode, &inode->i_mode, &acl);
if (rc < 0) if (rc)
return rc; return rc;
inode->i_ctime = CURRENT_TIME; inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode); mark_inode_dirty(inode);
if (rc == 0)
acl = NULL;
} }
break; break;
case ACL_TYPE_DEFAULT: case ACL_TYPE_DEFAULT:

View File

@ -103,7 +103,7 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
int rc; int rc;
rc = inode_change_ok(inode, iattr); rc = setattr_prepare(dentry, iattr);
if (rc) if (rc)
return rc; return rc;

View File

@ -122,7 +122,7 @@ int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr)
return -EINVAL; return -EINVAL;
mutex_lock(&kernfs_mutex); mutex_lock(&kernfs_mutex);
error = inode_change_ok(inode, iattr); error = setattr_prepare(dentry, iattr);
if (error) if (error)
goto out; goto out;

View File

@ -394,7 +394,7 @@ int simple_setattr(struct dentry *dentry, struct iattr *iattr)
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
int error; int error;
error = inode_change_ok(inode, iattr); error = setattr_prepare(dentry, iattr);
if (error) if (error)
return error; return error;

View File

@ -244,7 +244,7 @@ static int logfs_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
int err = 0; int err = 0;
err = inode_change_ok(inode, attr); err = setattr_prepare(dentry, attr);
if (err) if (err)
return err; return err;

View File

@ -26,7 +26,7 @@ static int minix_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
int error; int error;
error = inode_change_ok(inode, attr); error = setattr_prepare(dentry, attr);
if (error) if (error)
return error; return error;

View File

@ -884,7 +884,7 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
/* ageing the dentry to force validation */ /* ageing the dentry to force validation */
ncp_age_dentry(server, dentry); ncp_age_dentry(server, dentry);
result = inode_change_ok(inode, attr); result = setattr_prepare(dentry, attr);
if (result < 0) if (result < 0)
goto out; goto out;

View File

@ -74,10 +74,10 @@ nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
* which only requires access, and "set-[ac]time-to-X" which * which only requires access, and "set-[ac]time-to-X" which
* requires ownership. * requires ownership.
* So if it looks like it might be "set both to the same time which * 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" * 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. * it is not an interface that we should be using.
*/ */
#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET) #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
@ -92,17 +92,15 @@ nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
* request is. We require it be within 30 minutes of now. * request is. We require it be within 30 minutes of now.
*/ */
time_t delta = iap->ia_atime.tv_sec - get_seconds(); time_t delta = iap->ia_atime.tv_sec - get_seconds();
struct inode *inode;
nfserr = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP); nfserr = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
if (nfserr) if (nfserr)
goto done; goto done;
inode = d_inode(fhp->fh_dentry);
if (delta < 0) if (delta < 0)
delta = -delta; delta = -delta;
if (delta < MAX_TOUCH_TIME_ERROR && if (delta < MAX_TOUCH_TIME_ERROR &&
inode_change_ok(inode, iap) != 0) { setattr_prepare(fhp->fh_dentry, iap) != 0) {
/* /*
* Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME. * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME.
* This will cause notify_change to set these times * This will cause notify_change to set these times

View File

@ -829,7 +829,7 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr)
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
int err; int err;
err = inode_change_ok(inode, iattr); err = setattr_prepare(dentry, iattr);
if (err) if (err)
return err; return err;

View File

@ -2893,7 +2893,7 @@ int ntfs_setattr(struct dentry *dentry, struct iattr *attr)
int err; int err;
unsigned int ia_valid = attr->ia_valid; unsigned int ia_valid = attr->ia_valid;
err = inode_change_ok(vi, attr); err = setattr_prepare(dentry, attr);
if (err) if (err)
goto out; goto out;
/* We do not support NTFS ACLs yet. */ /* We do not support NTFS ACLs yet. */

View File

@ -241,13 +241,11 @@ int ocfs2_set_acl(handle_t *handle,
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS; name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) { if (acl) {
umode_t mode = inode->i_mode; umode_t mode;
ret = posix_acl_equiv_mode(acl, &mode);
if (ret < 0)
return ret;
if (ret == 0) ret = posix_acl_update_mode(inode, &mode, &acl);
acl = NULL; if (ret)
return ret;
ret = ocfs2_acl_set_mode(inode, di_bh, ret = ocfs2_acl_set_mode(inode, di_bh,
handle, mode); handle, mode);

View File

@ -211,7 +211,7 @@ static int dlmfs_file_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
attr->ia_valid &= ~ATTR_SIZE; attr->ia_valid &= ~ATTR_SIZE;
error = inode_change_ok(inode, attr); error = setattr_prepare(dentry, attr);
if (error) if (error)
return error; return error;

View File

@ -1155,7 +1155,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
if (!(attr->ia_valid & OCFS2_VALID_ATTRS)) if (!(attr->ia_valid & OCFS2_VALID_ATTRS))
return 0; return 0;
status = inode_change_ok(inode, attr); status = setattr_prepare(dentry, attr);
if (status) if (status)
return status; return status;

View File

@ -349,7 +349,7 @@ static int omfs_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
int error; int error;
error = inode_change_ok(inode, attr); error = setattr_prepare(dentry, attr);
if (error) if (error)
return error; return error;

View File

@ -73,14 +73,11 @@ int orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS; name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) { if (acl) {
umode_t mode = inode->i_mode; umode_t mode;
/*
* can we represent this with the traditional file error = posix_acl_update_mode(inode, &mode, &acl);
* mode permission bits? if (error) {
*/ gossip_err("%s: posix_acl_update_mode err: %d\n",
error = posix_acl_equiv_mode(acl, &mode);
if (error < 0) {
gossip_err("%s: posix_acl_equiv_mode err: %d\n",
__func__, __func__,
error); error);
return error; return error;
@ -90,8 +87,6 @@ int orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
SetModeFlag(orangefs_inode); SetModeFlag(orangefs_inode);
inode->i_mode = mode; inode->i_mode = mode;
mark_inode_dirty_sync(inode); mark_inode_dirty_sync(inode);
if (error == 0)
acl = NULL;
} }
break; break;
case ACL_TYPE_DEFAULT: case ACL_TYPE_DEFAULT:

View File

@ -219,7 +219,7 @@ int orangefs_setattr(struct dentry *dentry, struct iattr *iattr)
"orangefs_setattr: called on %pd\n", "orangefs_setattr: called on %pd\n",
dentry); dentry);
ret = inode_change_ok(inode, iattr); ret = setattr_prepare(dentry, iattr);
if (ret) if (ret)
goto out; goto out;

View File

@ -53,7 +53,7 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
* inode_newsize_ok() will always check against MAX_LFS_FILESIZE and not * inode_newsize_ok() will always check against MAX_LFS_FILESIZE and not
* check for a swapfile (which this won't be anyway). * check for a swapfile (which this won't be anyway).
*/ */
err = inode_change_ok(dentry->d_inode, attr); err = setattr_prepare(dentry, attr);
if (err) if (err)
return err; return err;

View File

@ -627,6 +627,37 @@ posix_acl_create(struct inode *dir, umode_t *mode,
} }
EXPORT_SYMBOL_GPL(posix_acl_create); EXPORT_SYMBOL_GPL(posix_acl_create);
/**
* posix_acl_update_mode - update mode in set_acl
*
* Update the file mode when setting an ACL: compute the new file permission
* bits based on the ACL. In addition, if the ACL is equivalent to the new
* file mode, set *acl to NULL to indicate that no ACL should be set.
*
* As with chmod, clear the setgit bit if the caller is not in the owning group
* or capable of CAP_FSETID (see inode_change_ok).
*
* Called from set_acl inode operations.
*/
int posix_acl_update_mode(struct inode *inode, umode_t *mode_p,
struct posix_acl **acl)
{
umode_t mode = inode->i_mode;
int error;
error = posix_acl_equiv_mode(*acl, &mode);
if (error < 0)
return error;
if (error == 0)
*acl = NULL;
if (!in_group_p(inode->i_gid) &&
!capable_wrt_inode_uidgid(inode, CAP_FSETID))
mode &= ~S_ISGID;
*mode_p = mode;
return 0;
}
EXPORT_SYMBOL(posix_acl_update_mode);
/* /*
* Fix up the uids and gids in posix acl extended attributes in place. * Fix up the uids and gids in posix acl extended attributes in place.
*/ */

View File

@ -692,7 +692,7 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr)
if (attr->ia_valid & ATTR_MODE) if (attr->ia_valid & ATTR_MODE)
return -EPERM; return -EPERM;
error = inode_change_ok(inode, attr); error = setattr_prepare(dentry, attr);
if (error) if (error)
return error; return error;

View File

@ -105,7 +105,7 @@ static int proc_notify_change(struct dentry *dentry, struct iattr *iattr)
struct proc_dir_entry *de = PDE(inode); struct proc_dir_entry *de = PDE(inode);
int error; int error;
error = inode_change_ok(inode, iattr); error = setattr_prepare(dentry, iattr);
if (error) if (error)
return error; return error;

View File

@ -754,7 +754,7 @@ static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr)
if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
return -EPERM; return -EPERM;
error = inode_change_ok(inode, attr); error = setattr_prepare(dentry, attr);
if (error) if (error)
return error; return error;

View File

@ -341,6 +341,7 @@ static int quota_getstate(struct super_block *sb, struct fs_quota_stat *fqs)
struct qc_state state; struct qc_state state;
int ret; int ret;
memset(&state, 0, sizeof (struct qc_state));
ret = sb->s_qcop->get_state(sb, &state); ret = sb->s_qcop->get_state(sb, &state);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -365,17 +366,19 @@ static int quota_getstate(struct super_block *sb, struct fs_quota_stat *fqs)
fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit; fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit;
fqs->qs_bwarnlimit = state.s_state[type].spc_warnlimit; fqs->qs_bwarnlimit = state.s_state[type].spc_warnlimit;
fqs->qs_iwarnlimit = state.s_state[type].ino_warnlimit; fqs->qs_iwarnlimit = state.s_state[type].ino_warnlimit;
if (state.s_state[USRQUOTA].flags & QCI_ACCT_ENABLED) {
/* Inodes may be allocated even if inactive; copy out if present */
if (state.s_state[USRQUOTA].ino) {
fqs->qs_uquota.qfs_ino = state.s_state[USRQUOTA].ino; fqs->qs_uquota.qfs_ino = state.s_state[USRQUOTA].ino;
fqs->qs_uquota.qfs_nblks = state.s_state[USRQUOTA].blocks; fqs->qs_uquota.qfs_nblks = state.s_state[USRQUOTA].blocks;
fqs->qs_uquota.qfs_nextents = state.s_state[USRQUOTA].nextents; fqs->qs_uquota.qfs_nextents = state.s_state[USRQUOTA].nextents;
} }
if (state.s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED) { if (state.s_state[GRPQUOTA].ino) {
fqs->qs_gquota.qfs_ino = state.s_state[GRPQUOTA].ino; fqs->qs_gquota.qfs_ino = state.s_state[GRPQUOTA].ino;
fqs->qs_gquota.qfs_nblks = state.s_state[GRPQUOTA].blocks; fqs->qs_gquota.qfs_nblks = state.s_state[GRPQUOTA].blocks;
fqs->qs_gquota.qfs_nextents = state.s_state[GRPQUOTA].nextents; fqs->qs_gquota.qfs_nextents = state.s_state[GRPQUOTA].nextents;
} }
if (state.s_state[PRJQUOTA].flags & QCI_ACCT_ENABLED) { if (state.s_state[PRJQUOTA].ino) {
/* /*
* Q_XGETQSTAT doesn't have room for both group and project * Q_XGETQSTAT doesn't have room for both group and project
* quotas. So, allow the project quota values to be copied out * quotas. So, allow the project quota values to be copied out
@ -411,6 +414,7 @@ static int quota_getstatev(struct super_block *sb, struct fs_quota_statv *fqs)
struct qc_state state; struct qc_state state;
int ret; int ret;
memset(&state, 0, sizeof (struct qc_state));
ret = sb->s_qcop->get_state(sb, &state); ret = sb->s_qcop->get_state(sb, &state);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -435,17 +439,19 @@ static int quota_getstatev(struct super_block *sb, struct fs_quota_statv *fqs)
fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit; fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit;
fqs->qs_bwarnlimit = state.s_state[type].spc_warnlimit; fqs->qs_bwarnlimit = state.s_state[type].spc_warnlimit;
fqs->qs_iwarnlimit = state.s_state[type].ino_warnlimit; fqs->qs_iwarnlimit = state.s_state[type].ino_warnlimit;
if (state.s_state[USRQUOTA].flags & QCI_ACCT_ENABLED) {
/* Inodes may be allocated even if inactive; copy out if present */
if (state.s_state[USRQUOTA].ino) {
fqs->qs_uquota.qfs_ino = state.s_state[USRQUOTA].ino; fqs->qs_uquota.qfs_ino = state.s_state[USRQUOTA].ino;
fqs->qs_uquota.qfs_nblks = state.s_state[USRQUOTA].blocks; fqs->qs_uquota.qfs_nblks = state.s_state[USRQUOTA].blocks;
fqs->qs_uquota.qfs_nextents = state.s_state[USRQUOTA].nextents; fqs->qs_uquota.qfs_nextents = state.s_state[USRQUOTA].nextents;
} }
if (state.s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED) { if (state.s_state[GRPQUOTA].ino) {
fqs->qs_gquota.qfs_ino = state.s_state[GRPQUOTA].ino; fqs->qs_gquota.qfs_ino = state.s_state[GRPQUOTA].ino;
fqs->qs_gquota.qfs_nblks = state.s_state[GRPQUOTA].blocks; fqs->qs_gquota.qfs_nblks = state.s_state[GRPQUOTA].blocks;
fqs->qs_gquota.qfs_nextents = state.s_state[GRPQUOTA].nextents; fqs->qs_gquota.qfs_nextents = state.s_state[GRPQUOTA].nextents;
} }
if (state.s_state[PRJQUOTA].flags & QCI_ACCT_ENABLED) { if (state.s_state[PRJQUOTA].ino) {
fqs->qs_pquota.qfs_ino = state.s_state[PRJQUOTA].ino; fqs->qs_pquota.qfs_ino = state.s_state[PRJQUOTA].ino;
fqs->qs_pquota.qfs_nblks = state.s_state[PRJQUOTA].blocks; fqs->qs_pquota.qfs_nblks = state.s_state[PRJQUOTA].blocks;
fqs->qs_pquota.qfs_nextents = state.s_state[PRJQUOTA].nextents; fqs->qs_pquota.qfs_nextents = state.s_state[PRJQUOTA].nextents;

View File

@ -169,7 +169,7 @@ static int ramfs_nommu_setattr(struct dentry *dentry, struct iattr *ia)
int ret = 0; int ret = 0;
/* POSIX UID/GID verification for setting inode attributes */ /* POSIX UID/GID verification for setting inode attributes */
ret = inode_change_ok(inode, ia); ret = setattr_prepare(dentry, ia);
if (ret) if (ret)
return ret; return ret;

View File

@ -3312,7 +3312,7 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
unsigned int ia_valid; unsigned int ia_valid;
int error; int error;
error = inode_change_ok(inode, attr); error = setattr_prepare(dentry, attr);
if (error) if (error)
return error; return error;

View File

@ -190,7 +190,15 @@ static int remove_save_link_only(struct super_block *s,
static int reiserfs_quota_on_mount(struct super_block *, int); static int reiserfs_quota_on_mount(struct super_block *, int);
#endif #endif
/* look for uncompleted unlinks and truncates and complete them */ /*
* Look for uncompleted unlinks and truncates and complete them
*
* Called with superblock write locked. If quotas are enabled, we have to
* release/retake lest we call dquot_quota_on_mount(), proceed to
* schedule_on_each_cpu() in invalidate_bdev() and deadlock waiting for the per
* cpu worklets to complete flush_async_commits() that in turn wait for the
* superblock write lock.
*/
static int finish_unfinished(struct super_block *s) static int finish_unfinished(struct super_block *s)
{ {
INITIALIZE_PATH(path); INITIALIZE_PATH(path);
@ -237,7 +245,9 @@ static int finish_unfinished(struct super_block *s)
quota_enabled[i] = 0; quota_enabled[i] = 0;
continue; continue;
} }
reiserfs_write_unlock(s);
ret = reiserfs_quota_on_mount(s, i); ret = reiserfs_quota_on_mount(s, i);
reiserfs_write_lock(s);
if (ret < 0) if (ret < 0)
reiserfs_warning(s, "reiserfs-2500", reiserfs_warning(s, "reiserfs-2500",
"cannot turn on journaled " "cannot turn on journaled "

View File

@ -242,13 +242,9 @@ __reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS; name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) { if (acl) {
error = posix_acl_equiv_mode(acl, &inode->i_mode); error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
if (error < 0) if (error)
return error; return error;
else {
if (error == 0)
acl = NULL;
}
} }
break; break;
case ACL_TYPE_DEFAULT: case ACL_TYPE_DEFAULT:

View File

@ -33,7 +33,7 @@ static int sysv_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
int error; int error;
error = inode_change_ok(inode, attr); error = setattr_prepare(dentry, attr);
if (error) if (error)
return error; return error;

View File

@ -1262,7 +1262,7 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr)
dbg_gen("ino %lu, mode %#x, ia_valid %#x", dbg_gen("ino %lu, mode %#x, ia_valid %#x",
inode->i_ino, inode->i_mode, attr->ia_valid); inode->i_ino, inode->i_mode, attr->ia_valid);
err = inode_change_ok(inode, attr); err = setattr_prepare(dentry, attr);
if (err) if (err)
return err; return err;

View File

@ -94,7 +94,7 @@ static int udf_adinicb_write_begin(struct file *file,
return -ENOMEM; return -ENOMEM;
*pagep = page; *pagep = page;
if (!PageUptodate(page) && len != PAGE_SIZE) if (!PageUptodate(page))
__udf_adinicb_readpage(page); __udf_adinicb_readpage(page);
return 0; return 0;
} }
@ -105,11 +105,25 @@ static ssize_t udf_adinicb_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
return 0; return 0;
} }
static int udf_adinicb_write_end(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned copied,
struct page *page, void *fsdata)
{
struct inode *inode = page->mapping->host;
loff_t last_pos = pos + copied;
if (last_pos > inode->i_size)
i_size_write(inode, last_pos);
set_page_dirty(page);
unlock_page(page);
put_page(page);
return copied;
}
const struct address_space_operations udf_adinicb_aops = { const struct address_space_operations udf_adinicb_aops = {
.readpage = udf_adinicb_readpage, .readpage = udf_adinicb_readpage,
.writepage = udf_adinicb_writepage, .writepage = udf_adinicb_writepage,
.write_begin = udf_adinicb_write_begin, .write_begin = udf_adinicb_write_begin,
.write_end = simple_write_end, .write_end = udf_adinicb_write_end,
.direct_IO = udf_adinicb_direct_IO, .direct_IO = udf_adinicb_direct_IO,
}; };
@ -247,7 +261,7 @@ static int udf_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
int error; int error;
error = inode_change_ok(inode, attr); error = setattr_prepare(dentry, attr);
if (error) if (error)
return error; return error;

View File

@ -1208,7 +1208,7 @@ int ufs_setattr(struct dentry *dentry, struct iattr *attr)
unsigned int ia_valid = attr->ia_valid; unsigned int ia_valid = attr->ia_valid;
int error; int error;
error = inode_change_ok(inode, attr); error = setattr_prepare(dentry, attr);
if (error) if (error)
return error; return error;

View File

@ -81,7 +81,7 @@ static int utimes_common(struct path *path, struct timespec *times)
newattrs.ia_valid |= ATTR_MTIME_SET; 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 * update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET
* were used. * were used.
*/ */

View File

@ -257,16 +257,11 @@ xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
return error; return error;
if (type == ACL_TYPE_ACCESS) { if (type == ACL_TYPE_ACCESS) {
umode_t mode = inode->i_mode; umode_t mode;
error = posix_acl_equiv_mode(acl, &mode);
if (error <= 0) {
acl = NULL;
if (error < 0)
return error;
}
error = posix_acl_update_mode(inode, &mode, &acl);
if (error)
return error;
error = xfs_set_mode(inode, mode); error = xfs_set_mode(inode, mode);
if (error) if (error)
return error; return error;

View File

@ -984,7 +984,7 @@ xfs_file_fallocate(
iattr.ia_valid = ATTR_SIZE; iattr.ia_valid = ATTR_SIZE;
iattr.ia_size = new_size; iattr.ia_size = new_size;
error = xfs_setattr_size(ip, &iattr); error = xfs_vn_setattr_size(file_dentry(file), &iattr);
if (error) if (error)
goto out_unlock; goto out_unlock;
} }

View File

@ -1710,7 +1710,7 @@ xfs_inactive_truncate(
/* /*
* Log the inode size first to prevent stale data exposure in the event * Log the inode size first to prevent stale data exposure in the event
* of a system crash before the truncate completes. See the related * of a system crash before the truncate completes. See the related
* comment in xfs_setattr_size() for details. * comment in xfs_vn_setattr_size() for details.
*/ */
ip->i_d.di_size = 0; ip->i_d.di_size = 0;
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);

View File

@ -720,7 +720,7 @@ xfs_ioc_space(
iattr.ia_valid = ATTR_SIZE; iattr.ia_valid = ATTR_SIZE;
iattr.ia_size = bf->l_start; iattr.ia_size = bf->l_start;
error = xfs_setattr_size(ip, &iattr); error = xfs_vn_setattr_size(file_dentry(filp), &iattr);
break; break;
default: default:
ASSERT(0); ASSERT(0);

View File

@ -542,6 +542,28 @@ xfs_setattr_time(
inode->i_mtime = iattr->ia_mtime; inode->i_mtime = iattr->ia_mtime;
} }
static int
xfs_vn_change_ok(
struct dentry *dentry,
struct iattr *iattr)
{
struct xfs_mount *mp = XFS_I(d_inode(dentry))->i_mount;
if (mp->m_flags & XFS_MOUNT_RDONLY)
return -EROFS;
if (XFS_FORCED_SHUTDOWN(mp))
return -EIO;
return setattr_prepare(dentry, iattr);
}
/*
* Set non-size attributes of an inode.
*
* Caution: The caller of this function is responsible for calling
* setattr_prepare() or otherwise verifying the change is fine.
*/
int int
xfs_setattr_nonsize( xfs_setattr_nonsize(
struct xfs_inode *ip, struct xfs_inode *ip,
@ -558,21 +580,6 @@ xfs_setattr_nonsize(
struct xfs_dquot *udqp = NULL, *gdqp = NULL; struct xfs_dquot *udqp = NULL, *gdqp = NULL;
struct xfs_dquot *olddquot1 = NULL, *olddquot2 = NULL; struct xfs_dquot *olddquot1 = NULL, *olddquot2 = NULL;
trace_xfs_setattr(ip);
/* If acls are being inherited, we already have this checked */
if (!(flags & XFS_ATTR_NOACL)) {
if (mp->m_flags & XFS_MOUNT_RDONLY)
return -EROFS;
if (XFS_FORCED_SHUTDOWN(mp))
return -EIO;
error = inode_change_ok(inode, iattr);
if (error)
return error;
}
ASSERT((mask & ATTR_SIZE) == 0); ASSERT((mask & ATTR_SIZE) == 0);
/* /*
@ -743,8 +750,27 @@ xfs_setattr_nonsize(
return error; return error;
} }
int
xfs_vn_setattr_nonsize(
struct dentry *dentry,
struct iattr *iattr)
{
struct xfs_inode *ip = XFS_I(d_inode(dentry));
int error;
trace_xfs_setattr(ip);
error = xfs_vn_change_ok(dentry, iattr);
if (error)
return error;
return xfs_setattr_nonsize(ip, iattr, 0);
}
/* /*
* Truncate file. Must have write permission and not be a directory. * Truncate file. Must have write permission and not be a directory.
*
* Caution: The caller of this function is responsible for calling
* setattr_prepare() or otherwise verifying the change is fine.
*/ */
int int
xfs_setattr_size( xfs_setattr_size(
@ -759,18 +785,6 @@ xfs_setattr_size(
uint lock_flags = 0; uint lock_flags = 0;
bool did_zeroing = false; bool did_zeroing = false;
trace_xfs_setattr(ip);
if (mp->m_flags & XFS_MOUNT_RDONLY)
return -EROFS;
if (XFS_FORCED_SHUTDOWN(mp))
return -EIO;
error = inode_change_ok(inode, iattr);
if (error)
return error;
ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
ASSERT(xfs_isilocked(ip, XFS_MMAPLOCK_EXCL)); ASSERT(xfs_isilocked(ip, XFS_MMAPLOCK_EXCL));
ASSERT(S_ISREG(inode->i_mode)); ASSERT(S_ISREG(inode->i_mode));
@ -942,16 +956,32 @@ xfs_setattr_size(
goto out_unlock; goto out_unlock;
} }
int
xfs_vn_setattr_size(
struct dentry *dentry,
struct iattr *iattr)
{
struct xfs_inode *ip = XFS_I(d_inode(dentry));
int error;
trace_xfs_setattr(ip);
error = xfs_vn_change_ok(dentry, iattr);
if (error)
return error;
return xfs_setattr_size(ip, iattr);
}
STATIC int STATIC int
xfs_vn_setattr( xfs_vn_setattr(
struct dentry *dentry, struct dentry *dentry,
struct iattr *iattr) struct iattr *iattr)
{ {
struct xfs_inode *ip = XFS_I(d_inode(dentry));
int error; int error;
if (iattr->ia_valid & ATTR_SIZE) { if (iattr->ia_valid & ATTR_SIZE) {
uint iolock = XFS_IOLOCK_EXCL; struct xfs_inode *ip = XFS_I(d_inode(dentry));
uint iolock = XFS_IOLOCK_EXCL;
xfs_ilock(ip, iolock); xfs_ilock(ip, iolock);
error = xfs_break_layouts(d_inode(dentry), &iolock, true); error = xfs_break_layouts(d_inode(dentry), &iolock, true);
@ -959,11 +989,11 @@ xfs_vn_setattr(
xfs_ilock(ip, XFS_MMAPLOCK_EXCL); xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
iolock |= XFS_MMAPLOCK_EXCL; iolock |= XFS_MMAPLOCK_EXCL;
error = xfs_setattr_size(ip, iattr); error = xfs_vn_setattr_size(dentry, iattr);
} }
xfs_iunlock(ip, iolock); xfs_iunlock(ip, iolock);
} else { } else {
error = xfs_setattr_nonsize(ip, iattr, 0); error = xfs_vn_setattr_nonsize(dentry, iattr);
} }
return error; return error;

View File

@ -33,6 +33,7 @@ extern ssize_t xfs_vn_listxattr(struct dentry *, char *data, size_t size);
extern void xfs_setattr_time(struct xfs_inode *ip, struct iattr *iattr); extern void xfs_setattr_time(struct xfs_inode *ip, struct iattr *iattr);
extern int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap, extern int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap,
int flags); int flags);
extern int xfs_setattr_size(struct xfs_inode *ip, struct iattr *vap); extern int xfs_vn_setattr_nonsize(struct dentry *dentry, struct iattr *vap);
extern int xfs_vn_setattr_size(struct dentry *dentry, struct iattr *vap);
#endif /* __XFS_IOPS_H__ */ #endif /* __XFS_IOPS_H__ */

View File

@ -3007,7 +3007,7 @@ extern int buffer_migrate_page(struct address_space *,
#define buffer_migrate_page NULL #define buffer_migrate_page NULL
#endif #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 int inode_newsize_ok(const struct inode *, loff_t offset);
extern void setattr_copy(struct inode *inode, const struct iattr *attr); extern void setattr_copy(struct inode *inode, const struct iattr *attr);

View File

@ -73,6 +73,7 @@ extern int set_posix_acl(struct inode *, int, struct posix_acl *);
extern int posix_acl_chmod(struct inode *, umode_t); extern int posix_acl_chmod(struct inode *, umode_t);
extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **, extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **,
struct posix_acl **); struct posix_acl **);
extern int posix_acl_update_mode(struct inode *, umode_t *, struct posix_acl **);
extern int simple_set_acl(struct inode *, struct posix_acl *, int); extern int simple_set_acl(struct inode *, struct posix_acl *, int);
extern int simple_acl_create(struct inode *, struct inode *); extern int simple_acl_create(struct inode *, struct inode *);

View File

@ -960,7 +960,7 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr)
struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
int error; int error;
error = inode_change_ok(inode, attr); error = setattr_prepare(dentry, attr);
if (error) if (error)
return error; return error;