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]
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 ((!uid_eq(current_fsuid(), inode->i_uid)) &&
!capable(CFS_CAP_FOWNER))
switch (handler->flags) {
case ACL_TYPE_ACCESS:
if (acl) {
- umode_t mode = inode->i_mode;
- retval = posix_acl_equiv_mode(acl, &mode);
- if (retval < 0)
+ struct iattr iattr;
+
+ retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
+ if (retval)
goto err_out;
- else {
- struct iattr iattr;
- if (retval == 0) {
- /*
- * ACL can be represented
- * 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 ?
+ if (!acl) {
+ /*
+ * ACL can be represented
+ * by the mode bits. So don't
+ * update ACL.
*/
- 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;
case ACL_TYPE_DEFAULT:
struct p9_wstat wstat;
p9_debug(P9_DEBUG_VFS, "\n");
- retval = inode_change_ok(d_inode(dentry), iattr);
+ retval = setattr_prepare(dentry, iattr);
if (retval)
return retval;
p9_debug(P9_DEBUG_VFS, "\n");
- retval = inode_change_ok(inode, iattr);
+ retval = setattr_prepare(dentry, iattr);
if (retval)
return retval;
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 -
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)
goto out;
#include <linux/ima.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 = d_inode(dentry);
unsigned int ia_valid = attr->ia_valid;
/*
/* If force is set do it anyway. */
if (ia_valid & ATTR_FORCE)
- return 0;
+ goto kill_priv;
/* Make sure a caller can chown. */
if ((ia_valid & ATTR_UID) &&
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;
}
-EXPORT_SYMBOL(inode_change_ok);
+EXPORT_SYMBOL(setattr_prepare);
/**
* inode_newsize_ok - may this inode be truncated to a given size
if (!(ia_valid & ATTR_MTIME_SET))
attr->ia_mtime = now;
if (ia_valid & ATTR_KILL_PRIV) {
- attr->ia_valid &= ~ATTR_KILL_PRIV;
- ia_valid &= ~ATTR_KILL_PRIV;
error = security_inode_need_killpriv(dentry);
- if (error > 0)
- error = security_inode_killpriv(dentry);
- if (error)
+ if (error < 0)
return error;
+ if (error == 0)
+ ia_valid = attr->ia_valid &= ~ATTR_KILL_PRIV;
}
/*
case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
- ret = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (ret < 0)
+ ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (ret)
return ret;
- if (ret == 0)
- acl = NULL;
}
ret = 0;
break;
if (btrfs_root_readonly(root))
return -EROFS;
- err = inode_change_ok(inode, attr);
+ err = setattr_prepare(dentry, attr);
if (err)
return err;
case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
- ret = posix_acl_equiv_mode(acl, &new_mode);
- if (ret < 0)
+ ret = posix_acl_update_mode(inode, &new_mode, &acl);
+ if (ret)
goto out;
- if (ret == 0)
- acl = NULL;
}
break;
case ACL_TYPE_DEFAULT:
goto out_free;
}
+ if (ceph_snap(inode) != CEPH_NOSNAP) {
+ ret = -EROFS;
+ goto out_free;
+ }
+
if (new_mode != old_mode) {
newattrs.ia_mode = new_mode;
newattrs.ia_valid = ATTR_MODE;
int inode_dirty_flags = 0;
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();
if (!prealloc_cf)
return -ENOMEM;
*/
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);
}
/*
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;
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) {
free_xid(xid);
return rc;
}
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) {
if (unlikely(error))
return error;
- error = inode_change_ok(inode, iattr);
+ error = setattr_prepare(dentry, iattr);
if (unlikely(error))
return error;
case ACL_TYPE_ACCESS:
name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) {
- error = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (error < 0)
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (error)
return error;
- else {
- inode->i_ctime = CURRENT_TIME_SEC;
- mark_inode_dirty(inode);
- if (error == 0)
- acl = NULL;
- }
+ inode->i_ctime = CURRENT_TIME_SEC;
+ mark_inode_dirty(inode);
}
break;
for (i = 0; i < sbi->s_groups_count; i++) {
gdp = ext2_get_group_desc(sb, group, &bh2);
+ if (!gdp) {
+ if (++group == sbi->s_groups_count)
+ group = 0;
+ continue;
+ }
brelse(bitmap_bh);
bitmap_bh = read_inode_bitmap(sb, group);
if (!bitmap_bh) {
struct inode *inode = d_inode(dentry);
int error;
- error = inode_change_ok(inode, iattr);
+ error = setattr_prepare(dentry, iattr);
if (error)
return error;
case ACL_TYPE_ACCESS:
name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) {
- error = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (error < 0)
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (error)
return error;
- else {
- inode->i_ctime = ext4_current_time(inode);
- ext4_mark_inode_dirty(handle, inode);
- if (error == 0)
- acl = NULL;
- }
+ inode->i_ctime = ext4_current_time(inode);
+ ext4_mark_inode_dirty(handle, inode);
}
break;
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;
case ACL_TYPE_ACCESS:
name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) {
- error = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (error < 0)
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (error)
return error;
set_acl_inode(inode, inode->i_mode);
- if (error == 0)
- acl = NULL;
}
break;
struct inode *inode = d_inode(dentry);
int err;
- err = inode_change_ok(inode, attr);
+ err = setattr_prepare(dentry, attr);
if (err)
return err;
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)
* vmtruncate() doesn't allow for this case, so do the rlimit checking
* 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 inode *inode = d_inode(dentry);
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_inode *fi = get_fuse_inode(inode);
FUSE_ARGS(args);
if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
attr->ia_valid |= ATTR_FORCE;
- err = inode_change_ok(inode, attr);
+ err = setattr_prepare(dentry, attr);
if (err)
return err;
return -EACCES;
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
- return fuse_do_setattr(inode, attr, NULL);
+ return fuse_do_setattr(entry, attr, NULL);
}
static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
attr.ia_file = 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)
int fuse_flush_times(struct inode *inode, struct fuse_file *ff);
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);
void fuse_set_initialized(struct fuse_conn *fc);
if (type == ACL_TYPE_ACCESS) {
umode_t mode = inode->i_mode;
- error = posix_acl_equiv_mode(acl, &mode);
- if (error < 0)
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (error)
return error;
-
- if (error == 0)
- acl = NULL;
-
- if (mode != inode->i_mode) {
- inode->i_mode = mode;
+ if (mode != inode->i_mode)
mark_inode_dirty(inode);
- }
}
if (acl) {
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
goto out;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
goto out;
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;
struct inode *inode = d_inode(dentry);
int error;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
case ACL_TYPE_ACCESS:
xattr_name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
- err = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (err < 0)
+ err = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (err)
return err;
}
err = 0;
int fd = HOSTFS_I(inode)->fd;
- err = inode_change_ok(inode, attr);
+ err = setattr_prepare(dentry, attr);
if (err)
return err;
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;
BUG_ON(!inode);
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
case ACL_TYPE_ACCESS:
xprefix = JFFS2_XPREFIX_ACL_ACCESS;
if (acl) {
- umode_t mode = inode->i_mode;
- rc = posix_acl_equiv_mode(acl, &mode);
- if (rc < 0)
+ umode_t mode;
+
+ rc = posix_acl_update_mode(inode, &mode, &acl);
+ if (rc)
return rc;
if (inode->i_mode != mode) {
struct iattr attr;
if (rc < 0)
return rc;
}
- if (rc == 0)
- acl = NULL;
}
break;
case ACL_TYPE_DEFAULT:
struct inode *inode = d_inode(dentry);
int rc;
- rc = inode_change_ok(inode, iattr);
+ rc = setattr_prepare(dentry, iattr);
if (rc)
return rc;
case ACL_TYPE_ACCESS:
ea_name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
- rc = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (rc < 0)
+ rc = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (rc)
return rc;
inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
- if (rc == 0)
- acl = NULL;
}
break;
case ACL_TYPE_DEFAULT:
struct inode *inode = d_inode(dentry);
int rc;
- rc = inode_change_ok(inode, iattr);
+ rc = setattr_prepare(dentry, iattr);
if (rc)
return rc;
return -EINVAL;
mutex_lock(&kernfs_mutex);
- error = inode_change_ok(inode, iattr);
+ error = setattr_prepare(dentry, iattr);
if (error)
goto out;
struct inode *inode = d_inode(dentry);
int error;
- error = inode_change_ok(inode, iattr);
+ error = setattr_prepare(dentry, iattr);
if (error)
return error;
struct inode *inode = d_inode(dentry);
int err = 0;
- err = inode_change_ok(inode, attr);
+ err = setattr_prepare(dentry, attr);
if (err)
return err;
struct inode *inode = d_inode(dentry);
int error;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
/* 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;
* 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)
* request is. We require it be within 30 minutes of now.
*/
time_t delta = iap->ia_atime.tv_sec - get_seconds();
- struct inode *inode;
nfserr = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
if (nfserr)
goto done;
- inode = d_inode(fhp->fh_dentry);
if (delta < 0)
delta = -delta;
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.
* This will cause notify_change to set these times
struct super_block *sb = inode->i_sb;
int err;
- err = inode_change_ok(inode, iattr);
+ err = setattr_prepare(dentry, iattr);
if (err)
return err;
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. */
case ACL_TYPE_ACCESS:
name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) {
- umode_t mode = inode->i_mode;
- ret = posix_acl_equiv_mode(acl, &mode);
- if (ret < 0)
- return ret;
+ umode_t mode;
- if (ret == 0)
- acl = NULL;
+ ret = posix_acl_update_mode(inode, &mode, &acl);
+ if (ret)
+ return ret;
ret = ocfs2_acl_set_mode(inode, di_bh,
handle, mode);
struct inode *inode = d_inode(dentry);
attr->ia_valid &= ~ATTR_SIZE;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
if (!(attr->ia_valid & OCFS2_VALID_ATTRS))
return 0;
- status = inode_change_ok(inode, attr);
+ status = setattr_prepare(dentry, attr);
if (status)
return status;
struct inode *inode = d_inode(dentry);
int error;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
- umode_t mode = inode->i_mode;
- /*
- * can we represent this with the traditional file
- * mode permission bits?
- */
- error = posix_acl_equiv_mode(acl, &mode);
- if (error < 0) {
- gossip_err("%s: posix_acl_equiv_mode err: %d\n",
+ umode_t mode;
+
+ error = posix_acl_update_mode(inode, &mode, &acl);
+ if (error) {
+ gossip_err("%s: posix_acl_update_mode err: %d\n",
__func__,
error);
return error;
SetModeFlag(orangefs_inode);
inode->i_mode = mode;
mark_inode_dirty_sync(inode);
- if (error == 0)
- acl = NULL;
}
break;
case ACL_TYPE_DEFAULT:
"orangefs_setattr: called on %pd\n",
dentry);
- ret = inode_change_ok(inode, iattr);
+ ret = setattr_prepare(dentry, iattr);
if (ret)
goto out;
* inode_newsize_ok() will always check against MAX_LFS_FILESIZE and not
* 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)
return err;
}
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.
*/
if (attr->ia_valid & ATTR_MODE)
return -EPERM;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
struct proc_dir_entry *de = PDE(inode);
int error;
- error = inode_change_ok(inode, iattr);
+ error = setattr_prepare(dentry, iattr);
if (error)
return error;
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;
struct qc_state state;
int ret;
+ memset(&state, 0, sizeof (struct qc_state));
ret = sb->s_qcop->get_state(sb, &state);
if (ret < 0)
return ret;
fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit;
fqs->qs_bwarnlimit = state.s_state[type].spc_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_nblks = state.s_state[USRQUOTA].blocks;
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_nblks = state.s_state[GRPQUOTA].blocks;
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
* quotas. So, allow the project quota values to be copied out
struct qc_state state;
int ret;
+ memset(&state, 0, sizeof (struct qc_state));
ret = sb->s_qcop->get_state(sb, &state);
if (ret < 0)
return ret;
fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit;
fqs->qs_bwarnlimit = state.s_state[type].spc_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_nblks = state.s_state[USRQUOTA].blocks;
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_nblks = state.s_state[GRPQUOTA].blocks;
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_nblks = state.s_state[PRJQUOTA].blocks;
fqs->qs_pquota.qfs_nextents = state.s_state[PRJQUOTA].nextents;
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;
unsigned int ia_valid;
int error;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
static int reiserfs_quota_on_mount(struct super_block *, int);
#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)
{
INITIALIZE_PATH(path);
quota_enabled[i] = 0;
continue;
}
+ reiserfs_write_unlock(s);
ret = reiserfs_quota_on_mount(s, i);
+ reiserfs_write_lock(s);
if (ret < 0)
reiserfs_warning(s, "reiserfs-2500",
"cannot turn on journaled "
case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
- error = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (error < 0)
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+ if (error)
return error;
- else {
- if (error == 0)
- acl = NULL;
- }
}
break;
case ACL_TYPE_DEFAULT:
struct inode *inode = d_inode(dentry);
int error;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
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;
return -ENOMEM;
*pagep = page;
- if (!PageUptodate(page) && len != PAGE_SIZE)
+ if (!PageUptodate(page))
__udf_adinicb_readpage(page);
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 = {
.readpage = udf_adinicb_readpage,
.writepage = udf_adinicb_writepage,
.write_begin = udf_adinicb_write_begin,
- .write_end = simple_write_end,
+ .write_end = udf_adinicb_write_end,
.direct_IO = udf_adinicb_direct_IO,
};
struct inode *inode = d_inode(dentry);
int error;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
unsigned int ia_valid = attr->ia_valid;
int error;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;
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.
*/
return error;
if (type == ACL_TYPE_ACCESS) {
- umode_t mode = inode->i_mode;
- error = posix_acl_equiv_mode(acl, &mode);
-
- if (error <= 0) {
- acl = NULL;
-
- if (error < 0)
- return error;
- }
+ umode_t mode;
+ error = posix_acl_update_mode(inode, &mode, &acl);
+ if (error)
+ return error;
error = xfs_set_mode(inode, mode);
if (error)
return error;
iattr.ia_valid = ATTR_SIZE;
iattr.ia_size = new_size;
- error = xfs_setattr_size(ip, &iattr);
+ error = xfs_vn_setattr_size(file_dentry(file), &iattr);
if (error)
goto out_unlock;
}
/*
* Log the inode size first to prevent stale data exposure in the event
* 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;
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
iattr.ia_valid = ATTR_SIZE;
iattr.ia_size = bf->l_start;
- error = xfs_setattr_size(ip, &iattr);
+ error = xfs_vn_setattr_size(file_dentry(filp), &iattr);
break;
default:
ASSERT(0);
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
xfs_setattr_nonsize(
struct xfs_inode *ip,
struct xfs_dquot *udqp = NULL, *gdqp = 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);
/*
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.
+ *
+ * Caution: The caller of this function is responsible for calling
+ * setattr_prepare() or otherwise verifying the change is fine.
*/
int
xfs_setattr_size(
uint lock_flags = 0;
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_MMAPLOCK_EXCL));
ASSERT(S_ISREG(inode->i_mode));
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
xfs_vn_setattr(
struct dentry *dentry,
struct iattr *iattr)
{
- struct xfs_inode *ip = XFS_I(d_inode(dentry));
int error;
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);
error = xfs_break_layouts(d_inode(dentry), &iolock, true);
xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
iolock |= XFS_MMAPLOCK_EXCL;
- error = xfs_setattr_size(ip, iattr);
+ error = xfs_vn_setattr_size(dentry, iattr);
}
xfs_iunlock(ip, iolock);
} else {
- error = xfs_setattr_nonsize(ip, iattr, 0);
+ error = xfs_vn_setattr_nonsize(dentry, iattr);
}
return error;
extern void xfs_setattr_time(struct xfs_inode *ip, struct iattr *iattr);
extern int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap,
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__ */
#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);
extern int posix_acl_chmod(struct inode *, umode_t);
extern int posix_acl_create(struct inode *, umode_t *, 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_acl_create(struct inode *, struct inode *);
struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
int error;
- error = inode_change_ok(inode, attr);
+ error = setattr_prepare(dentry, attr);
if (error)
return error;