diff options
Diffstat (limited to 'fs/xfs/xfs_log_cil.c')
-rw-r--r-- | fs/xfs/xfs_log_cil.c | 89 |
1 files changed, 35 insertions, 54 deletions
diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c index 5eb51fc5eb84..4ef6fdbced78 100644 --- a/fs/xfs/xfs_log_cil.c +++ b/fs/xfs/xfs_log_cil.c | |||
@@ -82,36 +82,6 @@ xlog_cil_init_post_recovery( | |||
82 | log->l_curr_block); | 82 | log->l_curr_block); |
83 | } | 83 | } |
84 | 84 | ||
85 | STATIC int | ||
86 | xlog_cil_lv_item_format( | ||
87 | struct xfs_log_item *lip, | ||
88 | struct xfs_log_vec *lv) | ||
89 | { | ||
90 | int index; | ||
91 | char *ptr; | ||
92 | |||
93 | /* format new vectors into array */ | ||
94 | lip->li_ops->iop_format(lip, lv->lv_iovecp); | ||
95 | |||
96 | /* copy data into existing array */ | ||
97 | ptr = lv->lv_buf; | ||
98 | for (index = 0; index < lv->lv_niovecs; index++) { | ||
99 | struct xfs_log_iovec *vec = &lv->lv_iovecp[index]; | ||
100 | |||
101 | memcpy(ptr, vec->i_addr, vec->i_len); | ||
102 | vec->i_addr = ptr; | ||
103 | ptr += vec->i_len; | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * some size calculations for log vectors over-estimate, so the caller | ||
108 | * doesn't know the amount of space actually used by the item. Return | ||
109 | * the byte count to the caller so they can check and store it | ||
110 | * appropriately. | ||
111 | */ | ||
112 | return ptr - lv->lv_buf; | ||
113 | } | ||
114 | |||
115 | /* | 85 | /* |
116 | * Prepare the log item for insertion into the CIL. Calculate the difference in | 86 | * Prepare the log item for insertion into the CIL. Calculate the difference in |
117 | * log space and vectors it will consume, and if it is a new item pin it as | 87 | * log space and vectors it will consume, and if it is a new item pin it as |
@@ -232,12 +202,28 @@ xlog_cil_insert_format_items( | |||
232 | nbytes = 0; | 202 | nbytes = 0; |
233 | } | 203 | } |
234 | 204 | ||
205 | /* | ||
206 | * We 64-bit align the length of each iovec so that the start | ||
207 | * of the next one is naturally aligned. We'll need to | ||
208 | * account for that slack space here. Then round nbytes up | ||
209 | * to 64-bit alignment so that the initial buffer alignment is | ||
210 | * easy to calculate and verify. | ||
211 | */ | ||
212 | nbytes += niovecs * sizeof(uint64_t); | ||
213 | nbytes = round_up(nbytes, sizeof(uint64_t)); | ||
214 | |||
235 | /* grab the old item if it exists for reservation accounting */ | 215 | /* grab the old item if it exists for reservation accounting */ |
236 | old_lv = lip->li_lv; | 216 | old_lv = lip->li_lv; |
237 | 217 | ||
238 | /* calc buffer size */ | 218 | /* |
239 | buf_size = sizeof(struct xfs_log_vec) + nbytes + | 219 | * The data buffer needs to start 64-bit aligned, so round up |
240 | niovecs * sizeof(struct xfs_log_iovec); | 220 | * that space to ensure we can align it appropriately and not |
221 | * overrun the buffer. | ||
222 | */ | ||
223 | buf_size = nbytes + | ||
224 | round_up((sizeof(struct xfs_log_vec) + | ||
225 | niovecs * sizeof(struct xfs_log_iovec)), | ||
226 | sizeof(uint64_t)); | ||
241 | 227 | ||
242 | /* compare to existing item size */ | 228 | /* compare to existing item size */ |
243 | if (lip->li_lv && buf_size <= lip->li_lv->lv_size) { | 229 | if (lip->li_lv && buf_size <= lip->li_lv->lv_size) { |
@@ -254,34 +240,29 @@ xlog_cil_insert_format_items( | |||
254 | */ | 240 | */ |
255 | *diff_iovecs -= lv->lv_niovecs; | 241 | *diff_iovecs -= lv->lv_niovecs; |
256 | *diff_len -= lv->lv_buf_len; | 242 | *diff_len -= lv->lv_buf_len; |
257 | 243 | } else { | |
258 | /* Ensure the lv is set up according to ->iop_size */ | 244 | /* allocate new data chunk */ |
259 | lv->lv_niovecs = niovecs; | 245 | lv = kmem_zalloc(buf_size, KM_SLEEP|KM_NOFS); |
260 | lv->lv_buf = (char *)lv + buf_size - nbytes; | 246 | lv->lv_item = lip; |
261 | 247 | lv->lv_size = buf_size; | |
262 | lv->lv_buf_len = xlog_cil_lv_item_format(lip, lv); | 248 | if (ordered) { |
263 | goto insert; | 249 | /* track as an ordered logvec */ |
250 | ASSERT(lip->li_lv == NULL); | ||
251 | lv->lv_buf_len = XFS_LOG_VEC_ORDERED; | ||
252 | goto insert; | ||
253 | } | ||
254 | lv->lv_iovecp = (struct xfs_log_iovec *)&lv[1]; | ||
264 | } | 255 | } |
265 | 256 | ||
266 | /* allocate new data chunk */ | 257 | /* Ensure the lv is set up according to ->iop_size */ |
267 | lv = kmem_zalloc(buf_size, KM_SLEEP|KM_NOFS); | ||
268 | lv->lv_item = lip; | ||
269 | lv->lv_size = buf_size; | ||
270 | lv->lv_niovecs = niovecs; | 258 | lv->lv_niovecs = niovecs; |
271 | if (ordered) { | ||
272 | /* track as an ordered logvec */ | ||
273 | ASSERT(lip->li_lv == NULL); | ||
274 | lv->lv_buf_len = XFS_LOG_VEC_ORDERED; | ||
275 | goto insert; | ||
276 | } | ||
277 | |||
278 | /* The allocated iovec region lies beyond the log vector. */ | ||
279 | lv->lv_iovecp = (struct xfs_log_iovec *)&lv[1]; | ||
280 | 259 | ||
281 | /* The allocated data region lies beyond the iovec region */ | 260 | /* The allocated data region lies beyond the iovec region */ |
261 | lv->lv_buf_len = 0; | ||
282 | lv->lv_buf = (char *)lv + buf_size - nbytes; | 262 | lv->lv_buf = (char *)lv + buf_size - nbytes; |
263 | ASSERT(IS_ALIGNED((unsigned long)lv->lv_buf, sizeof(uint64_t))); | ||
283 | 264 | ||
284 | lv->lv_buf_len = xlog_cil_lv_item_format(lip, lv); | 265 | lip->li_ops->iop_format(lip, lv); |
285 | insert: | 266 | insert: |
286 | ASSERT(lv->lv_buf_len <= nbytes); | 267 | ASSERT(lv->lv_buf_len <= nbytes); |
287 | xfs_cil_prepare_item(log, lv, old_lv, diff_len, diff_iovecs); | 268 | xfs_cil_prepare_item(log, lv, old_lv, diff_len, diff_iovecs); |