Skip to content

Commit

Permalink
Merge branch 'xfs-misc-fixes-1-for-3.16' into for-next
Browse files Browse the repository at this point in the history
  • Loading branch information
dchinner committed May 14, 2014
2 parents b767692 + 8cfcc3e commit ff14ee4
Show file tree
Hide file tree
Showing 13 changed files with 142 additions and 268 deletions.
14 changes: 13 additions & 1 deletion fs/quota/quota.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,17 @@ static int quota_getxquota(struct super_block *sb, int type, qid_t id,
return ret;
}

static int quota_rmxquota(struct super_block *sb, void __user *addr)
{
__u32 flags;

if (copy_from_user(&flags, addr, sizeof(flags)))
return -EFAULT;
if (!sb->s_qcop->rm_xquota)
return -ENOSYS;
return sb->s_qcop->rm_xquota(sb, flags);
}

/* Copy parameters and call proper function */
static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
void __user *addr, struct path *path)
Expand Down Expand Up @@ -316,8 +327,9 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
return sb->s_qcop->quota_sync(sb, type);
case Q_XQUOTAON:
case Q_XQUOTAOFF:
case Q_XQUOTARM:
return quota_setxstate(sb, cmd, addr);
case Q_XQUOTARM:
return quota_rmxquota(sb, addr);
case Q_XGETQSTAT:
return quota_getxstate(sb, addr);
case Q_XGETQSTATV:
Expand Down
3 changes: 1 addition & 2 deletions fs/xfs/xfs_dir2_readdir.c
Original file line number Diff line number Diff line change
Expand Up @@ -456,15 +456,14 @@ xfs_dir2_leaf_readbuf(
/*
* Advance offset through the mapping table.
*/
for (j = 0; j < mp->m_dirblkfsbs; j++) {
for (j = 0; j < mp->m_dirblkfsbs; j += length ) {
/*
* The rest of this extent but not more than a dir
* block.
*/
length = min_t(int, mp->m_dirblkfsbs,
map[mip->ra_index].br_blockcount -
mip->ra_offset);
j += length;
mip->ra_offset += length;

/*
Expand Down
53 changes: 8 additions & 45 deletions fs/xfs/xfs_dquot.c
Original file line number Diff line number Diff line change
Expand Up @@ -832,47 +832,6 @@ xfs_qm_dqget(
return (0);
}


STATIC void
xfs_qm_dqput_final(
struct xfs_dquot *dqp)
{
struct xfs_quotainfo *qi = dqp->q_mount->m_quotainfo;
struct xfs_dquot *gdqp;
struct xfs_dquot *pdqp;

trace_xfs_dqput_free(dqp);

if (list_lru_add(&qi->qi_lru, &dqp->q_lru))
XFS_STATS_INC(xs_qm_dquot_unused);

/*
* If we just added a udquot to the freelist, then we want to release
* the gdquot/pdquot reference that it (probably) has. Otherwise it'll
* keep the gdquot/pdquot from getting reclaimed.
*/
gdqp = dqp->q_gdquot;
if (gdqp) {
xfs_dqlock(gdqp);
dqp->q_gdquot = NULL;
}

pdqp = dqp->q_pdquot;
if (pdqp) {
xfs_dqlock(pdqp);
dqp->q_pdquot = NULL;
}
xfs_dqunlock(dqp);

/*
* If we had a group/project quota hint, release it now.
*/
if (gdqp)
xfs_qm_dqput(gdqp);
if (pdqp)
xfs_qm_dqput(pdqp);
}

/*
* Release a reference to the dquot (decrement ref-count) and unlock it.
*
Expand All @@ -888,10 +847,14 @@ xfs_qm_dqput(

trace_xfs_dqput(dqp);

if (--dqp->q_nrefs > 0)
xfs_dqunlock(dqp);
else
xfs_qm_dqput_final(dqp);
if (--dqp->q_nrefs == 0) {
struct xfs_quotainfo *qi = dqp->q_mount->m_quotainfo;
trace_xfs_dqput_free(dqp);

if (list_lru_add(&qi->qi_lru, &dqp->q_lru))
XFS_STATS_INC(xs_qm_dquot_unused);
}
xfs_dqunlock(dqp);
}

/*
Expand Down
2 changes: 0 additions & 2 deletions fs/xfs/xfs_dquot.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ typedef struct xfs_dquot {
int q_bufoffset; /* off of dq in buffer (# dquots) */
xfs_fileoff_t q_fileoffset; /* offset in quotas file */

struct xfs_dquot*q_gdquot; /* group dquot, hint only */
struct xfs_dquot*q_pdquot; /* project dquot, hint only */
xfs_disk_dquot_t q_core; /* actual usage & quotas */
xfs_dq_logitem_t q_logitem; /* dquot log item */
xfs_qcnt_t q_res_bcount; /* total regular nblks used+reserved */
Expand Down
5 changes: 3 additions & 2 deletions fs/xfs/xfs_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -543,10 +543,11 @@ xfs_attrmulti_by_handle(

ops = memdup_user(am_hreq.ops, size);
if (IS_ERR(ops)) {
error = PTR_ERR(ops);
error = -PTR_ERR(ops);
goto out_dput;
}

error = ENOMEM;
attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL);
if (!attr_name)
goto out_kfree_ops;
Expand All @@ -556,7 +557,7 @@ xfs_attrmulti_by_handle(
ops[i].am_error = strncpy_from_user((char *)attr_name,
ops[i].am_attrname, MAXNAMELEN);
if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN)
error = -ERANGE;
error = ERANGE;
if (ops[i].am_error < 0)
break;

Expand Down
5 changes: 3 additions & 2 deletions fs/xfs/xfs_ioctl32.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,10 +424,11 @@ xfs_compat_attrmulti_by_handle(

ops = memdup_user(compat_ptr(am_hreq.ops), size);
if (IS_ERR(ops)) {
error = PTR_ERR(ops);
error = -PTR_ERR(ops);
goto out_dput;
}

error = ENOMEM;
attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL);
if (!attr_name)
goto out_kfree_ops;
Expand All @@ -438,7 +439,7 @@ xfs_compat_attrmulti_by_handle(
compat_ptr(ops[i].am_attrname),
MAXNAMELEN);
if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN)
error = -ERANGE;
error = ERANGE;
if (ops[i].am_error < 0)
break;

Expand Down
20 changes: 16 additions & 4 deletions fs/xfs/xfs_iops.c
Original file line number Diff line number Diff line change
Expand Up @@ -829,22 +829,34 @@ xfs_setattr_size(
*/
inode_dio_wait(inode);

/*
* Do all the page cache truncate work outside the transaction context
* as the "lock" order is page lock->log space reservation. i.e.
* locking pages inside the transaction can ABBA deadlock with
* writeback. We have to do the VFS inode size update before we truncate
* the pagecache, however, to avoid racing with page faults beyond the
* new EOF they are not serialised against truncate operations except by
* page locks and size updates.
*
* Hence we are in a situation where a truncate can fail with ENOMEM
* from xfs_trans_reserve(), but having already truncated the in-memory
* version of the file (i.e. made user visible changes). There's not
* much we can do about this, except to hope that the caller sees ENOMEM
* and retries the truncate operation.
*/
error = -block_truncate_page(inode->i_mapping, newsize, xfs_get_blocks);
if (error)
return error;
truncate_setsize(inode, newsize);

tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE);
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
if (error)
goto out_trans_cancel;

truncate_setsize(inode, newsize);

commit_flags = XFS_TRANS_RELEASE_LOG_RES;
lock_flags |= XFS_ILOCK_EXCL;

xfs_ilock(ip, XFS_ILOCK_EXCL);

xfs_trans_ijoin(tp, ip, 0);

/*
Expand Down
9 changes: 6 additions & 3 deletions fs/xfs/xfs_log.c
Original file line number Diff line number Diff line change
Expand Up @@ -3952,11 +3952,14 @@ xfs_log_force_umount(
retval = xlog_state_ioerror(log);
spin_unlock(&log->l_icloglock);
}

/*
* Wake up everybody waiting on xfs_log_force.
* Callback all log item committed functions as if the
* log writes were completed.
* Wake up everybody waiting on xfs_log_force. Wake the CIL push first
* as if the log writes were completed. The abort handling in the log
* item committed callback functions will do this again under lock to
* avoid races.
*/
wake_up_all(&log->l_cilp->xc_commit_wait);
xlog_state_do_callback(log, XFS_LI_ABORTED, NULL);

#ifdef XFSERRORDEBUG
Expand Down
50 changes: 42 additions & 8 deletions fs/xfs/xfs_log_cil.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,15 @@ xlog_cil_committed(
xfs_extent_busy_clear(mp, &ctx->busy_extents,
(mp->m_flags & XFS_MOUNT_DISCARD) && !abort);

/*
* If we are aborting the commit, wake up anyone waiting on the
* committing list. If we don't, then a shutdown we can leave processes
* waiting in xlog_cil_force_lsn() waiting on a sequence commit that
* will never happen because we aborted it.
*/
spin_lock(&ctx->cil->xc_push_lock);
if (abort)
wake_up_all(&ctx->cil->xc_commit_wait);
list_del(&ctx->committing);
spin_unlock(&ctx->cil->xc_push_lock);

Expand Down Expand Up @@ -563,9 +571,19 @@ xlog_cil_push(
restart:
spin_lock(&cil->xc_push_lock);
list_for_each_entry(new_ctx, &cil->xc_committing, committing) {
/*
* Avoid getting stuck in this loop because we were woken by the
* shutdown, but then went back to sleep once already in the
* shutdown state.
*/
if (XLOG_FORCED_SHUTDOWN(log)) {
spin_unlock(&cil->xc_push_lock);
goto out_abort_free_ticket;
}

/*
* Higher sequences will wait for this one so skip them.
* Don't wait for own own sequence, either.
* Don't wait for our own sequence, either.
*/
if (new_ctx->sequence >= ctx->sequence)
continue;
Expand Down Expand Up @@ -810,6 +828,13 @@ xlog_cil_force_lsn(
*/
spin_lock(&cil->xc_push_lock);
list_for_each_entry(ctx, &cil->xc_committing, committing) {
/*
* Avoid getting stuck in this loop because we were woken by the
* shutdown, but then went back to sleep once already in the
* shutdown state.
*/
if (XLOG_FORCED_SHUTDOWN(log))
goto out_shutdown;
if (ctx->sequence > sequence)
continue;
if (!ctx->commit_lsn) {
Expand All @@ -833,14 +858,12 @@ xlog_cil_force_lsn(
* push sequence after the above wait loop and the CIL still contains
* dirty objects.
*
* When the push occurs, it will empty the CIL and
* atomically increment the currect sequence past the push sequence and
* move it into the committing list. Of course, if the CIL is clean at
* the time of the push, it won't have pushed the CIL at all, so in that
* case we should try the push for this sequence again from the start
* just in case.
* When the push occurs, it will empty the CIL and atomically increment
* the currect sequence past the push sequence and move it into the
* committing list. Of course, if the CIL is clean at the time of the
* push, it won't have pushed the CIL at all, so in that case we should
* try the push for this sequence again from the start just in case.
*/

if (sequence == cil->xc_current_sequence &&
!list_empty(&cil->xc_cil)) {
spin_unlock(&cil->xc_push_lock);
Expand All @@ -849,6 +872,17 @@ xlog_cil_force_lsn(

spin_unlock(&cil->xc_push_lock);
return commit_lsn;

/*
* We detected a shutdown in progress. We need to trigger the log force
* to pass through it's iclog state machine error handling, even though
* we are already in a shutdown state. Hence we can't return
* NULLCOMMITLSN here as that has special meaning to log forces (i.e.
* LSN is already stable), so we return a zero LSN instead.
*/
out_shutdown:
spin_unlock(&cil->xc_push_lock);
return 0;
}

/*
Expand Down
Loading

0 comments on commit ff14ee4

Please sign in to comment.