diff options
-rw-r--r-- | fs/xfs/xfs_log.c | 55 |
1 files changed, 42 insertions, 13 deletions
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 8556c59628ba..81323d73a4ee 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c | |||
@@ -664,7 +664,10 @@ xfs_log_item_init( | |||
664 | /* | 664 | /* |
665 | * Write region vectors to log. The write happens using the space reservation | 665 | * Write region vectors to log. The write happens using the space reservation |
666 | * of the ticket (tic). It is not a requirement that all writes for a given | 666 | * of the ticket (tic). It is not a requirement that all writes for a given |
667 | * transaction occur with one call to xfs_log_write(). | 667 | * transaction occur with one call to xfs_log_write(). However, it is important |
668 | * to note that the transaction reservation code makes an assumption about the | ||
669 | * number of log headers a transaction requires that may be violated if you | ||
670 | * don't pass all the transaction vectors in one call.... | ||
668 | */ | 671 | */ |
669 | int | 672 | int |
670 | xfs_log_write( | 673 | xfs_log_write( |
@@ -3170,14 +3173,16 @@ xfs_log_ticket_get( | |||
3170 | * Allocate and initialise a new log ticket. | 3173 | * Allocate and initialise a new log ticket. |
3171 | */ | 3174 | */ |
3172 | STATIC xlog_ticket_t * | 3175 | STATIC xlog_ticket_t * |
3173 | xlog_ticket_alloc(xlog_t *log, | 3176 | xlog_ticket_alloc( |
3174 | int unit_bytes, | 3177 | struct log *log, |
3175 | int cnt, | 3178 | int unit_bytes, |
3176 | char client, | 3179 | int cnt, |
3177 | uint xflags) | 3180 | char client, |
3181 | uint xflags) | ||
3178 | { | 3182 | { |
3179 | xlog_ticket_t *tic; | 3183 | struct xlog_ticket *tic; |
3180 | uint num_headers; | 3184 | uint num_headers; |
3185 | int iclog_space; | ||
3181 | 3186 | ||
3182 | tic = kmem_zone_zalloc(xfs_log_ticket_zone, KM_SLEEP|KM_MAYFAIL); | 3187 | tic = kmem_zone_zalloc(xfs_log_ticket_zone, KM_SLEEP|KM_MAYFAIL); |
3183 | if (!tic) | 3188 | if (!tic) |
@@ -3221,16 +3226,40 @@ xlog_ticket_alloc(xlog_t *log, | |||
3221 | /* for start-rec */ | 3226 | /* for start-rec */ |
3222 | unit_bytes += sizeof(xlog_op_header_t); | 3227 | unit_bytes += sizeof(xlog_op_header_t); |
3223 | 3228 | ||
3224 | /* for LR headers */ | 3229 | /* |
3225 | num_headers = ((unit_bytes + log->l_iclog_size-1) >> log->l_iclog_size_log); | 3230 | * for LR headers - the space for data in an iclog is the size minus |
3231 | * the space used for the headers. If we use the iclog size, then we | ||
3232 | * undercalculate the number of headers required. | ||
3233 | * | ||
3234 | * Furthermore - the addition of op headers for split-recs might | ||
3235 | * increase the space required enough to require more log and op | ||
3236 | * headers, so take that into account too. | ||
3237 | * | ||
3238 | * IMPORTANT: This reservation makes the assumption that if this | ||
3239 | * transaction is the first in an iclog and hence has the LR headers | ||
3240 | * accounted to it, then the remaining space in the iclog is | ||
3241 | * exclusively for this transaction. i.e. if the transaction is larger | ||
3242 | * than the iclog, it will be the only thing in that iclog. | ||
3243 | * Fundamentally, this means we must pass the entire log vector to | ||
3244 | * xlog_write to guarantee this. | ||
3245 | */ | ||
3246 | iclog_space = log->l_iclog_size - log->l_iclog_hsize; | ||
3247 | num_headers = howmany(unit_bytes, iclog_space); | ||
3248 | |||
3249 | /* for split-recs - ophdrs added when data split over LRs */ | ||
3250 | unit_bytes += sizeof(xlog_op_header_t) * num_headers; | ||
3251 | |||
3252 | /* add extra header reservations if we overrun */ | ||
3253 | while (!num_headers || | ||
3254 | howmany(unit_bytes, iclog_space) > num_headers) { | ||
3255 | unit_bytes += sizeof(xlog_op_header_t); | ||
3256 | num_headers++; | ||
3257 | } | ||
3226 | unit_bytes += log->l_iclog_hsize * num_headers; | 3258 | unit_bytes += log->l_iclog_hsize * num_headers; |
3227 | 3259 | ||
3228 | /* for commit-rec LR header - note: padding will subsume the ophdr */ | 3260 | /* for commit-rec LR header - note: padding will subsume the ophdr */ |
3229 | unit_bytes += log->l_iclog_hsize; | 3261 | unit_bytes += log->l_iclog_hsize; |
3230 | 3262 | ||
3231 | /* for split-recs - ophdrs added when data split over LRs */ | ||
3232 | unit_bytes += sizeof(xlog_op_header_t) * num_headers; | ||
3233 | |||
3234 | /* for roundoff padding for transaction data and one for commit record */ | 3263 | /* for roundoff padding for transaction data and one for commit record */ |
3235 | if (xfs_sb_version_haslogv2(&log->l_mp->m_sb) && | 3264 | if (xfs_sb_version_haslogv2(&log->l_mp->m_sb) && |
3236 | log->l_mp->m_sb.sb_logsunit > 1) { | 3265 | log->l_mp->m_sb.sb_logsunit > 1) { |
@@ -3252,7 +3281,7 @@ xlog_ticket_alloc(xlog_t *log, | |||
3252 | tic->t_trans_type = 0; | 3281 | tic->t_trans_type = 0; |
3253 | if (xflags & XFS_LOG_PERM_RESERV) | 3282 | if (xflags & XFS_LOG_PERM_RESERV) |
3254 | tic->t_flags |= XLOG_TIC_PERM_RESERV; | 3283 | tic->t_flags |= XLOG_TIC_PERM_RESERV; |
3255 | sv_init(&(tic->t_wait), SV_DEFAULT, "logtick"); | 3284 | sv_init(&tic->t_wait, SV_DEFAULT, "logtick"); |
3256 | 3285 | ||
3257 | xlog_tic_reset_res(tic); | 3286 | xlog_tic_reset_res(tic); |
3258 | 3287 | ||