aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_log_recover.c159
1 files changed, 152 insertions, 7 deletions
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 82f99b8ce07b..64e530e67053 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -3119,6 +3119,106 @@ xlog_recover_free_trans(
3119 kmem_free(trans); 3119 kmem_free(trans);
3120} 3120}
3121 3121
3122STATIC void
3123xlog_recover_buffer_ra_pass2(
3124 struct xlog *log,
3125 struct xlog_recover_item *item)
3126{
3127 struct xfs_buf_log_format *buf_f = item->ri_buf[0].i_addr;
3128 struct xfs_mount *mp = log->l_mp;
3129
3130 if (xlog_check_buffer_cancelled(log, buf_f->blf_blkno,
3131 buf_f->blf_len, buf_f->blf_flags)) {
3132 return;
3133 }
3134
3135 xfs_buf_readahead(mp->m_ddev_targp, buf_f->blf_blkno,
3136 buf_f->blf_len, NULL);
3137}
3138
3139STATIC void
3140xlog_recover_inode_ra_pass2(
3141 struct xlog *log,
3142 struct xlog_recover_item *item)
3143{
3144 struct xfs_inode_log_format ilf_buf;
3145 struct xfs_inode_log_format *ilfp;
3146 struct xfs_mount *mp = log->l_mp;
3147 int error;
3148
3149 if (item->ri_buf[0].i_len == sizeof(struct xfs_inode_log_format)) {
3150 ilfp = item->ri_buf[0].i_addr;
3151 } else {
3152 ilfp = &ilf_buf;
3153 memset(ilfp, 0, sizeof(*ilfp));
3154 error = xfs_inode_item_format_convert(&item->ri_buf[0], ilfp);
3155 if (error)
3156 return;
3157 }
3158
3159 if (xlog_check_buffer_cancelled(log, ilfp->ilf_blkno, ilfp->ilf_len, 0))
3160 return;
3161
3162 xfs_buf_readahead(mp->m_ddev_targp, ilfp->ilf_blkno,
3163 ilfp->ilf_len, &xfs_inode_buf_ops);
3164}
3165
3166STATIC void
3167xlog_recover_dquot_ra_pass2(
3168 struct xlog *log,
3169 struct xlog_recover_item *item)
3170{
3171 struct xfs_mount *mp = log->l_mp;
3172 struct xfs_disk_dquot *recddq;
3173 struct xfs_dq_logformat *dq_f;
3174 uint type;
3175
3176
3177 if (mp->m_qflags == 0)
3178 return;
3179
3180 recddq = item->ri_buf[1].i_addr;
3181 if (recddq == NULL)
3182 return;
3183 if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot))
3184 return;
3185
3186 type = recddq->d_flags & (XFS_DQ_USER | XFS_DQ_PROJ | XFS_DQ_GROUP);
3187 ASSERT(type);
3188 if (log->l_quotaoffs_flag & type)
3189 return;
3190
3191 dq_f = item->ri_buf[0].i_addr;
3192 ASSERT(dq_f);
3193 ASSERT(dq_f->qlf_len == 1);
3194
3195 xfs_buf_readahead(mp->m_ddev_targp, dq_f->qlf_blkno,
3196 dq_f->qlf_len, NULL);
3197}
3198
3199STATIC void
3200xlog_recover_ra_pass2(
3201 struct xlog *log,
3202 struct xlog_recover_item *item)
3203{
3204 switch (ITEM_TYPE(item)) {
3205 case XFS_LI_BUF:
3206 xlog_recover_buffer_ra_pass2(log, item);
3207 break;
3208 case XFS_LI_INODE:
3209 xlog_recover_inode_ra_pass2(log, item);
3210 break;
3211 case XFS_LI_DQUOT:
3212 xlog_recover_dquot_ra_pass2(log, item);
3213 break;
3214 case XFS_LI_EFI:
3215 case XFS_LI_EFD:
3216 case XFS_LI_QUOTAOFF:
3217 default:
3218 break;
3219 }
3220}
3221
3122STATIC int 3222STATIC int
3123xlog_recover_commit_pass1( 3223xlog_recover_commit_pass1(
3124 struct xlog *log, 3224 struct xlog *log,
@@ -3180,6 +3280,26 @@ xlog_recover_commit_pass2(
3180 } 3280 }
3181} 3281}
3182 3282
3283STATIC int
3284xlog_recover_items_pass2(
3285 struct xlog *log,
3286 struct xlog_recover *trans,
3287 struct list_head *buffer_list,
3288 struct list_head *item_list)
3289{
3290 struct xlog_recover_item *item;
3291 int error = 0;
3292
3293 list_for_each_entry(item, item_list, ri_list) {
3294 error = xlog_recover_commit_pass2(log, trans,
3295 buffer_list, item);
3296 if (error)
3297 return error;
3298 }
3299
3300 return error;
3301}
3302
3183/* 3303/*
3184 * Perform the transaction. 3304 * Perform the transaction.
3185 * 3305 *
@@ -3192,9 +3312,16 @@ xlog_recover_commit_trans(
3192 struct xlog_recover *trans, 3312 struct xlog_recover *trans,
3193 int pass) 3313 int pass)
3194{ 3314{
3195 int error = 0, error2; 3315 int error = 0;
3196 xlog_recover_item_t *item; 3316 int error2;
3197 LIST_HEAD (buffer_list); 3317 int items_queued = 0;
3318 struct xlog_recover_item *item;
3319 struct xlog_recover_item *next;
3320 LIST_HEAD (buffer_list);
3321 LIST_HEAD (ra_list);
3322 LIST_HEAD (done_list);
3323
3324 #define XLOG_RECOVER_COMMIT_QUEUE_MAX 100
3198 3325
3199 hlist_del(&trans->r_list); 3326 hlist_del(&trans->r_list);
3200 3327
@@ -3202,14 +3329,22 @@ xlog_recover_commit_trans(
3202 if (error) 3329 if (error)
3203 return error; 3330 return error;
3204 3331
3205 list_for_each_entry(item, &trans->r_itemq, ri_list) { 3332 list_for_each_entry_safe(item, next, &trans->r_itemq, ri_list) {
3206 switch (pass) { 3333 switch (pass) {
3207 case XLOG_RECOVER_PASS1: 3334 case XLOG_RECOVER_PASS1:
3208 error = xlog_recover_commit_pass1(log, trans, item); 3335 error = xlog_recover_commit_pass1(log, trans, item);
3209 break; 3336 break;
3210 case XLOG_RECOVER_PASS2: 3337 case XLOG_RECOVER_PASS2:
3211 error = xlog_recover_commit_pass2(log, trans, 3338 xlog_recover_ra_pass2(log, item);
3212 &buffer_list, item); 3339 list_move_tail(&item->ri_list, &ra_list);
3340 items_queued++;
3341 if (items_queued >= XLOG_RECOVER_COMMIT_QUEUE_MAX) {
3342 error = xlog_recover_items_pass2(log, trans,
3343 &buffer_list, &ra_list);
3344 list_splice_tail_init(&ra_list, &done_list);
3345 items_queued = 0;
3346 }
3347
3213 break; 3348 break;
3214 default: 3349 default:
3215 ASSERT(0); 3350 ASSERT(0);
@@ -3219,9 +3354,19 @@ xlog_recover_commit_trans(
3219 goto out; 3354 goto out;
3220 } 3355 }
3221 3356
3357out:
3358 if (!list_empty(&ra_list)) {
3359 if (!error)
3360 error = xlog_recover_items_pass2(log, trans,
3361 &buffer_list, &ra_list);
3362 list_splice_tail_init(&ra_list, &done_list);
3363 }
3364
3365 if (!list_empty(&done_list))
3366 list_splice_init(&done_list, &trans->r_itemq);
3367
3222 xlog_recover_free_trans(trans); 3368 xlog_recover_free_trans(trans);
3223 3369
3224out:
3225 error2 = xfs_buf_delwri_submit(&buffer_list); 3370 error2 = xfs_buf_delwri_submit(&buffer_list);
3226 return error ? error : error2; 3371 return error ? error : error2;
3227} 3372}