]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libxfs/logitem.c
Update copyright dates (again)
[thirdparty/xfsprogs-dev.git] / libxfs / logitem.c
CommitLineData
2bd0ea18 1/*
0d3e0b37 2 * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved.
2bd0ea18
NS
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22 *
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31 */
32
33#include <xfs.h>
34
35xfs_zone_t *xfs_buf_item_zone;
36xfs_zone_t *xfs_ili_zone; /* inode log item zone */
37
38
39/*
40 * This is called to add the given log item to the transaction's
41 * list of log items. It must find a free log item descriptor
42 * or allocate a new one and add the item to that descriptor.
43 * The function returns a pointer to item descriptor used to point
44 * to the new item. The log item will now point to its new descriptor
45 * with its li_desc field.
46 */
47xfs_log_item_desc_t *
48xfs_trans_add_item(xfs_trans_t *tp, xfs_log_item_t *lip)
49{
50 xfs_log_item_desc_t *lidp;
51 xfs_log_item_chunk_t *licp;
9fe055ab 52 int i = 0;
2bd0ea18
NS
53
54 /*
55 * If there are no free descriptors, allocate a new chunk
56 * of them and put it at the front of the chunk list.
57 */
58 if (tp->t_items_free == 0) {
59 licp = (xfs_log_item_chunk_t*)
60 kmem_alloc(sizeof(xfs_log_item_chunk_t), KM_SLEEP);
61 ASSERT(licp != NULL);
62 /*
63 * Initialize the chunk, and then
64 * claim the first slot in the newly allocated chunk.
65 */
66 XFS_LIC_INIT(licp);
67 XFS_LIC_CLAIM(licp, 0);
68 licp->lic_unused = 1;
69 XFS_LIC_INIT_SLOT(licp, 0);
70 lidp = XFS_LIC_SLOT(licp, 0);
71
72 /*
73 * Link in the new chunk and update the free count.
74 */
75 licp->lic_next = tp->t_items.lic_next;
76 tp->t_items.lic_next = licp;
77 tp->t_items_free = XFS_LIC_NUM_SLOTS - 1;
78
79 /*
80 * Initialize the descriptor and the generic portion
81 * of the log item.
82 *
83 * Point the new slot at this item and return it.
84 * Also point the log item at its currently active
85 * descriptor and set the item's mount pointer.
86 */
87 lidp->lid_item = lip;
88 lidp->lid_flags = 0;
89 lidp->lid_size = 0;
90 lip->li_desc = lidp;
91 lip->li_mountp = tp->t_mountp;
92 return (lidp);
93 }
94
95 /*
96 * Find the free descriptor. It is somewhere in the chunklist
97 * of descriptors.
98 */
99 licp = &tp->t_items;
100 while (licp != NULL) {
101 if (XFS_LIC_VACANCY(licp)) {
102 if (licp->lic_unused <= XFS_LIC_MAX_SLOT) {
103 i = licp->lic_unused;
104 ASSERT(XFS_LIC_ISFREE(licp, i));
105 break;
106 }
107 for (i = 0; i <= XFS_LIC_MAX_SLOT; i++) {
108 if (XFS_LIC_ISFREE(licp, i))
109 break;
110 }
111 ASSERT(i <= XFS_LIC_MAX_SLOT);
112 break;
113 }
114 licp = licp->lic_next;
115 }
116 ASSERT(licp != NULL);
117 /*
118 * If we find a free descriptor, claim it,
119 * initialize it, and return it.
120 */
121 XFS_LIC_CLAIM(licp, i);
122 if (licp->lic_unused <= i) {
123 licp->lic_unused = i + 1;
124 XFS_LIC_INIT_SLOT(licp, i);
125 }
126 lidp = XFS_LIC_SLOT(licp, i);
127 tp->t_items_free--;
128 lidp->lid_item = lip;
129 lidp->lid_flags = 0;
130 lidp->lid_size = 0;
131 lip->li_desc = lidp;
132 lip->li_mountp = tp->t_mountp;
133 return (lidp);
134}
135
136/*
137 * Free the given descriptor.
138 *
139 * This requires setting the bit in the chunk's free mask corresponding
140 * to the given slot.
141 */
142void
143xfs_trans_free_item(xfs_trans_t *tp, xfs_log_item_desc_t *lidp)
144{
145 uint slot;
146 xfs_log_item_chunk_t *licp;
147 xfs_log_item_chunk_t **licpp;
148
149 slot = XFS_LIC_DESC_TO_SLOT(lidp);
150 licp = XFS_LIC_DESC_TO_CHUNK(lidp);
151 XFS_LIC_RELSE(licp, slot);
152 lidp->lid_item->li_desc = NULL;
153 tp->t_items_free++;
154
155 /*
156 * If there are no more used items in the chunk and this is not
157 * the chunk embedded in the transaction structure, then free
158 * the chunk. First pull it from the chunk list and then
159 * free it back to the heap. We didn't bother with a doubly
160 * linked list here because the lists should be very short
161 * and this is not a performance path. It's better to save
162 * the memory of the extra pointer.
163 *
164 * Also decrement the transaction structure's count of free items
165 * by the number in a chunk since we are freeing an empty chunk.
166 */
167 if (XFS_LIC_ARE_ALL_FREE(licp) && (licp != &(tp->t_items))) {
168 licpp = &(tp->t_items.lic_next);
169 while (*licpp != licp) {
170 ASSERT(*licpp != NULL);
171 licpp = &((*licpp)->lic_next);
172 }
173 *licpp = licp->lic_next;
174 kmem_free(licp, sizeof(xfs_log_item_chunk_t));
175 tp->t_items_free -= XFS_LIC_NUM_SLOTS;
176 }
177}
178
179/*
180 * This is called to find the descriptor corresponding to the given
181 * log item. It returns a pointer to the descriptor.
182 * The log item MUST have a corresponding descriptor in the given
183 * transaction. This routine does not return NULL, it panics.
184 *
185 * The descriptor pointer is kept in the log item's li_desc field.
186 * Just return it.
187 */
188xfs_log_item_desc_t *
189xfs_trans_find_item(xfs_trans_t *tp, xfs_log_item_t *lip)
190{
191 ASSERT(lip->li_desc != NULL);
192
193 return (lip->li_desc);
194}
195
196/*
197 * This is called to unlock all of the items of a transaction and to free
198 * all the descriptors of that transaction.
199 *
200 * It walks the list of descriptors and unlocks each item. It frees
201 * each chunk except that embedded in the transaction as it goes along.
202 */
203void
204xfs_trans_free_items(
205 xfs_trans_t *tp,
206 int flags)
207{
208 xfs_log_item_chunk_t *licp;
209 xfs_log_item_chunk_t *next_licp;
210 int abort;
211
212 abort = flags & XFS_TRANS_ABORT;
213 licp = &tp->t_items;
214 /*
215 * Special case the embedded chunk so we don't free it below.
216 */
217 if (!XFS_LIC_ARE_ALL_FREE(licp)) {
218 (void) xfs_trans_unlock_chunk(licp, 1, abort, NULLCOMMITLSN);
219 XFS_LIC_ALL_FREE(licp);
220 licp->lic_unused = 0;
221 }
222 licp = licp->lic_next;
223
224 /*
225 * Unlock each item in each chunk and free the chunks.
226 */
227 while (licp != NULL) {
228 ASSERT(!XFS_LIC_ARE_ALL_FREE(licp));
229 (void) xfs_trans_unlock_chunk(licp, 1, abort, NULLCOMMITLSN);
230 next_licp = licp->lic_next;
231 kmem_free(licp, sizeof(xfs_log_item_chunk_t));
232 licp = next_licp;
233 }
234
235 /*
236 * Reset the transaction structure's free item count.
237 */
238 tp->t_items_free = XFS_LIC_NUM_SLOTS;
239 tp->t_items.lic_next = NULL;
240}
241
242/*
243 * Check to see if a buffer matching the given parameters is already
244 * a part of the given transaction. Only check the first, embedded
245 * chunk, since we don't want to spend all day scanning large transactions.
246 */
247STATIC xfs_buf_t *
248xfs_trans_buf_item_match(
249 xfs_trans_t *tp,
250 buftarg_t *target,
251 xfs_daddr_t blkno,
252 int len)
253{
254 xfs_log_item_chunk_t *licp;
255 xfs_log_item_desc_t *lidp;
256 xfs_buf_log_item_t *blip;
257 xfs_buf_t *bp;
258 int i;
259
260#ifdef LI_DEBUG
261 fprintf(stderr, "buf_item_match (fast) log items for xact %p\n", tp);
262#endif
263
264 bp = NULL;
265 len = BBTOB(len);
266 licp = &tp->t_items;
267 if (!XFS_LIC_ARE_ALL_FREE(licp)) {
268 for (i = 0; i < licp->lic_unused; i++) {
269 /*
270 * Skip unoccupied slots.
271 */
272 if (XFS_LIC_ISFREE(licp, i)) {
273 continue;
274 }
275
276 lidp = XFS_LIC_SLOT(licp, i);
277 blip = (xfs_buf_log_item_t *)lidp->lid_item;
278#ifdef LI_DEBUG
279 fprintf(stderr,
280 "\tfound log item, xact %p, blip=%p (%d/%d)\n",
281 tp, blip, i, licp->lic_unused);
282#endif
283 if (blip->bli_item.li_type != XFS_LI_BUF) {
284 continue;
285 }
286
287 bp = blip->bli_buf;
288#ifdef LI_DEBUG
289 fprintf(stderr,
290 "\tfound buf %p log item, xact %p, blip=%p (%d)\n",
291 bp, tp, blip, i);
292#endif
293 if ((XFS_BUF_TARGET(bp) == target->dev) &&
294 (XFS_BUF_ADDR(bp) == blkno) &&
295 (XFS_BUF_COUNT(bp) == len)) {
296 /*
297 * We found it. Break out and
298 * return the pointer to the buffer.
299 */
300#ifdef LI_DEBUG
301 fprintf(stderr,
302 "\tfound REAL buf log item, bp=%p\n",
303 bp);
304#endif
305 break;
306 } else {
307 bp = NULL;
308 }
309 }
310 }
311#ifdef LI_DEBUG
312 if (!bp) fprintf(stderr, "\tfast search - got nothing\n");
313#endif
314 return bp;
315}
316
317/*
318 * Check to see if a buffer matching the given parameters is already
319 * a part of the given transaction. Check all the chunks, we
320 * want to be thorough.
321 */
322STATIC xfs_buf_t *
323xfs_trans_buf_item_match_all(
324 xfs_trans_t *tp,
325 buftarg_t *target,
326 xfs_daddr_t blkno,
327 int len)
328{
329 xfs_log_item_chunk_t *licp;
330 xfs_log_item_desc_t *lidp;
331 xfs_buf_log_item_t *blip;
332 xfs_buf_t *bp;
333 int i;
334
335#ifdef LI_DEBUG
336 fprintf(stderr, "buf_item_match_all (slow) log items for xact %p\n",
337 tp);
338#endif
339
340 bp = NULL;
341 len = BBTOB(len);
342 for (licp = &tp->t_items; licp != NULL; licp = licp->lic_next) {
343 if (XFS_LIC_ARE_ALL_FREE(licp)) {
344 ASSERT(licp == &tp->t_items);
345 ASSERT(licp->lic_next == NULL);
346 return NULL;
347 }
348 for (i = 0; i < licp->lic_unused; i++) {
349 /*
350 * Skip unoccupied slots.
351 */
352 if (XFS_LIC_ISFREE(licp, i)) {
353 continue;
354 }
355
356 lidp = XFS_LIC_SLOT(licp, i);
357 blip = (xfs_buf_log_item_t *)lidp->lid_item;
358#ifdef LI_DEBUG
359 fprintf(stderr,
360 "\tfound log item, xact %p, blip=%p (%d/%d)\n",
361 tp, blip, i, licp->lic_unused);
362#endif
363 if (blip->bli_item.li_type != XFS_LI_BUF) {
364 continue;
365 }
366
367 bp = blip->bli_buf;
368 ASSERT(bp);
369 ASSERT(XFS_BUF_ADDR(bp));
370#ifdef LI_DEBUG
371 fprintf(stderr,
372 "\tfound buf %p log item, xact %p, blip=%p (%d)\n",
373 bp, tp, blip, i);
374#endif
375 if ((XFS_BUF_TARGET(bp) == target->dev) &&
376 (XFS_BUF_ADDR(bp) == blkno) &&
377 (XFS_BUF_COUNT(bp) == len)) {
378 /*
379 * We found it. Break out and
380 * return the pointer to the buffer.
381 */
382#ifdef LI_DEBUG
383 fprintf(stderr,
384 "\tfound REAL buf log item, bp=%p\n",
385 bp);
386#endif
387 return bp;
388 }
389 }
390 }
391#ifdef LI_DEBUG
392 if (!bp) fprintf(stderr, "slow search - got nothing\n");
393#endif
394 return NULL;
395}
396
397/*
398 * Allocate a new buf log item to go with the given buffer.
399 * Set the buffer's b_fsprivate field to point to the new
400 * buf log item. If there are other item's attached to the
401 * buffer (see xfs_buf_attach_iodone() below), then put the
402 * buf log item at the front.
403 */
404void
405xfs_buf_item_init(
406 xfs_buf_t *bp,
407 xfs_mount_t *mp)
408{
409 xfs_log_item_t *lip;
410 xfs_buf_log_item_t *bip;
411
412#ifdef LI_DEBUG
413 fprintf(stderr, "buf_item_init for buffer %p\n", bp);
414#endif
415
416 /*
417 * Check to see if there is already a buf log item for
418 * this buffer. If there is, it is guaranteed to be
419 * the first. If we do already have one, there is
420 * nothing to do here so return.
421 */
422 if (XFS_BUF_FSPRIVATE3(bp, xfs_mount_t *) != mp)
423 XFS_BUF_SET_FSPRIVATE3(bp, mp);
424 XFS_BUF_SET_BDSTRAT_FUNC(bp, xfs_bdstrat_cb);
425 if (XFS_BUF_FSPRIVATE(bp, void *) != NULL) {
426 lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *);
427 if (lip->li_type == XFS_LI_BUF) {
428#ifdef LI_DEBUG
429 fprintf(stderr,
430 "reused buf item %p for pre-logged buffer %p\n",
431 lip, bp);
432#endif
433 return;
434 }
435 }
436
437 bip = (xfs_buf_log_item_t *)kmem_zone_zalloc(xfs_buf_item_zone,
438 KM_SLEEP);
439#ifdef LI_DEBUG
440 fprintf(stderr, "adding buf item %p for not-logged buffer %p\n",
441 bip, bp);
442#endif
443 bip->bli_item.li_type = XFS_LI_BUF;
444 bip->bli_item.li_mountp = mp;
445 bip->bli_buf = bp;
446 bip->bli_format.blf_type = XFS_LI_BUF;
447 bip->bli_format.blf_blkno = (__int64_t)XFS_BUF_ADDR(bp);
448 bip->bli_format.blf_len = (ushort)BTOBB(XFS_BUF_COUNT(bp));
449 XFS_BUF_SET_FSPRIVATE(bp, bip);
450}
451
452
453/*
454 * Mark bytes first through last inclusive as dirty in the buf
455 * item's bitmap.
456 */
457void
458xfs_buf_item_log(
459 xfs_buf_log_item_t *bip,
460 uint first,
461 uint last)
462{
463 /*
464 * Mark the item as having some dirty data for
465 * quick reference in xfs_buf_item_dirty.
466 */
467 bip->bli_flags |= XFS_BLI_DIRTY;
468}
469
470/*
471 * Initialize the inode log item for a newly allocated (in-core) inode.
472 */
473void
474xfs_inode_item_init(
475 xfs_inode_t *ip,
476 xfs_mount_t *mp)
477{
478 xfs_inode_log_item_t *iip;
479
480 ASSERT(ip->i_itemp == NULL);
481 iip = ip->i_itemp = (xfs_inode_log_item_t *)
482 kmem_zone_zalloc(xfs_ili_zone, KM_SLEEP);
483#ifdef LI_DEBUG
484 fprintf(stderr, "inode_item_init for inode %llu, iip=%p\n",
485 ip->i_ino, iip);
486#endif
487
488 iip->ili_item.li_type = XFS_LI_INODE;
489 iip->ili_item.li_mountp = mp;
490 iip->ili_inode = ip;
491 iip->ili_format.ilf_type = XFS_LI_INODE;
492 iip->ili_format.ilf_ino = ip->i_ino;
493 iip->ili_format.ilf_blkno = ip->i_blkno;
494 iip->ili_format.ilf_len = ip->i_len;
495 iip->ili_format.ilf_boffset = ip->i_boffset;
496}