Pull xfs bugfixes from Ben Myers: "This contains fixes for some asserts related to project quotas, a memory leak, a hang when disabling group or project quotas before disabling user quotas, Dave's email address, several fixes for the alignment of file allocation to stripe unit/width geometry, a fix for an assertion with xfs_zero_remaining_bytes, and the behavior of metadata writeback in the face of IO errors. Details: - fix memory leak in xfs_dir2_node_removename - fix quota assertion in xfs_setattr_size - fix quota assertions in xfs_qm_vop_create_dqattach - fix for hang when disabling group and project quotas before disabling user quotas - fix Dave Chinner's email address in MAINTAINERS - fix for file allocation alignment - fix for assertion in xfs_buf_stale by removing xfsbdstrat - fix for alignment with swalloc mount option - fix for "retry forever" semantics on IO errors" * tag 'xfs-for-linus-v3.13-rc5' of git://oss.sgi.com/xfs/xfs: xfs: abort metadata writeback on permanent errors xfs: swalloc doesn't align allocations properly xfs: remove xfsbdstrat error xfs: align initial file allocations correctly MAINTAINERS: fix incorrect mail address of XFS maintainer xfs: fix infinite loop by detaching the group/project hints from user dquot xfs: fix assertion failure at xfs_setattr_nonsize xfs: fix false assertion at xfs_qm_vop_create_dqattach xfs: fix memory leak in xfs_dir2_node_removename
Unified · Split
| @@ -9588,7 +9588,7 @@ F: drivers/xen/*swiotlb* · 9587 unmodified lines | ||
| 9588 | 9588 | |
| 9589 | 9589 | XFS FILESYSTEM |
| 9590 | 9590 | P: Silicon Graphics Inc |
| 9591 | −M: Dave Chinner <dchinner@fromorbit.com> | |
| 9591 | +M: Dave Chinner <david@fromorbit.com> | |
| 9592 | 9592 | M: Ben Myers <bpm@sgi.com> |
| 9593 | 9593 | M: xfs@oss.sgi.com |
| 9594 | 9594 | L: xfs@oss.sgi.com |
| @@ -1635,7 +1635,7 @@ xfs_bmap_last_extent( · 1634 unmodified lines | ||
| 1635 | 1635 | * blocks at the end of the file which do not start at the previous data block, |
| 1636 | 1636 | * we will try to align the new blocks at stripe unit boundaries. |
| 1637 | 1637 | * |
| 1638 | − * Returns 0 in bma->aeof if the file (fork) is empty as any new write will be | |
| 1638 | + * Returns 1 in bma->aeof if the file (fork) is empty as any new write will be | |
| 1639 | 1639 | * at, or past the EOF. |
| 1640 | 1640 | */ |
| 1641 | 1641 | STATIC int |
| @@ -1650,9 +1650,14 @@ xfs_bmap_isaeof( · 8 unmodified lines | ||
| 1650 | 1650 | bma->aeof = 0; |
| 1651 | 1651 | error = xfs_bmap_last_extent(NULL, bma->ip, whichfork, &rec, |
| 1652 | 1652 | &is_empty); |
| 1653 | − if (error || is_empty) | |
| 1653 | + if (error) | |
| 1654 | 1654 | return error; |
| 1655 | 1655 | |
| 1656 | + if (is_empty) { | |
| 1657 | + bma->aeof = 1; | |
| 1658 | + return 0; | |
| 1659 | + } | |
| 1660 | + | |
| 1656 | 1661 | /* |
| 1657 | 1662 | * Check if we are allocation or past the last extent, or at least into |
| 1658 | 1663 | * the last delayed allocated extent. |
| @@ -3643,10 +3648,19 @@ xfs_bmap_btalloc( · 1984 unmodified lines | ||
| 3643 | 3648 | int isaligned; |
| 3644 | 3649 | int tryagain; |
| 3645 | 3650 | int error; |
| 3651 | + int stripe_align; | |
| 3646 | 3652 | |
| 3647 | 3653 | ASSERT(ap->length); |
| 3648 | 3654 | |
| 3649 | 3655 | mp = ap->ip->i_mount; |
| 3656 | + | |
| 3657 | + /* stripe alignment for allocation is determined by mount parameters */ | |
| 3658 | + stripe_align = 0; | |
| 3659 | + if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC)) | |
| 3660 | + stripe_align = mp->m_swidth; | |
| 3661 | + else if (mp->m_dalign) | |
| 3662 | + stripe_align = mp->m_dalign; | |
| 3663 | + | |
| 3650 | 3664 | align = ap->userdata ? xfs_get_extsz_hint(ap->ip) : 0; |
| 3651 | 3665 | if (unlikely(align)) { |
| 3652 | 3666 | error = xfs_bmap_extsize_align(mp, &ap->got, &ap->prev, |
| @@ -3655,6 +3669,8 @@ xfs_bmap_btalloc( · 2 unmodified lines | ||
| 3655 | 3669 | ASSERT(!error); |
| 3656 | 3670 | ASSERT(ap->length); |
| 3657 | 3671 | } |
| 3672 | + | |
| 3673 | + | |
| 3658 | 3674 | nullfb = *ap->firstblock == NULLFSBLOCK; |
| 3659 | 3675 | fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, *ap->firstblock); |
| 3660 | 3676 | if (nullfb) { |
| @@ -3730,7 +3746,7 @@ xfs_bmap_btalloc( · 69 unmodified lines | ||
| 3730 | 3746 | */ |
| 3731 | 3747 | if (!ap->flist->xbf_low && ap->aeof) { |
| 3732 | 3748 | if (!ap->offset) { |
| 3733 | − args.alignment = mp->m_dalign; | |
| 3749 | + args.alignment = stripe_align; | |
| 3734 | 3750 | atype = args.type; |
| 3735 | 3751 | isaligned = 1; |
| 3736 | 3752 | /* |
| @@ -3755,13 +3771,13 @@ xfs_bmap_btalloc( · 18 unmodified lines | ||
| 3755 | 3771 | * of minlen+alignment+slop doesn't go up |
| 3756 | 3772 | * between the calls. |
| 3757 | 3773 | */ |
| 3758 | − if (blen > mp->m_dalign && blen <= args.maxlen) | |
| 3759 | − nextminlen = blen - mp->m_dalign; | |
| 3774 | + if (blen > stripe_align && blen <= args.maxlen) | |
| 3775 | + nextminlen = blen - stripe_align; | |
| 3760 | 3776 | else |
| 3761 | 3777 | nextminlen = args.minlen; |
| 3762 | − if (nextminlen + mp->m_dalign > args.minlen + 1) | |
| 3778 | + if (nextminlen + stripe_align > args.minlen + 1) | |
| 3763 | 3779 | args.minalignslop = |
| 3764 | − nextminlen + mp->m_dalign - | |
| 3780 | + nextminlen + stripe_align - | |
| 3765 | 3781 | args.minlen - 1; |
| 3766 | 3782 | else |
| 3767 | 3783 | args.minalignslop = 0; |
| @@ -3783,7 +3799,7 @@ xfs_bmap_btalloc( · 15 unmodified lines | ||
| 3783 | 3799 | */ |
| 3784 | 3800 | args.type = atype; |
| 3785 | 3801 | args.fsbno = ap->blkno; |
| 3786 | − args.alignment = mp->m_dalign; | |
| 3802 | + args.alignment = stripe_align; | |
| 3787 | 3803 | args.minlen = nextminlen; |
| 3788 | 3804 | args.minalignslop = 0; |
| 3789 | 3805 | isaligned = 1; |
| @@ -1187,7 +1187,12 @@ xfs_zero_remaining_bytes( · 1186 unmodified lines | ||
| 1187 | 1187 | XFS_BUF_UNWRITE(bp); |
| 1188 | 1188 | XFS_BUF_READ(bp); |
| 1189 | 1189 | XFS_BUF_SET_ADDR(bp, xfs_fsb_to_db(ip, imap.br_startblock)); |
| 1190 | − xfsbdstrat(mp, bp); | |
| 1190 | + | |
| 1191 | + if (XFS_FORCED_SHUTDOWN(mp)) { | |
| 1192 | + error = XFS_ERROR(EIO); | |
| 1193 | + break; | |
| 1194 | + } | |
| 1195 | + xfs_buf_iorequest(bp); | |
| 1191 | 1196 | error = xfs_buf_iowait(bp); |
| 1192 | 1197 | if (error) { |
| 1193 | 1198 | xfs_buf_ioerror_alert(bp, |
| @@ -1200,7 +1205,12 @@ xfs_zero_remaining_bytes( · 6 unmodified lines | ||
| 1200 | 1205 | XFS_BUF_UNDONE(bp); |
| 1201 | 1206 | XFS_BUF_UNREAD(bp); |
| 1202 | 1207 | XFS_BUF_WRITE(bp); |
| 1203 | − xfsbdstrat(mp, bp); | |
| 1208 | + | |
| 1209 | + if (XFS_FORCED_SHUTDOWN(mp)) { | |
| 1210 | + error = XFS_ERROR(EIO); | |
| 1211 | + break; | |
| 1212 | + } | |
| 1213 | + xfs_buf_iorequest(bp); | |
| 1204 | 1214 | error = xfs_buf_iowait(bp); |
| 1205 | 1215 | if (error) { |
| 1206 | 1216 | xfs_buf_ioerror_alert(bp, |
| @@ -698,7 +698,11 @@ xfs_buf_read_uncached( · 697 unmodified lines | ||
| 698 | 698 | bp->b_flags |= XBF_READ; |
| 699 | 699 | bp->b_ops = ops; |
| 700 | 700 | |
| 701 | − xfsbdstrat(target->bt_mount, bp); | |
| 701 | + if (XFS_FORCED_SHUTDOWN(target->bt_mount)) { | |
| 702 | + xfs_buf_relse(bp); | |
| 703 | + return NULL; | |
| 704 | + } | |
| 705 | + xfs_buf_iorequest(bp); | |
| 702 | 706 | xfs_buf_iowait(bp); |
| 703 | 707 | return bp; |
| 704 | 708 | } |
| @@ -1089,7 +1093,7 @@ xfs_bioerror( · 384 unmodified lines | ||
| 1089 | 1093 | * This is meant for userdata errors; metadata bufs come with |
| 1090 | 1094 | * iodone functions attached, so that we can track down errors. |
| 1091 | 1095 | */ |
| 1092 | −STATIC int | |
| 1096 | +int | |
| 1093 | 1097 | xfs_bioerror_relse( |
| 1094 | 1098 | struct xfs_buf *bp) |
| 1095 | 1099 | { |
| @@ -1152,7 +1156,7 @@ xfs_bwrite( · 56 unmodified lines | ||
| 1152 | 1156 | ASSERT(xfs_buf_islocked(bp)); |
| 1153 | 1157 | |
| 1154 | 1158 | bp->b_flags |= XBF_WRITE; |
| 1155 | − bp->b_flags &= ~(XBF_ASYNC | XBF_READ | _XBF_DELWRI_Q); | |
| 1159 | + bp->b_flags &= ~(XBF_ASYNC | XBF_READ | _XBF_DELWRI_Q | XBF_WRITE_FAIL); | |
| 1156 | 1160 | |
| 1157 | 1161 | xfs_bdstrat_cb(bp); |
| 1158 | 1162 | |
| @@ -1164,25 +1168,6 @@ xfs_bwrite( · 5 unmodified lines | ||
| 1164 | 1168 | return error; |
| 1165 | 1169 | } |
| 1166 | 1170 | |
| 1167 | −/* | |
| 1168 | − * Wrapper around bdstrat so that we can stop data from going to disk in case | |
| 1169 | − * we are shutting down the filesystem. Typically user data goes thru this | |
| 1170 | − * path; one of the exceptions is the superblock. | |
| 1171 | − */ | |
| 1172 | −void | |
| 1173 | −xfsbdstrat( | |
| 1174 | − struct xfs_mount *mp, | |
| 1175 | − struct xfs_buf *bp) | |
| 1176 | −{ | |
| 1177 | − if (XFS_FORCED_SHUTDOWN(mp)) { | |
| 1178 | − trace_xfs_bdstrat_shut(bp, _RET_IP_); | |
| 1179 | − xfs_bioerror_relse(bp); | |
| 1180 | − return; | |
| 1181 | − } | |
| 1182 | − | |
| 1183 | − xfs_buf_iorequest(bp); | |
| 1184 | −} | |
| 1185 | − | |
| 1186 | 1171 | STATIC void |
| 1187 | 1172 | _xfs_buf_ioend( |
| 1188 | 1173 | xfs_buf_t *bp, |
| @@ -1516,6 +1501,12 @@ xfs_wait_buftarg( · 327 unmodified lines | ||
| 1516 | 1501 | struct xfs_buf *bp; |
| 1517 | 1502 | bp = list_first_entry(&dispose, struct xfs_buf, b_lru); |
| 1518 | 1503 | list_del_init(&bp->b_lru); |
| 1504 | + if (bp->b_flags & XBF_WRITE_FAIL) { | |
| 1505 | + xfs_alert(btp->bt_mount, | |
| 1506 | +"Corruption Alert: Buffer at block 0x%llx had permanent write failures!\n" | |
| 1507 | +"Please run xfs_repair to determine the extent of the problem.", | |
| 1508 | + (long long)bp->b_bn); | |
| 1509 | + } | |
| 1519 | 1510 | xfs_buf_rele(bp); |
| 1520 | 1511 | } |
| 1521 | 1512 | if (loop++ != 0) |
| @@ -1799,7 +1790,7 @@ __xfs_buf_delwri_submit( · 277 unmodified lines | ||
| 1799 | 1790 | |
| 1800 | 1791 | blk_start_plug(&plug); |
| 1801 | 1792 | list_for_each_entry_safe(bp, n, io_list, b_list) { |
| 1802 | − bp->b_flags &= ~(_XBF_DELWRI_Q | XBF_ASYNC); | |
| 1793 | + bp->b_flags &= ~(_XBF_DELWRI_Q | XBF_ASYNC | XBF_WRITE_FAIL); | |
| 1803 | 1794 | bp->b_flags |= XBF_WRITE; |
| 1804 | 1795 | |
| 1805 | 1796 | if (!wait) { |
| @@ -45,6 +45,7 @@ typedef enum { · 44 unmodified lines | ||
| 45 | 45 | #define XBF_ASYNC (1 << 4) /* initiator will not wait for completion */ |
| 46 | 46 | #define XBF_DONE (1 << 5) /* all pages in the buffer uptodate */ |
| 47 | 47 | #define XBF_STALE (1 << 6) /* buffer has been staled, do not find it */ |
| 48 | +#define XBF_WRITE_FAIL (1 << 24)/* async writes have failed on this buffer */ | |
| 48 | 49 | |
| 49 | 50 | /* I/O hints for the BIO layer */ |
| 50 | 51 | #define XBF_SYNCIO (1 << 10)/* treat this buffer as synchronous I/O */ |
| @@ -70,6 +71,7 @@ typedef unsigned int xfs_buf_flags_t; · 19 unmodified lines | ||
| 70 | 71 | { XBF_ASYNC, "ASYNC" }, \ |
| 71 | 72 | { XBF_DONE, "DONE" }, \ |
| 72 | 73 | { XBF_STALE, "STALE" }, \ |
| 74 | + { XBF_WRITE_FAIL, "WRITE_FAIL" }, \ | |
| 73 | 75 | { XBF_SYNCIO, "SYNCIO" }, \ |
| 74 | 76 | { XBF_FUA, "FUA" }, \ |
| 75 | 77 | { XBF_FLUSH, "FLUSH" }, \ |
| @@ -80,6 +82,7 @@ typedef unsigned int xfs_buf_flags_t; · 4 unmodified lines | ||
| 80 | 82 | { _XBF_DELWRI_Q, "DELWRI_Q" }, \ |
| 81 | 83 | { _XBF_COMPOUND, "COMPOUND" } |
| 82 | 84 | |
| 85 | + | |
| 83 | 86 | /* |
| 84 | 87 | * Internal state flags. |
| 85 | 88 | */ |
| @@ -269,9 +272,6 @@ extern void xfs_buf_unlock(xfs_buf_t *); · 183 unmodified lines | ||
| 269 | 272 | |
| 270 | 273 | /* Buffer Read and Write Routines */ |
| 271 | 274 | extern int xfs_bwrite(struct xfs_buf *bp); |
| 272 | − | |
| 273 | −extern void xfsbdstrat(struct xfs_mount *, struct xfs_buf *); | |
| 274 | − | |
| 275 | 275 | extern void xfs_buf_ioend(xfs_buf_t *, int); |
| 276 | 276 | extern void xfs_buf_ioerror(xfs_buf_t *, int); |
| 277 | 277 | extern void xfs_buf_ioerror_alert(struct xfs_buf *, const char *func); |
| @@ -282,6 +282,8 @@ extern void xfs_buf_iomove(xfs_buf_t *, size_t, size_t, void *, · 4 unmodified lines | ||
| 282 | 282 | #define xfs_buf_zero(bp, off, len) \ |
| 283 | 283 | xfs_buf_iomove((bp), (off), (len), NULL, XBRW_ZERO) |
| 284 | 284 | |
| 285 | +extern int xfs_bioerror_relse(struct xfs_buf *); | |
| 286 | + | |
| 285 | 287 | static inline int xfs_buf_geterror(xfs_buf_t *bp) |
| 286 | 288 | { |
| 287 | 289 | return bp ? bp->b_error : ENOMEM; |
| @@ -301,7 +303,8 @@ extern void xfs_buf_terminate(void); · 13 unmodified lines | ||
| 301 | 303 | |
| 302 | 304 | #define XFS_BUF_ZEROFLAGS(bp) \ |
| 303 | 305 | ((bp)->b_flags &= ~(XBF_READ|XBF_WRITE|XBF_ASYNC| \ |
| 304 | − XBF_SYNCIO|XBF_FUA|XBF_FLUSH)) | |
| 306 | + XBF_SYNCIO|XBF_FUA|XBF_FLUSH| \ | |
| 307 | + XBF_WRITE_FAIL)) | |
| 305 | 308 | |
| 306 | 309 | void xfs_buf_stale(struct xfs_buf *bp); |
| 307 | 310 | #define XFS_BUF_UNSTALE(bp) ((bp)->b_flags &= ~XBF_STALE) |
| @@ -496,6 +496,14 @@ xfs_buf_item_unpin( · 495 unmodified lines | ||
| 496 | 496 | } |
| 497 | 497 | } |
| 498 | 498 | |
| 499 | +/* | |
| 500 | + * Buffer IO error rate limiting. Limit it to no more than 10 messages per 30 | |
| 501 | + * seconds so as to not spam logs too much on repeated detection of the same | |
| 502 | + * buffer being bad.. | |
| 503 | + */ | |
| 504 | + | |
| 505 | +DEFINE_RATELIMIT_STATE(xfs_buf_write_fail_rl_state, 30 * HZ, 10); | |
| 506 | + | |
| 499 | 507 | STATIC uint |
| 500 | 508 | xfs_buf_item_push( |
| 501 | 509 | struct xfs_log_item *lip, |
| @@ -524,6 +532,14 @@ xfs_buf_item_push( · 22 unmodified lines | ||
| 524 | 532 | |
| 525 | 533 | trace_xfs_buf_item_push(bip); |
| 526 | 534 | |
| 535 | + /* has a previous flush failed due to IO errors? */ | |
| 536 | + if ((bp->b_flags & XBF_WRITE_FAIL) && | |
| 537 | + ___ratelimit(&xfs_buf_write_fail_rl_state, "XFS:")) { | |
| 538 | + xfs_warn(bp->b_target->bt_mount, | |
| 539 | +"Detected failing async write on buffer block 0x%llx. Retrying async write.\n", | |
| 540 | + (long long)bp->b_bn); | |
| 541 | + } | |
| 542 | + | |
| 527 | 543 | if (!xfs_buf_delwri_queue(bp, buffer_list)) |
| 528 | 544 | rval = XFS_ITEM_FLUSHING; |
| 529 | 545 | xfs_buf_unlock(bp); |
| @@ -1096,8 +1112,9 @@ xfs_buf_iodone_callbacks( · 566 unmodified lines | ||
| 1096 | 1112 | |
| 1097 | 1113 | xfs_buf_ioerror(bp, 0); /* errno of 0 unsets the flag */ |
| 1098 | 1114 | |
| 1099 | − if (!XFS_BUF_ISSTALE(bp)) { | |
| 1100 | − bp->b_flags |= XBF_WRITE | XBF_ASYNC | XBF_DONE; | |
| 1115 | + if (!(bp->b_flags & (XBF_STALE|XBF_WRITE_FAIL))) { | |
| 1116 | + bp->b_flags |= XBF_WRITE | XBF_ASYNC | | |
| 1117 | + XBF_DONE | XBF_WRITE_FAIL; | |
| 1101 | 1118 | xfs_buf_iorequest(bp); |
| 1102 | 1119 | } else { |
| 1103 | 1120 | xfs_buf_relse(bp); |
| @@ -2067,12 +2067,12 @@ xfs_dir2_node_lookup( · 2066 unmodified lines | ||
| 2067 | 2067 | */ |
| 2068 | 2068 | int /* error */ |
| 2069 | 2069 | xfs_dir2_node_removename( |
| 2070 | − xfs_da_args_t *args) /* operation arguments */ | |
| 2070 | + struct xfs_da_args *args) /* operation arguments */ | |
| 2071 | 2071 | { |
| 2072 | − xfs_da_state_blk_t *blk; /* leaf block */ | |
| 2072 | + struct xfs_da_state_blk *blk; /* leaf block */ | |
| 2073 | 2073 | int error; /* error return value */ |
| 2074 | 2074 | int rval; /* operation return value */ |
| 2075 | − xfs_da_state_t *state; /* btree cursor */ | |
| 2075 | + struct xfs_da_state *state; /* btree cursor */ | |
| 2076 | 2076 | |
| 2077 | 2077 | trace_xfs_dir2_node_removename(args); |
| 2078 | 2078 | |
| @@ -2084,19 +2084,18 @@ xfs_dir2_node_removename( · 5 unmodified lines | ||
| 2084 | 2084 | state->mp = args->dp->i_mount; |
| 2085 | 2085 | state->blocksize = state->mp->m_dirblksize; |
| 2086 | 2086 | state->node_ents = state->mp->m_dir_node_ents; |
| 2087 | − /* | |
| 2088 | − * Look up the entry we're deleting, set up the cursor. | |
| 2089 | − */ | |
| 2087 | + | |
| 2088 | + /* Look up the entry we're deleting, set up the cursor. */ | |
| 2090 | 2089 | error = xfs_da3_node_lookup_int(state, &rval); |
| 2091 | 2090 | if (error) |
| 2092 | − rval = error; | |
| 2093 | − /* | |
| 2094 | − * Didn't find it, upper layer screwed up. | |
| 2095 | − */ | |
| 2091 | + goto out_free; | |
| 2092 | + | |
| 2093 | + /* Didn't find it, upper layer screwed up. */ | |
| 2096 | 2094 | if (rval != EEXIST) { |
| 2097 | − xfs_da_state_free(state); | |
| 2098 | − return rval; | |
| 2095 | + error = rval; | |
| 2096 | + goto out_free; | |
| 2099 | 2097 | } |
| 2098 | + | |
| 2100 | 2099 | blk = &state->path.blk[state->path.active - 1]; |
| 2101 | 2100 | ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); |
| 2102 | 2101 | ASSERT(state->extravalid); |
| @@ -2107,7 +2106,7 @@ xfs_dir2_node_removename( · 4 unmodified lines | ||
| 2107 | 2106 | error = xfs_dir2_leafn_remove(args, blk->bp, blk->index, |
| 2108 | 2107 | &state->extrablk, &rval); |
| 2109 | 2108 | if (error) |
| 2110 | − return error; | |
| 2109 | + goto out_free; | |
| 2111 | 2110 | /* |
| 2112 | 2111 | * Fix the hash values up the btree. |
| 2113 | 2112 | */ |
| @@ -2122,6 +2121,7 @@ xfs_dir2_node_removename( · 8 unmodified lines | ||
| 2122 | 2121 | */ |
| 2123 | 2122 | if (!error) |
| 2124 | 2123 | error = xfs_dir2_node_to_leaf(state); |
| 2124 | +out_free: | |
| 2125 | 2125 | xfs_da_state_free(state); |
| 2126 | 2126 | return error; |
| 2127 | 2127 | } |
| @@ -618,7 +618,8 @@ xfs_setattr_nonsize( · 617 unmodified lines | ||
| 618 | 618 | } |
| 619 | 619 | if (!gid_eq(igid, gid)) { |
| 620 | 620 | if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_GQUOTA_ON(mp)) { |
| 621 | − ASSERT(!XFS_IS_PQUOTA_ON(mp)); | |
| 621 | + ASSERT(xfs_sb_version_has_pquotino(&mp->m_sb) || | |
| 622 | + !XFS_IS_PQUOTA_ON(mp)); | |
| 622 | 623 | ASSERT(mask & ATTR_GID); |
| 623 | 624 | ASSERT(gdqp); |
| 624 | 625 | olddquot2 = xfs_qm_vop_chown(tp, ip, |
| @@ -193,7 +193,10 @@ xlog_bread_noalign( · 192 unmodified lines | ||
| 193 | 193 | bp->b_io_length = nbblks; |
| 194 | 194 | bp->b_error = 0; |
| 195 | 195 | |
| 196 | − xfsbdstrat(log->l_mp, bp); | |
| 196 | + if (XFS_FORCED_SHUTDOWN(log->l_mp)) | |
| 197 | + return XFS_ERROR(EIO); | |
| 198 | + | |
| 199 | + xfs_buf_iorequest(bp); | |
| 197 | 200 | error = xfs_buf_iowait(bp); |
| 198 | 201 | if (error) |
| 199 | 202 | xfs_buf_ioerror_alert(bp, __func__); |
| @@ -4397,7 +4400,13 @@ xlog_do_recover( · 4197 unmodified lines | ||
| 4397 | 4400 | XFS_BUF_READ(bp); |
| 4398 | 4401 | XFS_BUF_UNASYNC(bp); |
| 4399 | 4402 | bp->b_ops = &xfs_sb_buf_ops; |
| 4400 | − xfsbdstrat(log->l_mp, bp); | |
| 4403 | + | |
| 4404 | + if (XFS_FORCED_SHUTDOWN(log->l_mp)) { | |
| 4405 | + xfs_buf_relse(bp); | |
| 4406 | + return XFS_ERROR(EIO); | |
| 4407 | + } | |
| 4408 | + | |
| 4409 | + xfs_buf_iorequest(bp); | |
| 4401 | 4410 | error = xfs_buf_iowait(bp); |
| 4402 | 4411 | if (error) { |
| 4403 | 4412 | xfs_buf_ioerror_alert(bp, __func__); |
| @@ -134,8 +134,6 @@ xfs_qm_dqpurge( · 133 unmodified lines | ||
| 134 | 134 | { |
| 135 | 135 | struct xfs_mount *mp = dqp->q_mount; |
| 136 | 136 | struct xfs_quotainfo *qi = mp->m_quotainfo; |
| 137 | − struct xfs_dquot *gdqp = NULL; | |
| 138 | − struct xfs_dquot *pdqp = NULL; | |
| 139 | 137 | |
| 140 | 138 | xfs_dqlock(dqp); |
| 141 | 139 | if ((dqp->dq_flags & XFS_DQ_FREEING) || dqp->q_nrefs != 0) { |
| @@ -143,21 +141,6 @@ xfs_qm_dqpurge( · 1 unmodified line | ||
| 143 | 141 | return EAGAIN; |
| 144 | 142 | } |
| 145 | 143 | |
| 146 | − /* | |
| 147 | − * If this quota has a hint attached, prepare for releasing it now. | |
| 148 | − */ | |
| 149 | − gdqp = dqp->q_gdquot; | |
| 150 | − if (gdqp) { | |
| 151 | − xfs_dqlock(gdqp); | |
| 152 | − dqp->q_gdquot = NULL; | |
| 153 | − } | |
| 154 | − | |
| 155 | − pdqp = dqp->q_pdquot; | |
| 156 | − if (pdqp) { | |
| 157 | − xfs_dqlock(pdqp); | |
| 158 | − dqp->q_pdquot = NULL; | |
| 159 | − } | |
| 160 | − | |
| 161 | 144 | dqp->dq_flags |= XFS_DQ_FREEING; |
| 162 | 145 | |
| 163 | 146 | xfs_dqflock(dqp); |
| @@ -206,11 +189,47 @@ xfs_qm_dqpurge( · 42 unmodified lines | ||
| 206 | 189 | XFS_STATS_DEC(xs_qm_dquot_unused); |
| 207 | 190 | |
| 208 | 191 | xfs_qm_dqdestroy(dqp); |
| 192 | + return 0; | |
| 193 | +} | |
| 194 | + | |
| 195 | +/* | |
| 196 | + * Release the group or project dquot pointers the user dquots maybe carrying | |
| 197 | + * around as a hint, and proceed to purge the user dquot cache if requested. | |
| 198 | +*/ | |
| 199 | +STATIC int | |
| 200 | +xfs_qm_dqpurge_hints( | |
| 201 | + struct xfs_dquot *dqp, | |
| 202 | + void *data) | |
| 203 | +{ | |
| 204 | + struct xfs_dquot *gdqp = NULL; | |
| 205 | + struct xfs_dquot *pdqp = NULL; | |
| 206 | + uint flags = *((uint *)data); | |
| 207 | + | |
| 208 | + xfs_dqlock(dqp); | |
| 209 | + if (dqp->dq_flags & XFS_DQ_FREEING) { | |
| 210 | + xfs_dqunlock(dqp); | |
| 211 | + return EAGAIN; | |
| 212 | + } | |
| 213 | + | |
| 214 | + /* If this quota has a hint attached, prepare for releasing it now */ | |
| 215 | + gdqp = dqp->q_gdquot; | |
| 216 | + if (gdqp) | |
| 217 | + dqp->q_gdquot = NULL; | |
| 218 | + | |
| 219 | + pdqp = dqp->q_pdquot; | |
| 220 | + if (pdqp) | |
| 221 | + dqp->q_pdquot = NULL; | |
| 222 | + | |
| 223 | + xfs_dqunlock(dqp); | |
| 209 | 224 | |
| 210 | 225 | if (gdqp) |
| 211 | − xfs_qm_dqput(gdqp); | |
| 226 | + xfs_qm_dqrele(gdqp); | |
| 212 | 227 | if (pdqp) |
| 213 | − xfs_qm_dqput(pdqp); | |
| 228 | + xfs_qm_dqrele(pdqp); | |
| 229 | + | |
| 230 | + if (flags & XFS_QMOPT_UQUOTA) | |
| 231 | + return xfs_qm_dqpurge(dqp, NULL); | |
| 232 | + | |
| 214 | 233 | return 0; |
| 215 | 234 | } |
| 216 | 235 | |
| @@ -222,8 +241,18 @@ xfs_qm_dqpurge_all( · 5 unmodified lines | ||
| 222 | 241 | struct xfs_mount *mp, |
| 223 | 242 | uint flags) |
| 224 | 243 | { |
| 225 | − if (flags & XFS_QMOPT_UQUOTA) | |
| 226 | − xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_dqpurge, NULL); | |
| 244 | + /* | |
| 245 | + * We have to release group/project dquot hint(s) from the user dquot | |
| 246 | + * at first if they are there, otherwise we would run into an infinite | |
| 247 | + * loop while walking through radix tree to purge other type of dquots | |
| 248 | + * since their refcount is not zero if the user dquot refers to them | |
| 249 | + * as hint. | |
| 250 | + * | |
| 251 | + * Call the special xfs_qm_dqpurge_hints() will end up go through the | |
| 252 | + * general xfs_qm_dqpurge() against user dquot cache if requested. | |
| 253 | + */ | |
| 254 | + xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_dqpurge_hints, &flags); | |
| 255 | + | |
| 227 | 256 | if (flags & XFS_QMOPT_GQUOTA) |
| 228 | 257 | xfs_qm_dquot_walk(mp, XFS_DQ_GROUP, xfs_qm_dqpurge, NULL); |
| 229 | 258 | if (flags & XFS_QMOPT_PQUOTA) |
| @@ -2082,24 +2111,21 @@ xfs_qm_vop_create_dqattach( · 1852 unmodified lines | ||
| 2082 | 2111 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); |
| 2083 | 2112 | ASSERT(XFS_IS_QUOTA_RUNNING(mp)); |
| 2084 | 2113 | |
| 2085 | − if (udqp) { | |
| 2114 | + if (udqp && XFS_IS_UQUOTA_ON(mp)) { | |
| 2086 | 2115 | ASSERT(ip->i_udquot == NULL); |
| 2087 | − ASSERT(XFS_IS_UQUOTA_ON(mp)); | |
| 2088 | 2116 | ASSERT(ip->i_d.di_uid == be32_to_cpu(udqp->q_core.d_id)); |
| 2089 | 2117 | |
| 2090 | 2118 | ip->i_udquot = xfs_qm_dqhold(udqp); |
| 2091 | 2119 | xfs_trans_mod_dquot(tp, udqp, XFS_TRANS_DQ_ICOUNT, 1); |
| 2092 | 2120 | } |
| 2093 | − if (gdqp) { | |
| 2121 | + if (gdqp && XFS_IS_GQUOTA_ON(mp)) { | |
| 2094 | 2122 | ASSERT(ip->i_gdquot == NULL); |
| 2095 | − ASSERT(XFS_IS_GQUOTA_ON(mp)); | |
| 2096 | 2123 | ASSERT(ip->i_d.di_gid == be32_to_cpu(gdqp->q_core.d_id)); |
| 2097 | 2124 | ip->i_gdquot = xfs_qm_dqhold(gdqp); |
| 2098 | 2125 | xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1); |
| 2099 | 2126 | } |
| 2100 | − if (pdqp) { | |
| 2127 | + if (pdqp && XFS_IS_PQUOTA_ON(mp)) { | |
| 2101 | 2128 | ASSERT(ip->i_pdquot == NULL); |
| 2102 | − ASSERT(XFS_IS_PQUOTA_ON(mp)); | |
| 2103 | 2129 | ASSERT(xfs_get_projid(ip) == be32_to_cpu(pdqp->q_core.d_id)); |
| 2104 | 2130 | |
| 2105 | 2131 | ip->i_pdquot = xfs_qm_dqhold(pdqp); |
| @@ -314,7 +314,18 @@ xfs_trans_read_buf_map( · 313 unmodified lines | ||
| 314 | 314 | ASSERT(bp->b_iodone == NULL); |
| 315 | 315 | XFS_BUF_READ(bp); |
| 316 | 316 | bp->b_ops = ops; |
| 317 | − xfsbdstrat(tp->t_mountp, bp); | |
| 317 | + | |
| 318 | + /* | |
| 319 | + * XXX(hch): clean up the error handling here to be less | |
| 320 | + * of a mess.. | |
| 321 | + */ | |
| 322 | + if (XFS_FORCED_SHUTDOWN(mp)) { | |
| 323 | + trace_xfs_bdstrat_shut(bp, _RET_IP_); | |
| 324 | + xfs_bioerror_relse(bp); | |
| 325 | + } else { | |
| 326 | + xfs_buf_iorequest(bp); | |
| 327 | + } | |
| 328 | + | |
| 318 | 329 | error = xfs_buf_iowait(bp); |
| 319 | 330 | if (error) { |
| 320 | 331 | xfs_buf_ioerror_alert(bp, __func__); |