aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/xfs_log.c55
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 */
669int 672int
670xfs_log_write( 673xfs_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 */
3172STATIC xlog_ticket_t * 3175STATIC xlog_ticket_t *
3173xlog_ticket_alloc(xlog_t *log, 3176xlog_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