]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libxfs/trans.c
libxfs: fix xfs_trans_alloc_empty namespace
[thirdparty/xfsprogs-dev.git] / libxfs / trans.c
CommitLineData
2bd0ea18 1/*
f1b058f9 2 * Copyright (c) 2000-2001,2005-2006 Silicon Graphics, Inc.
4329aa4c 3 * Copyright (C) 2010 Red Hat, Inc.
da23017d 4 * All Rights Reserved.
2bd0ea18 5 *
da23017d
NS
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
2bd0ea18
NS
8 * published by the Free Software Foundation.
9 *
da23017d
NS
10 * This program is distributed in the hope that it would be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
2bd0ea18 14 *
da23017d
NS
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2bd0ea18
NS
18 */
19
9c799827 20#include "libxfs_priv.h"
b626fb59
DC
21#include "xfs_fs.h"
22#include "xfs_shared.h"
23#include "xfs_format.h"
24#include "xfs_log_format.h"
25#include "xfs_trans_resv.h"
26#include "xfs_mount.h"
27#include "xfs_inode_buf.h"
28#include "xfs_inode_fork.h"
29#include "xfs_inode.h"
30#include "xfs_trans.h"
31#include "xfs_sb.h"
2bd0ea18 32
7bcb8403
CH
33static void xfs_trans_free_items(struct xfs_trans *tp);
34
2bd0ea18
NS
35/*
36 * Simple transaction interface
37 */
38
4329aa4c
DC
39kmem_zone_t *xfs_log_item_desc_zone;
40
41/*
42 * Initialize the precomputed transaction reservation values
43 * in the mount structure.
44 */
45void
46libxfs_trans_init(
47 struct xfs_mount *mp)
48{
cf52c730 49 xfs_trans_resv_calc(mp, &mp->m_resv);
4329aa4c
DC
50}
51
52/*
53 * Add the given log item to the transaction's list of log items.
54 *
55 * The log item will now point to its new descriptor with its li_desc field.
56 */
57void
58libxfs_trans_add_item(
59 struct xfs_trans *tp,
60 struct xfs_log_item *lip)
61{
62 struct xfs_log_item_desc *lidp;
63
64 ASSERT(lip->li_mountp == tp->t_mountp);
65 ASSERT(lip->li_ailp == tp->t_mountp->m_ail);
66
67 lidp = calloc(sizeof(struct xfs_log_item_desc), 1);
68 if (!lidp) {
69 fprintf(stderr, _("%s: lidp calloc failed (%d bytes): %s\n"),
70 progname, (int)sizeof(struct xfs_log_item_desc),
71 strerror(errno));
72 exit(1);
73 }
74
75 lidp->lid_item = lip;
76 lidp->lid_flags = 0;
77 list_add_tail(&lidp->lid_trans, &tp->t_items);
78
79 lip->li_desc = lidp;
80}
81
82/*
83 * Unlink and free the given descriptor.
84 */
85void
86libxfs_trans_del_item(
87 struct xfs_log_item *lip)
88{
89 list_del_init(&lip->li_desc->lid_trans);
90 free(lip->li_desc);
91 lip->li_desc = NULL;
92}
93
94/*
95 * Roll from one trans in the sequence of PERMANENT transactions to
96 * the next: permanent transactions are only flushed out when
97 * committed with XFS_TRANS_RELEASE_LOG_RES, but we still want as soon
98 * as possible to let chunks of it go to the log. So we commit the
99 * chunk we've been working on and get a new transaction to continue.
100 */
101int
102libxfs_trans_roll(
103 struct xfs_trans **tpp,
104 struct xfs_inode *dp)
105{
87307113 106 struct xfs_mount *mp;
4329aa4c 107 struct xfs_trans *trans;
48ea6cb9 108 struct xfs_trans_res tres;
4329aa4c
DC
109 int error;
110
111 /*
112 * Ensure that the inode is always logged.
113 */
114 trans = *tpp;
d262295d
CH
115 if (dp)
116 xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE);
4329aa4c
DC
117
118 /*
119 * Copy the critical parameters from one trans to the next.
120 */
87307113 121 mp = trans->t_mountp;
48ea6cb9
DC
122 tres.tr_logres = trans->t_log_res;
123 tres.tr_logcount = trans->t_log_count;
4329aa4c
DC
124
125 /*
126 * Commit the current transaction.
127 * If this commit failed, then it'd just unlock those items that
260c85e8 128 * are marked to be released. That also means that a filesystem shutdown
4329aa4c
DC
129 * is in progress. The caller takes the responsibility to cancel
130 * the duplicate transaction that gets returned.
131 */
de5a3f46 132 error = xfs_trans_commit(trans);
4329aa4c 133 if (error)
af43ca9f 134 return error;
4329aa4c 135
4329aa4c
DC
136
137 /*
138 * Reserve space in the log for th next transaction.
139 * This also pushes items in the "AIL", the list of logged items,
140 * out to disk if they are taking up space at the tail of the log
141 * that we want to use. This requires that either nothing be locked
142 * across this call, or that anything that is locked be logged in
143 * the prior and the next transactions.
144 */
48ea6cb9 145 tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
87307113 146 error = libxfs_trans_alloc(mp, &tres, 0, 0, 0, tpp);
9074815c 147 trans = *tpp;
4329aa4c
DC
148 /*
149 * Ensure that the inode is in the new transaction and locked.
150 */
151 if (error)
152 return error;
153
d262295d
CH
154 if (dp)
155 xfs_trans_ijoin(trans, dp, 0);
4329aa4c
DC
156 return 0;
157}
158
9074815c 159int
ad10fb70 160libxfs_trans_alloc(
9074815c
CH
161 struct xfs_mount *mp,
162 struct xfs_trans_res *resp,
163 unsigned int blocks,
164 unsigned int rtextents,
165 unsigned int flags,
166 struct xfs_trans **tpp)
167
2bd0ea18 168{
9074815c
CH
169 struct xfs_sb *sb = &mp->m_sb;
170 struct xfs_trans *ptr;
171
172 /*
173 * Attempt to reserve the needed disk blocks by decrementing
174 * the number needed from the number available. This will
175 * fail if the count would go below zero.
176 */
177 if (blocks > 0) {
178 if (sb->sb_fdblocks < blocks)
179 return -ENOSPC;
180 }
2bd0ea18
NS
181
182 if ((ptr = calloc(sizeof(xfs_trans_t), 1)) == NULL) {
9440d84d 183 fprintf(stderr, _("%s: xact calloc failed (%d bytes): %s\n"),
5b64e00a 184 progname, (int)sizeof(xfs_trans_t), strerror(errno));
2bd0ea18
NS
185 exit(1);
186 }
187 ptr->t_mountp = mp;
c40bdaa2 188 INIT_LIST_HEAD(&ptr->t_items);
2bd0ea18
NS
189#ifdef XACT_DEBUG
190 fprintf(stderr, "allocated new transaction %p\n", ptr);
2bd0ea18 191#endif
9074815c 192 *tpp = ptr;
2bd0ea18
NS
193 return 0;
194}
195
d4e8eb2e
DW
196/*
197 * Create an empty transaction with no reservation. This is a defensive
198 * mechanism for routines that query metadata without actually modifying
199 * them -- if the metadata being queried is somehow cross-linked (think a
200 * btree block pointer that points higher in the tree), we risk deadlock.
201 * However, blocks grabbed as part of a transaction can be re-grabbed.
202 * The verifiers will notice the corrupt block and the operation will fail
203 * back to userspace without deadlocking.
204 *
205 * Note the zero-length reservation; this transaction MUST be cancelled
206 * without any dirty data.
207 */
208int
3680a764 209libxfs_trans_alloc_empty(
d4e8eb2e
DW
210 struct xfs_mount *mp,
211 struct xfs_trans **tpp)
212{
213 struct xfs_trans_res resv = {0};
214
215 return xfs_trans_alloc(mp, &resv, 0, 0, XFS_TRANS_NO_WRITECOUNT, tpp);
216}
217
2bd0ea18 218void
ad10fb70 219libxfs_trans_cancel(
3d7434fe 220 xfs_trans_t *tp)
2bd0ea18
NS
221{
222#ifdef XACT_DEBUG
ad10fb70 223 xfs_trans_t *otp = tp;
2bd0ea18
NS
224#endif
225 if (tp != NULL) {
7bcb8403 226 xfs_trans_free_items(tp);
2bd0ea18
NS
227 free(tp);
228 tp = NULL;
229 }
230#ifdef XACT_DEBUG
231 fprintf(stderr, "## cancelled transaction %p\n", otp);
232#endif
233}
234
235int
ad10fb70
NS
236libxfs_trans_iget(
237 xfs_mount_t *mp,
238 xfs_trans_t *tp,
239 xfs_ino_t ino,
46eca962 240 uint flags,
ad10fb70
NS
241 uint lock_flags,
242 xfs_inode_t **ipp)
2bd0ea18
NS
243{
244 int error;
245 xfs_inode_t *ip;
246 xfs_inode_log_item_t *iip;
247
248 if (tp == NULL)
81f8132a 249 return libxfs_iget(mp, tp, ino, lock_flags, ipp);
2bd0ea18 250
81f8132a 251 error = libxfs_iget(mp, tp, ino, lock_flags, &ip);
2bd0ea18
NS
252 if (error)
253 return error;
254 ASSERT(ip != NULL);
255
256 if (ip->i_itemp == NULL)
257 xfs_inode_item_init(ip, mp);
258 iip = ip->i_itemp;
259 xfs_trans_add_item(tp, (xfs_log_item_t *)(iip));
260
261 /* initialize i_transp so we can find it incore */
262 ip->i_transp = tp;
263
264 *ipp = ip;
265 return 0;
266}
267
2bd0ea18 268void
ad10fb70
NS
269libxfs_trans_ijoin(
270 xfs_trans_t *tp,
271 xfs_inode_t *ip,
272 uint lock_flags)
2bd0ea18
NS
273{
274 xfs_inode_log_item_t *iip;
275
276 ASSERT(ip->i_transp == NULL);
277 if (ip->i_itemp == NULL)
278 xfs_inode_item_init(ip, ip->i_mount);
279 iip = ip->i_itemp;
280 ASSERT(iip->ili_flags == 0);
281 ASSERT(iip->ili_inode != NULL);
282
283 xfs_trans_add_item(tp, (xfs_log_item_t *)(iip));
284
285 ip->i_transp = tp;
286#ifdef XACT_DEBUG
287 fprintf(stderr, "ijoin'd inode %llu, transaction %p\n", ip->i_ino, tp);
288#endif
289}
290
c40bdaa2
DC
291void
292libxfs_trans_ijoin_ref(
293 xfs_trans_t *tp,
294 xfs_inode_t *ip,
295 int lock_flags)
296{
297 ASSERT(ip->i_transp == tp);
298 ASSERT(ip->i_itemp != NULL);
299
300 xfs_trans_ijoin(tp, ip, lock_flags);
c40bdaa2
DC
301
302#ifdef XACT_DEBUG
303 fprintf(stderr, "ijoin_ref'd inode %llu, transaction %p\n", ip->i_ino, tp);
304#endif
305}
306
2bd0ea18 307void
ad10fb70
NS
308libxfs_trans_inode_alloc_buf(
309 xfs_trans_t *tp,
310 xfs_buf_t *bp)
2bd0ea18
NS
311{
312 xfs_buf_log_item_t *bip;
313
314 ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp);
315 ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
316 bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
317 bip->bli_flags |= XFS_BLI_INODE_ALLOC_BUF;
bdc16ee5 318 xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DINO_BUF);
2bd0ea18
NS
319}
320
321/*
322 * This is called to mark the fields indicated in fieldmask as needing
323 * to be logged when the transaction is committed. The inode must
324 * already be associated with the given transaction.
325 *
2d4bfb91 326 * The values for fieldmask are defined in xfs_log_format.h. We always
2bd0ea18
NS
327 * log all of the core inode if any of it has changed, and we always log
328 * all of the inline data/extents/b-tree root if any of them has changed.
329 */
330void
331xfs_trans_log_inode(
ad10fb70
NS
332 xfs_trans_t *tp,
333 xfs_inode_t *ip,
334 uint flags)
2bd0ea18 335{
2bd0ea18
NS
336 ASSERT(ip->i_transp == tp);
337 ASSERT(ip->i_itemp != NULL);
338#ifdef XACT_DEBUG
339 fprintf(stderr, "dirtied inode %llu, transaction %p\n", ip->i_ino, tp);
340#endif
341
2bd0ea18 342 tp->t_flags |= XFS_TRANS_DIRTY;
c40bdaa2 343 ip->i_itemp->ili_item.li_desc->lid_flags |= XFS_LID_DIRTY;
2bd0ea18
NS
344
345 /*
346 * Always OR in the bits from the ili_last_fields field.
347 * This is to coordinate with the xfs_iflush() and xfs_iflush_done()
348 * routines in the eventual clearing of the ilf_fields bits.
349 * See the big comment in xfs_iflush() for an explanation of
350 * this coordination mechanism.
351 */
352 flags |= ip->i_itemp->ili_last_fields;
a2ceac1f 353 ip->i_itemp->ili_fields |= flags;
2bd0ea18
NS
354}
355
356/*
357 * This is called to mark bytes first through last inclusive of the given
358 * buffer as needing to be logged when the transaction is committed.
359 * The buffer must already be associated with the given transaction.
5000d01d 360 *
2bd0ea18
NS
361 * First and last are numbers relative to the beginning of this buffer,
362 * so the first byte in the buffer is numbered 0 regardless of the
363 * value of b_blkno.
364 */
365void
ad10fb70
NS
366libxfs_trans_log_buf(
367 xfs_trans_t *tp,
368 xfs_buf_t *bp,
369 uint first,
370 uint last)
2bd0ea18
NS
371{
372 xfs_buf_log_item_t *bip;
2bd0ea18
NS
373
374 ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp);
375 ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
376 ASSERT((first <= last) && (last < XFS_BUF_COUNT(bp)));
377#ifdef XACT_DEBUG
378 fprintf(stderr, "dirtied buffer %p, transaction %p\n", bp, tp);
379#endif
380
381 bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
382
2bd0ea18 383 tp->t_flags |= XFS_TRANS_DIRTY;
c40bdaa2 384 bip->bli_item.li_desc->lid_flags |= XFS_LID_DIRTY;
2bd0ea18
NS
385 xfs_buf_item_log(bip, first, last);
386}
387
388void
ad10fb70
NS
389libxfs_trans_brelse(
390 xfs_trans_t *tp,
391 xfs_buf_t *bp)
2bd0ea18
NS
392{
393 xfs_buf_log_item_t *bip;
2bd0ea18
NS
394#ifdef XACT_DEBUG
395 fprintf(stderr, "released buffer %p, transaction %p\n", bp, tp);
396#endif
397
398 if (tp == NULL) {
399 ASSERT(XFS_BUF_FSPRIVATE2(bp, void *) == NULL);
400 libxfs_putbuf(bp);
401 return;
402 }
403 ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp);
404 bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
405 ASSERT(bip->bli_item.li_type == XFS_LI_BUF);
2bd0ea18
NS
406 if (bip->bli_recur > 0) {
407 bip->bli_recur--;
408 return;
409 }
f1b058f9
NS
410 /* If dirty/stale, can't release till transaction committed */
411 if (bip->bli_flags & XFS_BLI_STALE)
412 return;
c40bdaa2 413 if (bip->bli_item.li_desc->lid_flags & XFS_LID_DIRTY)
2bd0ea18 414 return;
c40bdaa2 415 xfs_trans_del_item(&bip->bli_item);
f1b058f9 416 if (bip->bli_flags & XFS_BLI_HOLD)
2bd0ea18 417 bip->bli_flags &= ~XFS_BLI_HOLD;
2bd0ea18
NS
418 XFS_BUF_SET_FSPRIVATE2(bp, NULL);
419 libxfs_putbuf(bp);
420}
421
422void
ad10fb70
NS
423libxfs_trans_binval(
424 xfs_trans_t *tp,
425 xfs_buf_t *bp)
2bd0ea18 426{
2bd0ea18
NS
427 xfs_buf_log_item_t *bip;
428#ifdef XACT_DEBUG
429 fprintf(stderr, "binval'd buffer %p, transaction %p\n", bp, tp);
430#endif
431
432 ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp);
433 ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
434
435 bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
f1b058f9
NS
436 if (bip->bli_flags & XFS_BLI_STALE)
437 return;
438 XFS_BUF_UNDELAYWRITE(bp);
a2ceac1f 439 xfs_buf_stale(bp);
f1b058f9
NS
440 bip->bli_flags |= XFS_BLI_STALE;
441 bip->bli_flags &= ~XFS_BLI_DIRTY;
c40bdaa2
DC
442 bip->bli_format.blf_flags &= ~XFS_BLF_INODE_BUF;
443 bip->bli_format.blf_flags |= XFS_BLF_CANCEL;
444 bip->bli_item.li_desc->lid_flags |= XFS_LID_DIRTY;
2bd0ea18
NS
445 tp->t_flags |= XFS_TRANS_DIRTY;
446}
447
448void
ad10fb70
NS
449libxfs_trans_bjoin(
450 xfs_trans_t *tp,
451 xfs_buf_t *bp)
2bd0ea18
NS
452{
453 xfs_buf_log_item_t *bip;
454
455 ASSERT(XFS_BUF_FSPRIVATE2(bp, void *) == NULL);
456#ifdef XACT_DEBUG
457 fprintf(stderr, "bjoin'd buffer %p, transaction %p\n", bp, tp);
458#endif
459
460 xfs_buf_item_init(bp, tp->t_mountp);
461 bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
462 xfs_trans_add_item(tp, (xfs_log_item_t *)bip);
463 XFS_BUF_SET_FSPRIVATE2(bp, tp);
464}
465
466void
ad10fb70
NS
467libxfs_trans_bhold(
468 xfs_trans_t *tp,
469 xfs_buf_t *bp)
2bd0ea18
NS
470{
471 xfs_buf_log_item_t *bip;
472
473 ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp);
474 ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
475#ifdef XACT_DEBUG
476 fprintf(stderr, "bhold'd buffer %p, transaction %p\n", bp, tp);
477#endif
478
479 bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
480 bip->bli_flags |= XFS_BLI_HOLD;
481}
482
483xfs_buf_t *
a2ceac1f 484libxfs_trans_get_buf_map(
ad10fb70 485 xfs_trans_t *tp,
75c8b434 486 struct xfs_buftarg *btp,
a2ceac1f
DC
487 struct xfs_buf_map *map,
488 int nmaps,
ad10fb70 489 uint f)
2bd0ea18
NS
490{
491 xfs_buf_t *bp;
492 xfs_buf_log_item_t *bip;
2bd0ea18
NS
493
494 if (tp == NULL)
7e3ab890 495 return libxfs_getbuf_map(btp, map, nmaps, 0);
2bd0ea18 496
75c8b434 497 bp = xfs_trans_buf_item_match(tp, btp, map, nmaps);
2bd0ea18
NS
498 if (bp != NULL) {
499 ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp);
500 bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
501 ASSERT(bip != NULL);
502 bip->bli_recur++;
503 return bp;
504 }
505
7e3ab890 506 bp = libxfs_getbuf_map(btp, map, nmaps, 0);
2bd0ea18
NS
507 if (bp == NULL)
508 return NULL;
509#ifdef XACT_DEBUG
510 fprintf(stderr, "trans_get_buf buffer %p, transaction %p\n", bp, tp);
511#endif
512
513 xfs_buf_item_init(bp, tp->t_mountp);
514 bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*);
515 bip->bli_recur = 0;
516 xfs_trans_add_item(tp, (xfs_log_item_t *)bip);
517
518 /* initialize b_fsprivate2 so we can find it incore */
519 XFS_BUF_SET_FSPRIVATE2(bp, tp);
520 return bp;
521}
522
f1b058f9
NS
523xfs_buf_t *
524libxfs_trans_getsb(
525 xfs_trans_t *tp,
526 xfs_mount_t *mp,
527 int flags)
528{
529 xfs_buf_t *bp;
530 xfs_buf_log_item_t *bip;
a2ceac1f
DC
531 int len = XFS_FSS_TO_BB(mp, 1);
532 DEFINE_SINGLE_BUF_MAP(map, XFS_SB_DADDR, len);
f1b058f9
NS
533
534 if (tp == NULL)
535 return libxfs_getsb(mp, flags);
536
a2ceac1f 537 bp = xfs_trans_buf_item_match(tp, mp->m_dev, &map, 1);
f1b058f9
NS
538 if (bp != NULL) {
539 ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp);
540 bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
541 ASSERT(bip != NULL);
542 bip->bli_recur++;
543 return bp;
544 }
545
546 bp = libxfs_getsb(mp, flags);
547#ifdef XACT_DEBUG
548 fprintf(stderr, "trans_get_sb buffer %p, transaction %p\n", bp, tp);
549#endif
550
551 xfs_buf_item_init(bp, mp);
552 bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*);
553 bip->bli_recur = 0;
554 xfs_trans_add_item(tp, (xfs_log_item_t *)bip);
555
556 /* initialize b_fsprivate2 so we can find it incore */
557 XFS_BUF_SET_FSPRIVATE2(bp, tp);
558 return bp;
559}
560
2bd0ea18 561int
a2ceac1f 562libxfs_trans_read_buf_map(
ad10fb70
NS
563 xfs_mount_t *mp,
564 xfs_trans_t *tp,
75c8b434 565 struct xfs_buftarg *btp,
a2ceac1f
DC
566 struct xfs_buf_map *map,
567 int nmaps,
f1b058f9 568 uint flags,
a2ceac1f
DC
569 xfs_buf_t **bpp,
570 const struct xfs_buf_ops *ops)
2bd0ea18
NS
571{
572 xfs_buf_t *bp;
573 xfs_buf_log_item_t *bip;
a6a7776a 574 int error;
2bd0ea18 575
00aea09f
CH
576 *bpp = NULL;
577
2bd0ea18 578 if (tp == NULL) {
75c8b434 579 bp = libxfs_readbuf_map(btp, map, nmaps, flags, ops);
00aea09f 580 if (!bp) {
12b53197 581 return (flags & XBF_TRYLOCK) ? -EAGAIN : -ENOMEM;
00aea09f 582 }
a6a7776a
CH
583 if (bp->b_error)
584 goto out_relse;
00aea09f 585 goto done;
2bd0ea18
NS
586 }
587
75c8b434 588 bp = xfs_trans_buf_item_match(tp, btp, map, nmaps);
2bd0ea18
NS
589 if (bp != NULL) {
590 ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp);
591 ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
592 bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*);
593 bip->bli_recur++;
00aea09f 594 goto done;
2bd0ea18
NS
595 }
596
75c8b434 597 bp = libxfs_readbuf_map(btp, map, nmaps, flags, ops);
00aea09f 598 if (!bp) {
12b53197 599 return (flags & XBF_TRYLOCK) ? -EAGAIN : -ENOMEM;
00aea09f 600 }
a6a7776a
CH
601 if (bp->b_error)
602 goto out_relse;
00aea09f 603
2bd0ea18
NS
604#ifdef XACT_DEBUG
605 fprintf(stderr, "trans_read_buf buffer %p, transaction %p\n", bp, tp);
606#endif
607
608 xfs_buf_item_init(bp, tp->t_mountp);
609 bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
610 bip->bli_recur = 0;
611 xfs_trans_add_item(tp, (xfs_log_item_t *)bip);
612
613 /* initialise b_fsprivate2 so we can find it incore */
614 XFS_BUF_SET_FSPRIVATE2(bp, tp);
00aea09f 615done:
2bd0ea18
NS
616 *bpp = bp;
617 return 0;
a6a7776a
CH
618out_relse:
619 error = bp->b_error;
620 xfs_buf_relse(bp);
621 return error;
2bd0ea18
NS
622}
623
624/*
625 * Record the indicated change to the given field for application
626 * to the file system's superblock when the transaction commits.
627 * For now, just store the change in the transaction structure.
628 * Mark the transaction structure to indicate that the superblock
5000d01d 629 * needs to be updated before committing.
2bd0ea18
NS
630 *
631 * Originally derived from xfs_trans_mod_sb().
632 */
633void
ad10fb70
NS
634libxfs_trans_mod_sb(
635 xfs_trans_t *tp,
636 uint field,
637 long delta)
2bd0ea18
NS
638{
639 switch (field) {
640 case XFS_TRANS_SB_RES_FDBLOCKS:
641 return;
642 case XFS_TRANS_SB_FDBLOCKS:
643 tp->t_fdblocks_delta += delta;
644 break;
645 case XFS_TRANS_SB_ICOUNT:
646 ASSERT(delta > 0);
647 tp->t_icount_delta += delta;
648 break;
649 case XFS_TRANS_SB_IFREE:
650 tp->t_ifree_delta += delta;
651 break;
652 case XFS_TRANS_SB_FREXTENTS:
653 tp->t_frextents_delta += delta;
654 break;
655 default:
656 ASSERT(0);
657 return;
658 }
659 tp->t_flags |= (XFS_TRANS_SB_DIRTY | XFS_TRANS_DIRTY);
660}
661
662
663/*
664 * Transaction commital code follows (i.e. write to disk in libxfs)
665 */
666
5e656dbb 667static void
ad10fb70
NS
668inode_item_done(
669 xfs_inode_log_item_t *iip)
2bd0ea18 670{
ad10fb70
NS
671 xfs_dinode_t *dip;
672 xfs_inode_t *ip;
673 xfs_mount_t *mp;
674 xfs_buf_t *bp;
ad10fb70 675 int error;
2bd0ea18
NS
676
677 ip = iip->ili_inode;
678 mp = iip->ili_item.li_mountp;
2bd0ea18
NS
679 ASSERT(ip != NULL);
680
a2ceac1f 681 if (!(iip->ili_fields & XFS_ILOG_ALL)) {
2bd0ea18
NS
682 ip->i_transp = NULL; /* disassociate from transaction */
683 iip->ili_flags = 0; /* reset all flags */
260c85e8 684 return;
2bd0ea18
NS
685 }
686
687 /*
688 * Get the buffer containing the on-disk inode.
689 */
a2ceac1f 690 error = xfs_imap_to_bp(mp, NULL, &ip->i_imap, &dip, &bp, 0, 0);
2bd0ea18 691 if (error) {
a2ceac1f 692 fprintf(stderr, _("%s: warning - imap_to_bp failed (%d)\n"),
2bd0ea18 693 progname, error);
260c85e8 694 return;
2bd0ea18
NS
695 }
696
697 XFS_BUF_SET_FSPRIVATE(bp, iip);
698 error = libxfs_iflush_int(ip, bp);
699 if (error) {
9440d84d 700 fprintf(stderr, _("%s: warning - iflush_int failed (%d)\n"),
2bd0ea18 701 progname, error);
260c85e8 702 return;
2bd0ea18
NS
703 }
704
705 ip->i_transp = NULL; /* disassociate from transaction */
706 XFS_BUF_SET_FSPRIVATE(bp, NULL); /* remove log item */
707 XFS_BUF_SET_FSPRIVATE2(bp, NULL); /* remove xact ptr */
f1b058f9 708 libxfs_writebuf(bp, 0);
2bd0ea18 709#ifdef XACT_DEBUG
260c85e8
MT
710 fprintf(stderr, "flushing dirty inode %llu, buffer %p\n",
711 ip->i_ino, bp);
2bd0ea18 712#endif
2bd0ea18
NS
713}
714
5e656dbb 715static void
ad10fb70
NS
716buf_item_done(
717 xfs_buf_log_item_t *bip)
2bd0ea18 718{
ad10fb70
NS
719 xfs_buf_t *bp;
720 int hold;
5e656dbb 721 extern kmem_zone_t *xfs_buf_item_zone;
2bd0ea18
NS
722
723 bp = bip->bli_buf;
724 ASSERT(bp != NULL);
725 XFS_BUF_SET_FSPRIVATE(bp, NULL); /* remove log item */
726 XFS_BUF_SET_FSPRIVATE2(bp, NULL); /* remove xact ptr */
727
728 hold = (bip->bli_flags & XFS_BLI_HOLD);
2556c98b 729 if (bip->bli_flags & XFS_BLI_DIRTY) {
2bd0ea18 730#ifdef XACT_DEBUG
f1b058f9 731 fprintf(stderr, "flushing/staling buffer %p (hold=%d)\n",
2bd0ea18
NS
732 bp, hold);
733#endif
2556c98b 734 libxfs_writebuf_int(bp, 0);
2bd0ea18 735 }
2556c98b
BN
736 if (hold)
737 bip->bli_flags &= ~XFS_BLI_HOLD;
738 else
739 libxfs_putbuf(bp);
2bd0ea18
NS
740 /* release the buf item */
741 kmem_zone_free(xfs_buf_item_zone, bip);
742}
743
2bd0ea18 744static void
c40bdaa2
DC
745trans_committed(
746 xfs_trans_t *tp)
2bd0ea18 747{
c40bdaa2
DC
748 struct xfs_log_item_desc *lidp, *next;
749
750 list_for_each_entry_safe(lidp, next, &tp->t_items, lid_trans) {
751 struct xfs_log_item *lip = lidp->lid_item;
752
753 xfs_trans_del_item(lip);
a2ceac1f 754
2bd0ea18 755 if (lip->li_type == XFS_LI_BUF)
c40bdaa2 756 buf_item_done((xfs_buf_log_item_t *)lip);
2bd0ea18 757 else if (lip->li_type == XFS_LI_INODE)
c40bdaa2 758 inode_item_done((xfs_inode_log_item_t *)lip);
2bd0ea18 759 else {
9440d84d 760 fprintf(stderr, _("%s: unrecognised log item type\n"),
2bd0ea18
NS
761 progname);
762 ASSERT(0);
763 }
c40bdaa2 764 }
2bd0ea18
NS
765}
766
5e656dbb 767static void
1bab604b
NS
768buf_item_unlock(
769 xfs_buf_log_item_t *bip)
770{
771 xfs_buf_t *bp = bip->bli_buf;
772 uint hold;
773
774 /* Clear the buffer's association with this transaction. */
775 XFS_BUF_SET_FSPRIVATE2(bip->bli_buf, NULL);
776
777 hold = bip->bli_flags & XFS_BLI_HOLD;
c40bdaa2 778 bip->bli_flags &= ~XFS_BLI_HOLD;
1bab604b
NS
779 if (!hold)
780 libxfs_putbuf(bp);
1bab604b
NS
781}
782
5e656dbb 783static void
1bab604b
NS
784inode_item_unlock(
785 xfs_inode_log_item_t *iip)
786{
787 xfs_inode_t *ip = iip->ili_inode;
1bab604b
NS
788
789 /* Clear the transaction pointer in the inode. */
790 ip->i_transp = NULL;
791
1bab604b
NS
792 iip->ili_flags = 0;
793}
794
2bd0ea18 795/*
c40bdaa2
DC
796 * Unlock all of the items of a transaction and free all the descriptors
797 * of that transaction.
2bd0ea18 798 */
7bcb8403 799static void
c40bdaa2 800xfs_trans_free_items(
7bcb8403 801 struct xfs_trans *tp)
2bd0ea18 802{
c40bdaa2 803 struct xfs_log_item_desc *lidp, *next;
2bd0ea18 804
c40bdaa2
DC
805 list_for_each_entry_safe(lidp, next, &tp->t_items, lid_trans) {
806 struct xfs_log_item *lip = lidp->lid_item;
807
808 xfs_trans_del_item(lip);
1bab604b 809 if (lip->li_type == XFS_LI_BUF)
c40bdaa2 810 buf_item_unlock((xfs_buf_log_item_t *)lip);
1bab604b 811 else if (lip->li_type == XFS_LI_INODE)
c40bdaa2 812 inode_item_unlock((xfs_inode_log_item_t *)lip);
2bd0ea18 813 else {
9440d84d 814 fprintf(stderr, _("%s: unrecognised log item type\n"),
2bd0ea18
NS
815 progname);
816 ASSERT(0);
817 }
2bd0ea18 818 }
2bd0ea18
NS
819}
820
2bd0ea18
NS
821/*
822 * Commit the changes represented by this transaction
823 */
824int
ad10fb70 825libxfs_trans_commit(
de5a3f46 826 xfs_trans_t *tp)
2bd0ea18
NS
827{
828 xfs_sb_t *sbp;
2bd0ea18
NS
829
830 if (tp == NULL)
831 return 0;
832
833 if (!(tp->t_flags & XFS_TRANS_DIRTY)) {
834#ifdef XACT_DEBUG
835 fprintf(stderr, "committed clean transaction %p\n", tp);
836#endif
7bcb8403 837 xfs_trans_free_items(tp);
2bd0ea18
NS
838 free(tp);
839 tp = NULL;
840 return 0;
841 }
842
843 if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
844 sbp = &(tp->t_mountp->m_sb);
845 if (tp->t_icount_delta)
846 sbp->sb_icount += tp->t_icount_delta;
847 if (tp->t_ifree_delta)
848 sbp->sb_ifree += tp->t_ifree_delta;
849 if (tp->t_fdblocks_delta)
850 sbp->sb_fdblocks += tp->t_fdblocks_delta;
851 if (tp->t_frextents_delta)
852 sbp->sb_frextents += tp->t_frextents_delta;
19ebedcf 853 xfs_log_sb(tp);
2bd0ea18
NS
854 }
855
856#ifdef XACT_DEBUG
857 fprintf(stderr, "committing dirty transaction %p\n", tp);
858#endif
859 trans_committed(tp);
860
861 /* That's it for the transaction structure. Free it. */
862 free(tp);
863 tp = NULL;
864 return 0;
865}