diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c index eff4a127188e5a5a0f9b6ec624dc1627e6dbd533..168b8798625f9736bcc5b9f820d1cad727958149 100644 --- a/fs/xfs/libxfs/xfs_defer.c +++ b/fs/xfs/libxfs/xfs_defer.c @@ -210,21 +210,18 @@ xfs_defer_create_intents( } } -/* Abort all the intents that were committed. */ -STATIC void -xfs_defer_trans_abort( - struct xfs_trans *tp, - struct list_head *dop_pending) +void +xfs_defer_pending_abort( + struct xfs_mount *mp, + struct list_head *dop_list) { struct xfs_defer_pending *dfp; const struct xfs_defer_op_type *ops; - trace_xfs_defer_trans_abort(tp, _RET_IP_); - /* Abort intent items that don't have a done item. */ - list_for_each_entry(dfp, dop_pending, dfp_list) { + list_for_each_entry(dfp, dop_list, dfp_list) { ops = defer_op_types[dfp->dfp_type]; - trace_xfs_defer_pending_abort(tp->t_mountp, dfp); + trace_xfs_defer_pending_abort(mp, dfp); if (dfp->dfp_intent && !dfp->dfp_done) { ops->abort_intent(dfp->dfp_intent); dfp->dfp_intent = NULL; @@ -232,6 +229,16 @@ xfs_defer_trans_abort( } } +/* Abort all the intents that were committed. */ +STATIC void +xfs_defer_trans_abort( + struct xfs_trans *tp, + struct list_head *dop_pending) +{ + trace_xfs_defer_trans_abort(tp, _RET_IP_); + xfs_defer_pending_abort(tp->t_mountp, dop_pending); +} + /* Roll a transaction so we can do some deferred op processing. */ STATIC int xfs_defer_trans_roll( @@ -706,6 +713,7 @@ xfs_defer_ops_capture_and_commit( /* Commit the transaction and add the capture structure to the list. */ error = xfs_trans_commit(tp); if (error) { + xfs_defer_pending_abort(mp, &dfc->dfc_dfops); xfs_defer_ops_release(mp, dfc); return error; } diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h index 05472f71fffe432b20613854bf7fc6e91abacc39..df0312679ca74bb50c43e9afe199d97bcffcf285 100644 --- a/fs/xfs/libxfs/xfs_defer.h +++ b/fs/xfs/libxfs/xfs_defer.h @@ -36,6 +36,7 @@ struct xfs_defer_pending { enum xfs_defer_ops_type dfp_type; }; +void xfs_defer_pending_abort(struct xfs_mount *mp, struct list_head *dop_list); void xfs_defer_add(struct xfs_trans *tp, enum xfs_defer_ops_type type, struct list_head *h); int xfs_defer_finish_noroll(struct xfs_trans **tp); diff --git a/fs/xfs/libxfs/xfs_log_recover.h b/fs/xfs/libxfs/xfs_log_recover.h index 32a8ab3da18371a1889489cd5f9a58c1d054f0fa..27732685b8aebed0ae21157c3effd8e8d20ef70f 100644 --- a/fs/xfs/libxfs/xfs_log_recover.h +++ b/fs/xfs/libxfs/xfs_log_recover.h @@ -18,6 +18,7 @@ enum xlog_recover_reorder { XLOG_REORDER_ITEM_LIST, XLOG_REORDER_INODE_BUFFER_LIST, XLOG_REORDER_CANCEL_LIST, + XLOG_REORDER_SB_BUFFER_LIST, }; struct xlog_recover_item_ops { diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c index d7ac96b137bdc2c94d367718e7982f6aefec31d5..af313e9bf55ec95add515610862589d77aead0fd 100644 --- a/fs/xfs/libxfs/xfs_sb.c +++ b/fs/xfs/libxfs/xfs_sb.c @@ -70,6 +70,8 @@ xfs_sb_version_to_features( /* optional V4 features */ if (sbp->sb_rblocks > 0) features |= XFS_FEAT_REALTIME; + if (sbp->sb_versionnum & XFS_SB_VERSION_NLINKBIT) + features |= XFS_FEAT_NLINK; if (sbp->sb_versionnum & XFS_SB_VERSION_ATTRBIT) features |= XFS_FEAT_ATTR; if (sbp->sb_versionnum & XFS_SB_VERSION_QUOTABIT) diff --git a/fs/xfs/xfs_buf_item_recover.c b/fs/xfs/xfs_buf_item_recover.c index 368937745f809b7ec9e15cd8fc3fca3c9f5e7a65..9cb79a494d06bf002745b35c32bb31feba67ef49 100644 --- a/fs/xfs/xfs_buf_item_recover.c +++ b/fs/xfs/xfs_buf_item_recover.c @@ -162,6 +162,8 @@ xlog_recover_buf_reorder( return XLOG_REORDER_CANCEL_LIST; if (buf_f->blf_flags & XFS_BLF_INODE_BUF) return XLOG_REORDER_INODE_BUFFER_LIST; + if (buf_f->blf_blkno == XFS_SB_DADDR) + return XLOG_REORDER_SB_BUFFER_LIST; return XLOG_REORDER_BUFFER_LIST; } diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c index 4ca3a7fcc001427edaeb49a6386e55e4c2033576..595450a99ae23b83dd5355a3ea89941c6b4d1307 100644 --- a/fs/xfs/xfs_fsmap.c +++ b/fs/xfs/xfs_fsmap.c @@ -746,6 +746,7 @@ xfs_getfsmap_datadev_bnobt( { struct xfs_alloc_rec_incore akeys[2]; + memset(akeys, 0, sizeof(akeys)); info->missing_owner = XFS_FMR_OWN_UNKNOWN; return __xfs_getfsmap_datadev(tp, keys, info, xfs_getfsmap_datadev_bnobt_query, &akeys[0]); diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index e81e052dcb7502bef54c6622ca15639d86dd49f2..68ad7113ac3922e8c8d2dfc7bc7d329402c4421f 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -76,7 +76,7 @@ xfs_growfs_data_private( error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata, XFS_GROWFS_SPACE_RES(mp), 0, XFS_TRANS_RESERVE, &tp); if (error) - return error; + goto destroy_perag; /* * Write new AG headers to disk. Non-transactional, but need to be @@ -167,6 +167,9 @@ xfs_growfs_data_private( out_trans_cancel: xfs_trans_cancel(tp); +destroy_perag: + if (nagcount > oagcount) + xfs_destroy_perag(mp, oagcount, nagcount); return error; } diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index 14e55a5e39b715522433eb217323b2b032d4cdfe..6847bbb5a735fc0fc4b0a9d668b0620801a36604 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c @@ -534,6 +534,12 @@ xfs_iget_cache_hit( if (!igrab(inode)) goto out_skip; + if (!(flags & XFS_IGET_DONTCACHE)) { + spin_lock(&inode->i_lock); + inode->i_state &= ~I_DONTCACHE; + spin_unlock(&inode->i_lock); + } + /* We've got a live one. */ spin_unlock(&ip->i_flags_lock); rcu_read_unlock(); diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 7d2a788b3e7ebcbbd95f720535897b7e0126e697..1ce9700ea68c0e4e1d50b6486aa974eb5cc97f8d 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -1879,6 +1879,9 @@ xlog_recover_reorder_trans( case XLOG_REORDER_BUFFER_LIST: list_move_tail(&item->ri_list, &buffer_list); break; + case XLOG_REORDER_SB_BUFFER_LIST: + list_move(&item->ri_list, &buffer_list); + break; case XLOG_REORDER_CANCEL_LIST: trace_xfs_log_recover_item_reorder_head(log, trans, item, pass); @@ -1942,6 +1945,25 @@ xlog_recover_items_pass2( return error; } +#define XLOG_RECOVER_COMMIT_QUEUE_MAX 100 +static inline bool +xlog_recover_should_pass2( + struct xlog_recover_item *item, + int items_queued) +{ + struct xfs_buf_log_format *buf_f; + + if (items_queued >= XLOG_RECOVER_COMMIT_QUEUE_MAX) + return true; + if (ITEM_TYPE(item) == XFS_LI_BUF) { + buf_f = item->ri_buf[0].i_addr; + if (buf_f->blf_blkno == XFS_SB_DADDR) + return true; + } + + return false; +} + /* * Perform the transaction. * @@ -1962,8 +1984,6 @@ xlog_recover_commit_trans( LIST_HEAD (ra_list); LIST_HEAD (done_list); - #define XLOG_RECOVER_COMMIT_QUEUE_MAX 100 - hlist_del_init(&trans->r_list); error = xlog_recover_reorder_trans(log, trans, pass); @@ -1983,7 +2003,7 @@ xlog_recover_commit_trans( item->ri_ops->ra_pass2(log, item); list_move_tail(&item->ri_list, &ra_list); items_queued++; - if (items_queued >= XLOG_RECOVER_COMMIT_QUEUE_MAX) { + if (xlog_recover_should_pass2(item, items_queued)) { error = xlog_recover_items_pass2(log, trans, buffer_list, &ra_list); list_splice_tail_init(&ra_list, &done_list); @@ -2494,6 +2514,7 @@ xlog_abort_defer_ops( list_for_each_entry_safe(dfc, next, capture_list, dfc_list) { list_del_init(&dfc->dfc_list); + xfs_defer_pending_abort(mp, &dfc->dfc_dfops); xfs_defer_ops_release(mp, dfc); } } diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 69888dd863d789e03ceeea3dfd2b991642df1347..8346441985b0e54ecf28baf20c605461e7e522ac 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -173,6 +173,27 @@ xfs_sb_validate_fsb_count( return 0; } +void +xfs_destroy_perag( + xfs_mount_t *mp, + xfs_agnumber_t agstart, + xfs_agnumber_t agend) +{ + xfs_agnumber_t index; + xfs_perag_t *pag; + + for (index = agstart; index < agend; index++) { + spin_lock(&mp->m_perag_lock); + pag = radix_tree_delete(&mp->m_perag_tree, index); + spin_unlock(&mp->m_perag_lock); + if (!pag) + break; + xfs_buf_hash_destroy(pag); + xfs_iunlink_destroy(pag); + kmem_free(pag); + } +} + int xfs_initialize_perag( xfs_mount_t *mp, @@ -252,14 +273,7 @@ xfs_initialize_perag( kmem_free(pag); out_unwind_new_pags: /* unwind any prior newly initialized pags */ - for (index = first_initialised; index < agcount; index++) { - pag = radix_tree_delete(&mp->m_perag_tree, index); - if (!pag) - break; - xfs_buf_hash_destroy(pag); - xfs_iunlink_destroy(pag); - kmem_free(pag); - } + xfs_destroy_perag(mp, first_initialised, agcount); return error; } diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index a4bdf24a070c38f3c7c7e985cecd43a837073d90..21547ff97b5a6782fae4c06f1b2fdec74acf2748 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -564,6 +564,8 @@ extern void xfs_uuid_table_free(void); extern int xfs_log_sbcount(xfs_mount_t *); extern uint64_t xfs_default_resblks(xfs_mount_t *mp); extern int xfs_mountfs(xfs_mount_t *mp); +extern void xfs_destroy_perag(xfs_mount_t *mp, xfs_agnumber_t agstart, + xfs_agnumber_t agend); extern int xfs_initialize_perag(xfs_mount_t *mp, xfs_agnumber_t agcount, xfs_agnumber_t *maxagi); extern void xfs_unmountfs(xfs_mount_t *);