STATIC int xfs_qm_log_quotaoff_end( xfs_mount_t *mp, xfs_qoff_logitem_t *startqoff, uint flags) { xfs_trans_t *tp; int error; xfs_qoff_logitem_t *qoffi; tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF_END); if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_qoff_logitem_t) * 2, 0, 0, XFS_DEFAULT_LOG_COUNT))) { xfs_trans_cancel(tp, 0); return (error); } qoffi = xfs_trans_get_qoff_item(tp, startqoff, flags & XFS_ALL_QUOTA_ACCT); xfs_trans_log_quotaoff_item(tp, qoffi); xfs_trans_set_sync(tp); error = xfs_trans_commit(tp, 0); return (error); }
/* * Clear the inode reflink flag if there are no shared extents and the size * hasn't changed. */ STATIC int xfs_reflink_try_clear_inode_flag( struct xfs_inode *ip) { struct xfs_mount *mp = ip->i_mount; struct xfs_trans *tp; int error = 0; /* Start a rolling transaction to remove the mappings */ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, 0, 0, 0, &tp); if (error) return error; xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, 0); error = xfs_reflink_clear_inode_flag(ip, &tp); if (error) goto cancel; error = xfs_trans_commit(tp); if (error) goto out; xfs_iunlock(ip, XFS_ILOCK_EXCL); return 0; cancel: xfs_trans_cancel(tp); out: xfs_iunlock(ip, XFS_ILOCK_EXCL); return error; }
int xfs_log_dirty_inode( struct xfs_inode *ip, struct xfs_perag *pag, int flags) { struct xfs_mount *mp = ip->i_mount; struct xfs_trans *tp; int error; if (!ip->i_update_core) return 0; tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS); error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0); if (error) { xfs_trans_cancel(tp, 0); return error; } xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); return xfs_trans_commit(tp, 0); }
/* * Update on-disk file size now that data has been written to disk. */ STATIC int xfs_setfilesize( struct xfs_ioend *ioend) { struct xfs_inode *ip = XFS_I(ioend->io_inode); struct xfs_trans *tp = ioend->io_append_trans; xfs_fsize_t isize; /* * The transaction was allocated in the I/O submission thread, * thus we need to mark ourselves as beeing in a transaction * manually. */ current_set_flags_nested(&tp->t_pflags, PF_FSTRANS); xfs_ilock(ip, XFS_ILOCK_EXCL); isize = xfs_new_eof(ip, ioend->io_offset + ioend->io_size); if (!isize) { xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_trans_cancel(tp, 0); return 0; } trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size); ip->i_d.di_size = isize; xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); return xfs_trans_commit(tp, 0); }
/* * Update on-disk file size now that data has been written to disk. */ STATIC int xfs_setfilesize( struct xfs_inode *ip, struct xfs_trans *tp, xfs_off_t offset, size_t size) { xfs_fsize_t isize; xfs_ilock(ip, XFS_ILOCK_EXCL); isize = xfs_new_eof(ip, offset + size); if (!isize) { xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_trans_cancel(tp); return 0; } trace_xfs_setfilesize(ip, offset, size); ip->i_d.di_size = isize; xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); return xfs_trans_commit(tp); }
/* Allocate and initialize the dquot buffer for this in-core dquot. */ static int xfs_qm_dqread_alloc( struct xfs_mount *mp, struct xfs_dquot *dqp, struct xfs_buf **bpp) { struct xfs_trans *tp; int error; error = xfs_trans_alloc(mp, &M_RES(mp)->tr_qm_dqalloc, XFS_QM_DQALLOC_SPACE_RES(mp), 0, 0, &tp); if (error) goto err; error = xfs_dquot_disk_alloc(&tp, dqp, bpp); if (error) goto err_cancel; error = xfs_trans_commit(tp); if (error) { /* * Buffer was held to the transaction, so we have to unlock it * manually here because we're not passing it back. */ xfs_buf_relse(*bpp); *bpp = NULL; goto err; } return 0; err_cancel: xfs_trans_cancel(tp); err: return error; }
STATIC int xfs_commit_dummy_trans( struct xfs_mount *mp, uint log_flags) { struct xfs_inode *ip = mp->m_rootip; struct xfs_trans *tp; int error; /* * Put a dummy transaction in the log to tell recovery * that all others are OK. */ tp = xfs_trans_alloc(mp, XFS_TRANS_DUMMY1); error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0); if (error) { xfs_trans_cancel(tp, 0); return error; } xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_ihold(tp, ip); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); /* XXX(hch): ignoring the error here.. */ error = xfs_trans_commit(tp, 0); xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_log_force(mp, 0, log_flags); return 0; }
/* * Update on-disk file size now that data has been written to disk. */ STATIC int xfs_setfilesize( struct xfs_ioend *ioend) { struct xfs_inode *ip = XFS_I(ioend->io_inode); struct xfs_trans *tp = ioend->io_append_trans; xfs_fsize_t isize; current_set_flags_nested(&tp->t_pflags, PF_FSTRANS); xfs_ilock(ip, XFS_ILOCK_EXCL); isize = xfs_new_eof(ip, ioend->io_offset + ioend->io_size); if (!isize) { xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_trans_cancel(tp, 0); return 0; } trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size); ip->i_d.di_size = isize; xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); return xfs_trans_commit(tp, 0); }
/* * Update on-disk file size now that data has been written to disk. */ STATIC int xfs_setfilesize( struct xfs_ioend *ioend) { struct xfs_inode *ip = XFS_I(ioend->io_inode); struct xfs_trans *tp = ioend->io_append_trans; xfs_fsize_t isize; /* * The transaction may have been allocated in the I/O submission thread, * thus we need to mark ourselves as beeing in a transaction manually. * Similarly for freeze protection. */ current_set_flags_nested(&tp->t_pflags, PF_FSTRANS); rwsem_acquire_read(&VFS_I(ip)->i_sb->s_writers.lock_map[SB_FREEZE_FS-1], 0, 1, _THIS_IP_); xfs_ilock(ip, XFS_ILOCK_EXCL); isize = xfs_new_eof(ip, ioend->io_offset + ioend->io_size); if (!isize) { xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_trans_cancel(tp, 0); return 0; } trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size); ip->i_d.di_size = isize; xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); return xfs_trans_commit(tp, 0); }
STATIC int xfs_commit_dummy_trans( struct xfs_mount *mp, uint flags) { struct xfs_inode *ip = mp->m_rootip; struct xfs_trans *tp; int error; /* * Put a dummy transaction in the log to tell recovery * that all others are OK. */ tp = xfs_trans_alloc(mp, XFS_TRANS_DUMMY1); error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0); if (error) { xfs_trans_cancel(tp, 0); return error; } xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_ihold(tp, ip); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); error = xfs_trans_commit(tp, 0); xfs_iunlock(ip, XFS_ILOCK_EXCL); /* the log force ensures this transaction is pushed to disk */ xfs_log_force(mp, (flags & SYNC_WAIT) ? XFS_LOG_SYNC : 0); return error; }
STATIC int xfs_qm_log_quotaoff_end( xfs_mount_t *mp, xfs_qoff_logitem_t *startqoff, uint flags) { xfs_trans_t *tp; int error; xfs_qoff_logitem_t *qoffi; tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF_END); if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_qoff_logitem_t) * 2, 0, 0, XFS_DEFAULT_LOG_COUNT))) { xfs_trans_cancel(tp, 0); return (error); } qoffi = xfs_trans_get_qoff_item(tp, startqoff, flags & XFS_ALL_QUOTA_ACCT); xfs_trans_log_quotaoff_item(tp, qoffi); /* * We have to make sure that the transaction is secure on disk before we * return and actually stop quota accounting. So, make it synchronous. * We don't care about quotoff's performance. */ xfs_trans_set_sync(tp); error = xfs_trans_commit(tp, 0, NULL); return (error); }
int xfs_update_prealloc_flags( struct xfs_inode *ip, enum xfs_prealloc_flags flags) { struct xfs_trans *tp; int error; error = xfs_trans_alloc(ip->i_mount, &M_RES(ip->i_mount)->tr_writeid, 0, 0, 0, &tp); if (error) return error; xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); if (!(flags & XFS_PREALLOC_INVISIBLE)) { VFS_I(ip)->i_mode &= ~S_ISUID; if (VFS_I(ip)->i_mode & S_IXGRP) VFS_I(ip)->i_mode &= ~S_ISGID; xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); } if (flags & XFS_PREALLOC_SET) ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; if (flags & XFS_PREALLOC_CLEAR) ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC; xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); if (flags & XFS_PREALLOC_SYNC) xfs_trans_set_sync(tp); return xfs_trans_commit(tp); }
int xfs_set_dmattrs( xfs_inode_t *ip, u_int evmask, u_int16_t state) { xfs_mount_t *mp = ip->i_mount; xfs_trans_t *tp; int error; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; tp = xfs_trans_alloc(mp, XFS_TRANS_SET_DMATTRS); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0); if (error) { xfs_trans_cancel(tp, 0); return error; } xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); ip->i_d.di_dmevmask = evmask; ip->i_d.di_dmstate = state; xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); error = xfs_trans_commit(tp, 0); return error; }
STATIC int xfs_vn_update_time( struct inode *inode, struct timespec *now, int flags) { struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; struct xfs_trans *tp; int error; trace_xfs_update_time(ip); error = xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp); if (error) return error; xfs_ilock(ip, XFS_ILOCK_EXCL); if (flags & S_CTIME) inode->i_ctime = *now; if (flags & S_MTIME) inode->i_mtime = *now; if (flags & S_ATIME) inode->i_atime = *now; xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_log_inode(tp, ip, XFS_ILOG_TIMESTAMP); return xfs_trans_commit(tp); }
/* * Roll from one trans in the sequence of PERMANENT transactions to * the next: permanent transactions are only flushed out when * committed with XFS_TRANS_RELEASE_LOG_RES, but we still want as soon * as possible to let chunks of it go to the log. So we commit the * chunk we've been working on and get a new transaction to continue. */ int libxfs_trans_roll( struct xfs_trans **tpp, struct xfs_inode *dp) { struct xfs_mount *mp; struct xfs_trans *trans; struct xfs_trans_res tres; int error; /* * Ensure that the inode is always logged. */ trans = *tpp; if (dp) xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE); /* * Copy the critical parameters from one trans to the next. */ mp = trans->t_mountp; tres.tr_logres = trans->t_log_res; tres.tr_logcount = trans->t_log_count; /* * Commit the current transaction. * If this commit failed, then it'd just unlock those items that * are marked to be released. That also means that a filesystem shutdown * is in progress. The caller takes the responsibility to cancel * the duplicate transaction that gets returned. */ error = xfs_trans_commit(trans); if (error) return error; /* * Reserve space in the log for th next transaction. * This also pushes items in the "AIL", the list of logged items, * out to disk if they are taking up space at the tail of the log * that we want to use. This requires that either nothing be locked * across this call, or that anything that is locked be logged in * the prior and the next transactions. */ tres.tr_logflags = XFS_TRANS_PERM_LOG_RES; error = libxfs_trans_alloc(mp, &tres, 0, 0, 0, tpp); trans = *tpp; /* * Ensure that the inode is in the new transaction and locked. */ if (error) return error; if (dp) xfs_trans_ijoin(trans, dp, 0); return 0; }
STATIC int xfs_qm_log_quotaoff( xfs_mount_t *mp, xfs_qoff_logitem_t **qoffstartp, uint flags) { xfs_trans_t *tp; int error; unsigned long s; xfs_qoff_logitem_t *qoffi=NULL; uint oldsbqflag=0; tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF); if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_qoff_logitem_t) * 2 + mp->m_sb.sb_sectsize + 128, 0, 0, XFS_DEFAULT_LOG_COUNT))) { goto error0; } qoffi = xfs_trans_get_qoff_item(tp, NULL, flags & XFS_ALL_QUOTA_ACCT); xfs_trans_log_quotaoff_item(tp, qoffi); s = XFS_SB_LOCK(mp); oldsbqflag = mp->m_sb.sb_qflags; mp->m_sb.sb_qflags = (mp->m_qflags & ~(flags)) & XFS_MOUNT_QUOTA_ALL; XFS_SB_UNLOCK(mp, s); xfs_mod_sb(tp, XFS_SB_QFLAGS); /* * We have to make sure that the transaction is secure on disk before we * return and actually stop quota accounting. So, make it synchronous. * We don't care about quotoff's performance. */ xfs_trans_set_sync(tp); error = xfs_trans_commit(tp, 0, NULL); error0: if (error) { xfs_trans_cancel(tp, 0); /* * No one else is modifying sb_qflags, so this is OK. * We still hold the quotaofflock. */ s = XFS_SB_LOCK(mp); mp->m_sb.sb_qflags = oldsbqflag; XFS_SB_UNLOCK(mp, s); } *qoffstartp = qoffi; return (error); }
/* * Ensure the reflink bit is set in both inodes. */ STATIC int xfs_reflink_set_inode_flag( struct xfs_inode *src, struct xfs_inode *dest) { struct xfs_mount *mp = src->i_mount; int error; struct xfs_trans *tp; if (xfs_is_reflink_inode(src) && xfs_is_reflink_inode(dest)) return 0; error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 0, 0, 0, &tp); if (error) goto out_error; /* Lock both files against IO */ if (src->i_ino == dest->i_ino) xfs_ilock(src, XFS_ILOCK_EXCL); else xfs_lock_two_inodes(src, dest, XFS_ILOCK_EXCL); if (!xfs_is_reflink_inode(src)) { trace_xfs_reflink_set_inode_flag(src); xfs_trans_ijoin(tp, src, XFS_ILOCK_EXCL); src->i_d.di_flags2 |= XFS_DIFLAG2_REFLINK; xfs_trans_log_inode(tp, src, XFS_ILOG_CORE); xfs_ifork_init_cow(src); } else xfs_iunlock(src, XFS_ILOCK_EXCL); if (src->i_ino == dest->i_ino) goto commit_flags; if (!xfs_is_reflink_inode(dest)) { trace_xfs_reflink_set_inode_flag(dest); xfs_trans_ijoin(tp, dest, XFS_ILOCK_EXCL); dest->i_d.di_flags2 |= XFS_DIFLAG2_REFLINK; xfs_trans_log_inode(tp, dest, XFS_ILOG_CORE); xfs_ifork_init_cow(dest); } else xfs_iunlock(dest, XFS_ILOCK_EXCL); commit_flags: error = xfs_trans_commit(tp); if (error) goto out_error; return error; out_error: trace_xfs_reflink_set_inode_flag_error(dest, error, _RET_IP_); return error; }
STATIC int xfs_qm_scall_trunc_qfile( struct xfs_mount *mp, xfs_ino_t ino) { struct xfs_inode *ip; struct xfs_trans *tp; int error; if (ino == NULLFSINO) return 0; error = xfs_iget(mp, NULL, ino, 0, 0, &ip); if (error) return error; xfs_ilock(ip, XFS_IOLOCK_EXCL); tp = xfs_trans_alloc(mp, XFS_TRANS_TRUNCATE_FILE); error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0, XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT); if (error) { xfs_trans_cancel(tp, 0); xfs_iunlock(ip, XFS_IOLOCK_EXCL); goto out_put; } xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, 0); ip->i_d.di_size = 0; xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0); if (error) { xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); goto out_unlock; } ASSERT(ip->i_d.di_nextents == 0); xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); out_unlock: xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); out_put: IRELE(ip); return error; }
STATIC int xfs_qm_log_quotaoff( xfs_mount_t *mp, xfs_qoff_logitem_t **qoffstartp, uint flags) { xfs_trans_t *tp; int error; xfs_qoff_logitem_t *qoffi=NULL; uint oldsbqflag=0; tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_qm_quotaoff, 0, 0); if (error) goto error0; qoffi = xfs_trans_get_qoff_item(tp, NULL, flags & XFS_ALL_QUOTA_ACCT); xfs_trans_log_quotaoff_item(tp, qoffi); spin_lock(&mp->m_sb_lock); oldsbqflag = mp->m_sb.sb_qflags; mp->m_sb.sb_qflags = (mp->m_qflags & ~(flags)) & XFS_MOUNT_QUOTA_ALL; spin_unlock(&mp->m_sb_lock); xfs_mod_sb(tp, XFS_SB_QFLAGS); /* * We have to make sure that the transaction is secure on disk before we * return and actually stop quota accounting. So, make it synchronous. * We don't care about quotoff's performance. */ xfs_trans_set_sync(tp); error = xfs_trans_commit(tp, 0); error0: if (error) { xfs_trans_cancel(tp, 0); /* * No one else is modifying sb_qflags, so this is OK. * We still hold the quotaofflock. */ spin_lock(&mp->m_sb_lock); mp->m_sb.sb_qflags = oldsbqflag; spin_unlock(&mp->m_sb_lock); } *qoffstartp = qoffi; return error; }
/* * Cancel CoW reservations for some byte range of an inode. * * If cancel_real is true this function cancels all COW fork extents for the * inode; if cancel_real is false, real extents are not cleared. */ int xfs_reflink_cancel_cow_range( struct xfs_inode *ip, xfs_off_t offset, xfs_off_t count, bool cancel_real) { struct xfs_trans *tp; xfs_fileoff_t offset_fsb; xfs_fileoff_t end_fsb; int error; trace_xfs_reflink_cancel_cow_range(ip, offset, count); ASSERT(xfs_is_reflink_inode(ip)); offset_fsb = XFS_B_TO_FSBT(ip->i_mount, offset); if (count == NULLFILEOFF) end_fsb = NULLFILEOFF; else end_fsb = XFS_B_TO_FSB(ip->i_mount, offset + count); /* Start a rolling transaction to remove the mappings */ error = xfs_trans_alloc(ip->i_mount, &M_RES(ip->i_mount)->tr_write, 0, 0, 0, &tp); if (error) goto out; xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, 0); /* Scrape out the old CoW reservations */ error = xfs_reflink_cancel_cow_blocks(ip, &tp, offset_fsb, end_fsb, cancel_real); if (error) goto out_cancel; error = xfs_trans_commit(tp); xfs_iunlock(ip, XFS_ILOCK_EXCL); return error; out_cancel: xfs_trans_cancel(tp); xfs_iunlock(ip, XFS_ILOCK_EXCL); out: trace_xfs_reflink_cancel_cow_range_error(ip, error, _RET_IP_); return error; }
/* * Update destination inode size & cowextsize hint, if necessary. */ STATIC int xfs_reflink_update_dest( struct xfs_inode *dest, xfs_off_t newlen, xfs_extlen_t cowextsize, bool is_dedupe) { struct xfs_mount *mp = dest->i_mount; struct xfs_trans *tp; int error; if (is_dedupe && newlen <= i_size_read(VFS_I(dest)) && cowextsize == 0) return 0; error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 0, 0, 0, &tp); if (error) goto out_error; xfs_ilock(dest, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, dest, XFS_ILOCK_EXCL); if (newlen > i_size_read(VFS_I(dest))) { trace_xfs_reflink_update_inode_size(dest, newlen); i_size_write(VFS_I(dest), newlen); dest->i_d.di_size = newlen; } if (cowextsize) { dest->i_d.di_cowextsize = cowextsize; dest->i_d.di_flags2 |= XFS_DIFLAG2_COWEXTSIZE; } if (!is_dedupe) { xfs_trans_ichgtime(tp, dest, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); } xfs_trans_log_inode(tp, dest, XFS_ILOG_CORE); error = xfs_trans_commit(tp); if (error) goto out_error; return error; out_error: trace_xfs_reflink_update_inode_size_error(dest, error, _RET_IP_); return error; }
/* * Wrapper around call to libxfs_ialloc. Takes care of committing and * allocating a new transaction as needed. * * Originally there were two copies of this code - one in mkfs, the * other in repair - now there is just the one. */ int libxfs_inode_alloc( xfs_trans_t **tp, xfs_inode_t *pip, mode_t mode, ushort nlink, dev_t rdev, cred_t *cr, xfs_inode_t **ipp) { boolean_t call_again; int i; xfs_buf_t *ialloc_context; xfs_inode_t *ip; xfs_trans_t *ntp; int error; call_again = B_FALSE; ialloc_context = (xfs_buf_t *)0; error = libxfs_ialloc(*tp, pip, mode, nlink, rdev, cr, (xfs_prid_t) 0, 1, &ialloc_context, &call_again, &ip); if (error) { return error; } if (call_again) { xfs_trans_bhold(*tp, ialloc_context); ntp = xfs_trans_dup(*tp); xfs_trans_commit(*tp, 0, NULL); *tp = ntp; if ((i = xfs_trans_reserve(*tp, 0, 0, 0, 0, 0))) { fprintf(stderr, "%s: cannot reserve space: %s\n", progname, strerror(errno)); exit(1); } xfs_trans_bjoin(*tp, ialloc_context); error = libxfs_ialloc(*tp, pip, mode, nlink, rdev, cr, (xfs_prid_t) 0, 1, &ialloc_context, &call_again, &ip); if (error) { return error; } } *ipp = ip; ASSERT(ip); return error; }
STATIC int xfs_qm_log_quotaoff( xfs_mount_t *mp, xfs_qoff_logitem_t **qoffstartp, uint flags) { xfs_trans_t *tp; int error; xfs_qoff_logitem_t *qoffi=NULL; uint oldsbqflag=0; tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF); if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_qoff_logitem_t) * 2 + mp->m_sb.sb_sectsize + 128, 0, 0, XFS_DEFAULT_LOG_COUNT))) { goto error0; } qoffi = xfs_trans_get_qoff_item(tp, NULL, flags & XFS_ALL_QUOTA_ACCT); xfs_trans_log_quotaoff_item(tp, qoffi); spin_lock(&mp->m_sb_lock); oldsbqflag = mp->m_sb.sb_qflags; mp->m_sb.sb_qflags = (mp->m_qflags & ~(flags)) & XFS_MOUNT_QUOTA_ALL; spin_unlock(&mp->m_sb_lock); xfs_mod_sb(tp, XFS_SB_QFLAGS); xfs_trans_set_sync(tp); error = xfs_trans_commit(tp, 0); error0: if (error) { xfs_trans_cancel(tp, 0); spin_lock(&mp->m_sb_lock); mp->m_sb.sb_qflags = oldsbqflag; spin_unlock(&mp->m_sb_lock); } *qoffstartp = qoffi; return (error); }
/* * xfs_sync_sb * * Sync the superblock to disk. * * Note that the caller is responsible for checking the frozen state of the * filesystem. This procedure uses the non-blocking transaction allocator and * thus will allow modifications to a frozen fs. This is required because this * code can be called during the process of freezing where use of the high-level * allocator would deadlock. */ int xfs_sync_sb( struct xfs_mount *mp, bool wait) { struct xfs_trans *tp; int error; tp = _xfs_trans_alloc(mp, XFS_TRANS_SB_CHANGE, KM_SLEEP); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_sb, 0, 0); if (error) { xfs_trans_cancel(tp, 0); return error; } xfs_log_sb(tp); if (wait) xfs_trans_set_sync(tp); return xfs_trans_commit(tp, 0); }
/* * Start a transaction and write the incore superblock changes to * disk. flags parameter indicates which fields have changed. */ int xfs_qm_write_sb_changes( xfs_mount_t *mp, __int64_t flags) { xfs_trans_t *tp; int error; tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE); error = xfs_trans_reserve(tp, 0, XFS_QM_SBCHANGE_LOG_RES(mp), 0, 0, XFS_DEFAULT_LOG_COUNT); if (error) { xfs_trans_cancel(tp, 0); return error; } xfs_mod_sb(tp, flags); error = xfs_trans_commit(tp, 0); return error; }
STATIC int xfs_vn_update_time( struct inode *inode, struct timespec *now, int flags) { struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; struct xfs_trans *tp; int error; trace_xfs_update_time(ip); tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_fsyncts, 0, 0); if (error) { xfs_trans_cancel(tp, 0); return -error; } xfs_ilock(ip, XFS_ILOCK_EXCL); if (flags & S_CTIME) { inode->i_ctime = *now; ip->i_d.di_ctime.t_sec = (__int32_t)now->tv_sec; ip->i_d.di_ctime.t_nsec = (__int32_t)now->tv_nsec; } if (flags & S_MTIME) { inode->i_mtime = *now; ip->i_d.di_mtime.t_sec = (__int32_t)now->tv_sec; ip->i_d.di_mtime.t_nsec = (__int32_t)now->tv_nsec; } if (flags & S_ATIME) { inode->i_atime = *now; ip->i_d.di_atime.t_sec = (__int32_t)now->tv_sec; ip->i_d.di_atime.t_nsec = (__int32_t)now->tv_nsec; } xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_log_inode(tp, ip, XFS_ILOG_TIMESTAMP); return -xfs_trans_commit(tp, 0); }
/* * Clear the quotaflags in memory and in the superblock. */ int xfs_mount_reset_sbqflags(xfs_mount_t *mp) { int error; xfs_trans_t *tp; unsigned long s; mp->m_qflags = 0; /* * It is OK to look at sb_qflags here in mount path, * without SB_LOCK. */ if (mp->m_sb.sb_qflags == 0) return 0; s = XFS_SB_LOCK(mp); mp->m_sb.sb_qflags = 0; XFS_SB_UNLOCK(mp, s); /* * if the fs is readonly, let the incore superblock run * with quotas off but don't flush the update out to disk */ if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY) return 0; #ifdef QUOTADEBUG xfs_fs_cmn_err(CE_NOTE, mp, "Writing superblock quota changes"); #endif tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE); if ((error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0, XFS_DEFAULT_LOG_COUNT))) { xfs_trans_cancel(tp, 0); xfs_fs_cmn_err(CE_ALERT, mp, "xfs_mount_reset_sbqflags: Superblock update failed!"); return error; } xfs_mod_sb(tp, XFS_SB_QFLAGS); error = xfs_trans_commit(tp, 0, NULL); return error; }
/* * This is a subroutine for xfs_write() and other writers (xfs_ioctl) * which clears the setuid and setgid bits when a file is written. */ int xfs_write_clear_setuid( xfs_inode_t *ip) { xfs_mount_t *mp; xfs_trans_t *tp; int error; mp = ip->i_mount; tp = xfs_trans_alloc(mp, XFS_TRANS_WRITEID); if ((error = xfs_trans_reserve(tp, 0, XFS_WRITEID_LOG_RES(mp), 0, 0, 0))) { xfs_trans_cancel(tp, 0); return error; } xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_ihold(tp, ip); ip->i_d.di_mode &= ~S_ISUID; /* * Note that we don't have to worry about mandatory * file locking being disabled here because we only * clear the S_ISGID bit if the Group execute bit is * on, but if it was on then mandatory locking wouldn't * have been enabled. */ if (ip->i_d.di_mode & S_IXGRP) { ip->i_d.di_mode &= ~S_ISGID; } xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); xfs_trans_set_sync(tp); error = xfs_trans_commit(tp, 0, NULL); xfs_iunlock(ip, XFS_ILOCK_EXCL); return 0; }
/* * Handle logging requirements of various synchronous types of write. */ int xfs_write_sync_logforce( xfs_mount_t *mp, xfs_inode_t *ip) { int error = 0; /* * If we're treating this as O_DSYNC and we have not updated the * size, force the log. */ if (!(mp->m_flags & XFS_MOUNT_OSYNCISOSYNC) && !(ip->i_update_size)) { xfs_inode_log_item_t *iip = ip->i_itemp; /* * If an allocation transaction occurred * without extending the size, then we have to force * the log up the proper point to ensure that the * allocation is permanent. We can't count on * the fact that buffered writes lock out direct I/O * writes - the direct I/O write could have extended * the size nontransactionally, then finished before * we started. xfs_write_file will think that the file * didn't grow but the update isn't safe unless the * size change is logged. * * Force the log if we've committed a transaction * against the inode or if someone else has and * the commit record hasn't gone to disk (e.g. * the inode is pinned). This guarantees that * all changes affecting the inode are permanent * when we return. */ if (iip && iip->ili_last_lsn) { xfs_log_force(mp, iip->ili_last_lsn, XFS_LOG_FORCE | XFS_LOG_SYNC); } else if (xfs_ipincount(ip) > 0) { xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); } } else { xfs_trans_t *tp; /* * O_SYNC or O_DSYNC _with_ a size update are handled * the same way. * * If the write was synchronous then we need to make * sure that the inode modification time is permanent. * We'll have updated the timestamp above, so here * we use a synchronous transaction to log the inode. * It's not fast, but it's necessary. * * If this a dsync write and the size got changed * non-transactionally, then we need to ensure that * the size change gets logged in a synchronous * transaction. */ tp = xfs_trans_alloc(mp, XFS_TRANS_WRITE_SYNC); if ((error = xfs_trans_reserve(tp, 0, XFS_SWRITE_LOG_RES(mp), 0, 0, 0))) { /* Transaction reserve failed */ xfs_trans_cancel(tp, 0); } else { /* Transaction reserve successful */ xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_ihold(tp, ip); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); xfs_trans_set_sync(tp); error = xfs_trans_commit(tp, 0, NULL); xfs_iunlock(ip, XFS_ILOCK_EXCL); } } return error; }
} ASSERT(ip->i_d.di_version > 1); xfs_set_projid(ip, fa->fsx_projid); } /* * Only set the extent size hint if we've already determined that the * extent size hint should be set on the inode. If no extent size flags * are set on the inode then unconditionally clear the extent size hint. */ if (ip->i_d.di_flags & (XFS_DIFLAG_EXTSIZE | XFS_DIFLAG_EXTSZINHERIT)) ip->i_d.di_extsize = fa->fsx_extsize >> mp->m_sb.sb_blocklog; else ip->i_d.di_extsize = 0; code = xfs_trans_commit(tp, 0); /* * Release any dquot(s) the inode had kept before chown. */ xfs_qm_dqrele(olddquot); xfs_qm_dqrele(udqp); xfs_qm_dqrele(pdqp); return code; error_trans_cancel: xfs_trans_cancel(tp, 0); error_free_dquots: xfs_qm_dqrele(udqp); xfs_qm_dqrele(pdqp);