]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libxfs/rdwr.c
libxfs: add b_error
[thirdparty/xfsprogs-dev.git] / libxfs / rdwr.c
1 /*
2 * Copyright (c) 2000-2006 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include <xfs/libxfs.h>
20 #include <xfs/xfs_log.h>
21 #include <xfs/xfs_log_priv.h>
22 #include "init.h"
23
24 #define BDSTRAT_SIZE (256 * 1024)
25 #define min(x, y) ((x) < (y) ? (x) : (y))
26
27 #define IO_BCOMPARE_CHECK
28
29 void
30 libxfs_device_zero(dev_t dev, xfs_daddr_t start, uint len)
31 {
32 xfs_off_t start_offset, end_offset, offset;
33 ssize_t zsize, bytes;
34 char *z;
35 int fd;
36
37 zsize = min(BDSTRAT_SIZE, BBTOB(len));
38 if ((z = memalign(libxfs_device_alignment(), zsize)) == NULL) {
39 fprintf(stderr,
40 _("%s: %s can't memalign %d bytes: %s\n"),
41 progname, __FUNCTION__, (int)zsize, strerror(errno));
42 exit(1);
43 }
44 memset(z, 0, zsize);
45
46 fd = libxfs_device_to_fd(dev);
47 start_offset = LIBXFS_BBTOOFF64(start);
48
49 if ((lseek64(fd, start_offset, SEEK_SET)) < 0) {
50 fprintf(stderr, _("%s: %s seek to offset %llu failed: %s\n"),
51 progname, __FUNCTION__,
52 (unsigned long long)start_offset, strerror(errno));
53 exit(1);
54 }
55
56 end_offset = LIBXFS_BBTOOFF64(start + len) - start_offset;
57 for (offset = 0; offset < end_offset; ) {
58 bytes = min((ssize_t)(end_offset - offset), zsize);
59 if ((bytes = write(fd, z, bytes)) < 0) {
60 fprintf(stderr, _("%s: %s write failed: %s\n"),
61 progname, __FUNCTION__, strerror(errno));
62 exit(1);
63 } else if (bytes == 0) {
64 fprintf(stderr, _("%s: %s not progressing?\n"),
65 progname, __FUNCTION__);
66 exit(1);
67 }
68 offset += bytes;
69 }
70 free(z);
71 }
72
73 static void unmount_record(void *p)
74 {
75 xlog_op_header_t *op = (xlog_op_header_t *)p;
76 /* the data section must be 32 bit size aligned */
77 struct {
78 __uint16_t magic;
79 __uint16_t pad1;
80 __uint32_t pad2; /* may as well make it 64 bits */
81 } magic = { XLOG_UNMOUNT_TYPE, 0, 0 };
82
83 memset(p, 0, BBSIZE);
84 op->oh_tid = cpu_to_be32(1);
85 op->oh_len = cpu_to_be32(sizeof(magic));
86 op->oh_clientid = XFS_LOG;
87 op->oh_flags = XLOG_UNMOUNT_TRANS;
88 op->oh_res2 = 0;
89
90 /* and the data for this op */
91 memcpy((char *)p + sizeof(xlog_op_header_t), &magic, sizeof(magic));
92 }
93
94 static xfs_caddr_t next(xfs_caddr_t ptr, int offset, void *private)
95 {
96 xfs_buf_t *buf = (xfs_buf_t *)private;
97
98 if (XFS_BUF_COUNT(buf) < (int)(ptr - XFS_BUF_PTR(buf)) + offset)
99 abort();
100 return ptr + offset;
101 }
102
103 int
104 libxfs_log_clear(
105 dev_t device,
106 xfs_daddr_t start,
107 uint length,
108 uuid_t *fs_uuid,
109 int version,
110 int sunit,
111 int fmt)
112 {
113 xfs_buf_t *bp;
114 int len;
115
116 if (!device || !fs_uuid)
117 return -EINVAL;
118
119 /* first zero the log */
120 libxfs_device_zero(device, start, length);
121
122 /* then write a log record header */
123 len = ((version == 2) && sunit) ? BTOBB(sunit) : 2;
124 len = MAX(len, 2);
125 bp = libxfs_getbufr(device, start, len);
126 libxfs_log_header(XFS_BUF_PTR(bp),
127 fs_uuid, version, sunit, fmt, next, bp);
128 bp->b_flags |= LIBXFS_B_DIRTY;
129 libxfs_putbufr(bp);
130 return 0;
131 }
132
133 int
134 libxfs_log_header(
135 xfs_caddr_t caddr,
136 uuid_t *fs_uuid,
137 int version,
138 int sunit,
139 int fmt,
140 libxfs_get_block_t *nextfunc,
141 void *private)
142 {
143 xlog_rec_header_t *head = (xlog_rec_header_t *)caddr;
144 xfs_caddr_t p = caddr;
145 __be32 cycle_lsn;
146 int i, len;
147
148 len = ((version == 2) && sunit) ? BTOBB(sunit) : 1;
149
150 /* note that oh_tid actually contains the cycle number
151 * and the tid is stored in h_cycle_data[0] - that's the
152 * way things end up on disk.
153 */
154 memset(p, 0, BBSIZE);
155 head->h_magicno = cpu_to_be32(XLOG_HEADER_MAGIC_NUM);
156 head->h_cycle = cpu_to_be32(1);
157 head->h_version = cpu_to_be32(version);
158 if (len != 1)
159 head->h_len = cpu_to_be32(sunit - BBSIZE);
160 else
161 head->h_len = cpu_to_be32(20);
162 head->h_chksum = cpu_to_be32(0);
163 head->h_prev_block = cpu_to_be32(-1);
164 head->h_num_logops = cpu_to_be32(1);
165 head->h_cycle_data[0] = cpu_to_be32(0xb0c0d0d0);
166 head->h_fmt = cpu_to_be32(fmt);
167 head->h_size = cpu_to_be32(XLOG_HEADER_CYCLE_SIZE);
168
169 head->h_lsn = cpu_to_be64(xlog_assign_lsn(1, 0));
170 head->h_tail_lsn = cpu_to_be64(xlog_assign_lsn(1, 0));
171
172 memcpy(&head->h_fs_uuid, fs_uuid, sizeof(uuid_t));
173
174 len = MAX(len, 2);
175 p = nextfunc(p, BBSIZE, private);
176 unmount_record(p);
177
178 cycle_lsn = CYCLE_LSN_DISK(head->h_lsn);
179 for (i = 2; i < len; i++) {
180 p = nextfunc(p, BBSIZE, private);
181 memset(p, 0, BBSIZE);
182 *(__be32 *)p = cycle_lsn;
183 }
184
185 return BBTOB(len);
186 }
187
188 /*
189 * Simple I/O (buffer cache) interface
190 */
191
192
193 #ifdef XFS_BUF_TRACING
194
195 #undef libxfs_readbuf
196 #undef libxfs_writebuf
197 #undef libxfs_getbuf
198 #undef libxfs_putbuf
199
200 xfs_buf_t *libxfs_readbuf(dev_t, xfs_daddr_t, int, int);
201 int libxfs_writebuf(xfs_buf_t *, int);
202 xfs_buf_t *libxfs_getbuf(dev_t, xfs_daddr_t, int);
203 void libxfs_putbuf (xfs_buf_t *);
204
205 xfs_buf_t *
206 libxfs_trace_readbuf(const char *func, const char *file, int line, dev_t dev, xfs_daddr_t blkno, int len, int flags)
207 {
208 xfs_buf_t *bp = libxfs_readbuf(dev, blkno, len, flags);
209
210 if (bp){
211 bp->b_func = func;
212 bp->b_file = file;
213 bp->b_line = line;
214 }
215
216 return bp;
217 }
218
219 int
220 libxfs_trace_writebuf(const char *func, const char *file, int line, xfs_buf_t *bp, int flags)
221 {
222 bp->b_func = func;
223 bp->b_file = file;
224 bp->b_line = line;
225
226 return libxfs_writebuf(bp, flags);
227 }
228
229 xfs_buf_t *
230 libxfs_trace_getbuf(const char *func, const char *file, int line, dev_t device, xfs_daddr_t blkno, int len)
231 {
232 xfs_buf_t *bp = libxfs_getbuf(device, blkno, len);
233
234 bp->b_func = func;
235 bp->b_file = file;
236 bp->b_line = line;
237
238 return bp;
239 }
240
241 void
242 libxfs_trace_putbuf(const char *func, const char *file, int line, xfs_buf_t *bp)
243 {
244 bp->b_func = func;
245 bp->b_file = file;
246 bp->b_line = line;
247
248 libxfs_putbuf(bp);
249 }
250
251
252 #endif
253
254
255 xfs_buf_t *
256 libxfs_getsb(xfs_mount_t *mp, int flags)
257 {
258 return libxfs_readbuf(mp->m_dev, XFS_SB_DADDR,
259 XFS_FSS_TO_BB(mp, 1), flags);
260 }
261
262 kmem_zone_t *xfs_buf_zone;
263
264 static struct cache_mru xfs_buf_freelist =
265 {{&xfs_buf_freelist.cm_list, &xfs_buf_freelist.cm_list},
266 0, PTHREAD_MUTEX_INITIALIZER };
267
268 typedef struct {
269 dev_t device;
270 xfs_daddr_t blkno;
271 unsigned int bblen;
272 } xfs_bufkey_t;
273
274 static unsigned int
275 libxfs_bhash(cache_key_t key, unsigned int hashsize)
276 {
277 return (((unsigned int)((xfs_bufkey_t *)key)->blkno) >> 5) % hashsize;
278 }
279
280 static int
281 libxfs_bcompare(struct cache_node *node, cache_key_t key)
282 {
283 xfs_buf_t *bp = (xfs_buf_t *)node;
284 xfs_bufkey_t *bkey = (xfs_bufkey_t *)key;
285
286 #ifdef IO_BCOMPARE_CHECK
287 if (bp->b_dev == bkey->device &&
288 bp->b_blkno == bkey->blkno &&
289 bp->b_bcount != BBTOB(bkey->bblen))
290 fprintf(stderr, "%lx: Badness in key lookup (length)\n"
291 "bp=(bno %llu, len %u bytes) key=(bno %llu, len %u bytes)\n",
292 pthread_self(),
293 (unsigned long long)bp->b_blkno, (int)bp->b_bcount,
294 (unsigned long long)bkey->blkno, BBTOB(bkey->bblen));
295 #endif
296
297 return (bp->b_dev == bkey->device &&
298 bp->b_blkno == bkey->blkno &&
299 bp->b_bcount == BBTOB(bkey->bblen));
300 }
301
302 void
303 libxfs_bprint(xfs_buf_t *bp)
304 {
305 fprintf(stderr, "Buffer 0x%p blkno=%llu bytes=%u flags=0x%x count=%u\n",
306 bp, (unsigned long long)bp->b_blkno, (unsigned)bp->b_bcount,
307 bp->b_flags, bp->b_node.cn_count);
308 }
309
310 static void
311 libxfs_initbuf(xfs_buf_t *bp, dev_t device, xfs_daddr_t bno, unsigned int bytes)
312 {
313 bp->b_flags = 0;
314 bp->b_blkno = bno;
315 bp->b_bcount = bytes;
316 bp->b_dev = device;
317 bp->b_error = 0;
318 if (!bp->b_addr)
319 bp->b_addr = memalign(libxfs_device_alignment(), bytes);
320 if (!bp->b_addr) {
321 fprintf(stderr,
322 _("%s: %s can't memalign %u bytes: %s\n"),
323 progname, __FUNCTION__, bytes,
324 strerror(errno));
325 exit(1);
326 }
327 #ifdef XFS_BUF_TRACING
328 list_head_init(&bp->b_lock_list);
329 #endif
330 pthread_mutex_init(&bp->b_lock, NULL);
331 }
332
333 xfs_buf_t *
334 libxfs_getbufr(dev_t device, xfs_daddr_t blkno, int bblen)
335 {
336 xfs_buf_t *bp;
337 int blen = BBTOB(bblen);
338
339 /*
340 * first look for a buffer that can be used as-is,
341 * if one cannot be found, see if there is a buffer,
342 * and if so, free its buffer and set b_addr to NULL
343 * before calling libxfs_initbuf.
344 */
345 pthread_mutex_lock(&xfs_buf_freelist.cm_mutex);
346 if (!list_empty(&xfs_buf_freelist.cm_list)) {
347 list_for_each_entry(bp, &xfs_buf_freelist.cm_list, b_node.cn_mru) {
348 if (bp->b_bcount == blen) {
349 list_del_init(&bp->b_node.cn_mru);
350 break;
351 }
352 }
353 if (&bp->b_node.cn_mru == &xfs_buf_freelist.cm_list) {
354 bp = list_entry(xfs_buf_freelist.cm_list.next,
355 xfs_buf_t, b_node.cn_mru);
356 list_del_init(&bp->b_node.cn_mru);
357 free(bp->b_addr);
358 bp->b_addr = NULL;
359 }
360 } else
361 bp = kmem_zone_zalloc(xfs_buf_zone, 0);
362 pthread_mutex_unlock(&xfs_buf_freelist.cm_mutex);
363
364 if (bp != NULL)
365 libxfs_initbuf(bp, device, blkno, blen);
366 #ifdef IO_DEBUG
367 printf("%lx: %s: allocated %u bytes buffer, key=%llu(%llu), %p\n",
368 pthread_self(), __FUNCTION__, BBTOB(len),
369 (long long)LIBXFS_BBTOOFF64(blkno), (long long)blkno, bp);
370 #endif
371
372 return bp;
373 }
374
375
376 #ifdef XFS_BUF_TRACING
377 struct list_head lock_buf_list = {&lock_buf_list, &lock_buf_list};
378 int lock_buf_count = 0;
379 #endif
380
381 extern int use_xfs_buf_lock;
382
383 xfs_buf_t *
384 libxfs_getbuf(dev_t device, xfs_daddr_t blkno, int len)
385 {
386 xfs_buf_t *bp;
387 xfs_bufkey_t key;
388 int miss;
389
390 key.device = device;
391 key.blkno = blkno;
392 key.bblen = len;
393
394 miss = cache_node_get(libxfs_bcache, &key, (struct cache_node **)&bp);
395 if (bp) {
396 if (use_xfs_buf_lock)
397 pthread_mutex_lock(&bp->b_lock);
398 cache_node_set_priority(libxfs_bcache, (struct cache_node *)bp,
399 cache_node_get_priority((struct cache_node *)bp) -
400 CACHE_PREFETCH_PRIORITY);
401 #ifdef XFS_BUF_TRACING
402 pthread_mutex_lock(&libxfs_bcache->c_mutex);
403 lock_buf_count++;
404 list_add(&bp->b_lock_list, &lock_buf_list);
405 pthread_mutex_unlock(&libxfs_bcache->c_mutex);
406 #endif
407 #ifdef IO_DEBUG
408 printf("%lx %s: %s buffer %p for bno = %llu\n",
409 pthread_self(), __FUNCTION__, miss ? "miss" : "hit",
410 bp, (long long)LIBXFS_BBTOOFF64(blkno));
411 #endif
412 }
413
414 return bp;
415 }
416
417 void
418 libxfs_putbuf(xfs_buf_t *bp)
419 {
420 #ifdef XFS_BUF_TRACING
421 pthread_mutex_lock(&libxfs_bcache->c_mutex);
422 lock_buf_count--;
423 ASSERT(lock_buf_count >= 0);
424 list_del_init(&bp->b_lock_list);
425 pthread_mutex_unlock(&libxfs_bcache->c_mutex);
426 #endif
427 if (use_xfs_buf_lock)
428 pthread_mutex_unlock(&bp->b_lock);
429 cache_node_put(libxfs_bcache, (struct cache_node *)bp);
430 }
431
432 void
433 libxfs_purgebuf(xfs_buf_t *bp)
434 {
435 xfs_bufkey_t key;
436
437 key.device = bp->b_dev;
438 key.blkno = bp->b_blkno;
439 key.bblen = bp->b_bcount >> BBSHIFT;
440
441 cache_node_purge(libxfs_bcache, &key, (struct cache_node *)bp);
442 }
443
444 static struct cache_node *
445 libxfs_balloc(cache_key_t key)
446 {
447 xfs_bufkey_t *bufkey = (xfs_bufkey_t *)key;
448
449 return (struct cache_node *)libxfs_getbufr(bufkey->device,
450 bufkey->blkno, bufkey->bblen);
451 }
452
453 int
454 libxfs_readbufr(dev_t dev, xfs_daddr_t blkno, xfs_buf_t *bp, int len, int flags)
455 {
456 int fd = libxfs_device_to_fd(dev);
457 int bytes = BBTOB(len);
458 int error;
459 int sts;
460
461 ASSERT(BBTOB(len) <= bp->b_bcount);
462
463 sts = pread64(fd, bp->b_addr, bytes, LIBXFS_BBTOOFF64(blkno));
464 if (sts < 0) {
465 error = errno;
466 fprintf(stderr, _("%s: read failed: %s\n"),
467 progname, strerror(error));
468 if (flags & LIBXFS_EXIT_ON_FAILURE)
469 exit(1);
470 return error;
471 } else if (sts != bytes) {
472 fprintf(stderr, _("%s: error - read only %d of %d bytes\n"),
473 progname, sts, bytes);
474 if (flags & LIBXFS_EXIT_ON_FAILURE)
475 exit(1);
476 return EIO;
477 }
478 #ifdef IO_DEBUG
479 printf("%lx: %s: read %u bytes, blkno=%llu(%llu), %p\n",
480 pthread_self(), __FUNCTION__, bytes,
481 (long long)LIBXFS_BBTOOFF64(blkno), (long long)blkno, bp);
482 #endif
483 if (bp->b_dev == dev &&
484 bp->b_blkno == blkno &&
485 bp->b_bcount == bytes)
486 bp->b_flags |= LIBXFS_B_UPTODATE;
487 return 0;
488 }
489
490 xfs_buf_t *
491 libxfs_readbuf(dev_t dev, xfs_daddr_t blkno, int len, int flags)
492 {
493 xfs_buf_t *bp;
494 int error;
495
496 bp = libxfs_getbuf(dev, blkno, len);
497 if (bp && !(bp->b_flags & (LIBXFS_B_UPTODATE|LIBXFS_B_DIRTY))) {
498 error = libxfs_readbufr(dev, blkno, bp, len, flags);
499 if (error)
500 bp->b_error = error;
501 }
502 return bp;
503 }
504
505 int
506 libxfs_writebufr(xfs_buf_t *bp)
507 {
508 int sts;
509 int fd = libxfs_device_to_fd(bp->b_dev);
510 int error;
511
512 sts = pwrite64(fd, bp->b_addr, bp->b_bcount, LIBXFS_BBTOOFF64(bp->b_blkno));
513 if (sts < 0) {
514 error = errno;
515 fprintf(stderr, _("%s: pwrite64 failed: %s\n"),
516 progname, strerror(error));
517 if (bp->b_flags & LIBXFS_B_EXIT)
518 exit(1);
519 return error;
520 } else if (sts != bp->b_bcount) {
521 fprintf(stderr, _("%s: error - wrote only %d of %d bytes\n"),
522 progname, sts, bp->b_bcount);
523 if (bp->b_flags & LIBXFS_B_EXIT)
524 exit(1);
525 return EIO;
526 }
527 #ifdef IO_DEBUG
528 printf("%lx: %s: wrote %u bytes, blkno=%llu(%llu), %p\n",
529 pthread_self(), __FUNCTION__, bp->b_bcount,
530 (long long)LIBXFS_BBTOOFF64(bp->b_blkno),
531 (long long)bp->b_blkno, bp);
532 #endif
533 bp->b_flags |= LIBXFS_B_UPTODATE;
534 bp->b_flags &= ~(LIBXFS_B_DIRTY | LIBXFS_B_EXIT);
535 return 0;
536 }
537
538 int
539 libxfs_writebuf_int(xfs_buf_t *bp, int flags)
540 {
541 bp->b_flags |= (LIBXFS_B_DIRTY | flags);
542 return 0;
543 }
544
545 int
546 libxfs_writebuf(xfs_buf_t *bp, int flags)
547 {
548 bp->b_flags |= (LIBXFS_B_DIRTY | flags);
549 libxfs_putbuf(bp);
550 return 0;
551 }
552
553 void
554 libxfs_iomove(xfs_buf_t *bp, uint boff, int len, void *data, int flags)
555 {
556 #ifdef IO_DEBUG
557 if (boff + len > bp->b_bcount) {
558 printf("Badness, iomove out of range!\n"
559 "bp=(bno %llu, bytes %u) range=(boff %u, bytes %u)\n",
560 (long long)bp->b_blkno, bp->b_bcount, boff, len);
561 abort();
562 }
563 #endif
564 switch (flags) {
565 case LIBXFS_BZERO:
566 memset(bp->b_addr + boff, 0, len);
567 break;
568 case LIBXFS_BREAD:
569 memcpy(data, bp->b_addr + boff, len);
570 break;
571 case LIBXFS_BWRITE:
572 memcpy(bp->b_addr + boff, data, len);
573 break;
574 }
575 }
576
577 static void
578 libxfs_brelse(struct cache_node *node)
579 {
580 xfs_buf_t *bp = (xfs_buf_t *)node;
581
582 if (bp != NULL) {
583 if (bp->b_flags & LIBXFS_B_DIRTY)
584 libxfs_writebufr(bp);
585 pthread_mutex_lock(&xfs_buf_freelist.cm_mutex);
586 list_add(&bp->b_node.cn_mru, &xfs_buf_freelist.cm_list);
587 pthread_mutex_unlock(&xfs_buf_freelist.cm_mutex);
588 }
589 }
590
591 static unsigned int
592 libxfs_bulkrelse(
593 struct cache *cache,
594 struct list_head *list)
595 {
596 xfs_buf_t *bp;
597 int count = 0;
598
599 if (list_empty(list))
600 return 0 ;
601
602 list_for_each_entry(bp, list, b_node.cn_mru) {
603 if (bp->b_flags & LIBXFS_B_DIRTY)
604 libxfs_writebufr(bp);
605 count++;
606 }
607
608 pthread_mutex_lock(&xfs_buf_freelist.cm_mutex);
609 __list_splice(list, &xfs_buf_freelist.cm_list);
610 pthread_mutex_unlock(&xfs_buf_freelist.cm_mutex);
611
612 return count;
613 }
614
615 static void
616 libxfs_bflush(struct cache_node *node)
617 {
618 xfs_buf_t *bp = (xfs_buf_t *)node;
619
620 if ((bp != NULL) && (bp->b_flags & LIBXFS_B_DIRTY))
621 libxfs_writebufr(bp);
622 }
623
624 void
625 libxfs_putbufr(xfs_buf_t *bp)
626 {
627 libxfs_brelse((struct cache_node *)bp);
628 }
629
630
631 void
632 libxfs_bcache_purge(void)
633 {
634 cache_purge(libxfs_bcache);
635 }
636
637 void
638 libxfs_bcache_flush(void)
639 {
640 cache_flush(libxfs_bcache);
641 }
642
643 int
644 libxfs_bcache_overflowed(void)
645 {
646 return cache_overflowed(libxfs_bcache);
647 }
648
649 struct cache_operations libxfs_bcache_operations = {
650 /* .hash */ libxfs_bhash,
651 /* .alloc */ libxfs_balloc,
652 /* .flush */ libxfs_bflush,
653 /* .relse */ libxfs_brelse,
654 /* .compare */ libxfs_bcompare,
655 /* .bulkrelse */libxfs_bulkrelse
656 };
657
658
659 /*
660 * Inode cache interfaces
661 */
662
663 extern kmem_zone_t *xfs_ili_zone;
664 extern kmem_zone_t *xfs_inode_zone;
665
666 static unsigned int
667 libxfs_ihash(cache_key_t key, unsigned int hashsize)
668 {
669 return ((unsigned int)*(xfs_ino_t *)key) % hashsize;
670 }
671
672 static int
673 libxfs_icompare(struct cache_node *node, cache_key_t key)
674 {
675 xfs_inode_t *ip = (xfs_inode_t *)node;
676
677 return (ip->i_ino == *(xfs_ino_t *)key);
678 }
679
680 int
681 libxfs_iget(xfs_mount_t *mp, xfs_trans_t *tp, xfs_ino_t ino, uint lock_flags,
682 xfs_inode_t **ipp, xfs_daddr_t bno)
683 {
684 xfs_inode_t *ip;
685 int error = 0;
686
687 if (cache_node_get(libxfs_icache, &ino, (struct cache_node **)&ip)) {
688 #ifdef INO_DEBUG
689 fprintf(stderr, "%s: allocated inode, ino=%llu(%llu), %p\n",
690 __FUNCTION__, (unsigned long long)ino, bno, ip);
691 #endif
692 if ((error = libxfs_iread(mp, tp, ino, ip, bno))) {
693 cache_node_purge(libxfs_icache, &ino,
694 (struct cache_node *)ip);
695 ip = NULL;
696 }
697 }
698 *ipp = ip;
699 return error;
700 }
701
702 void
703 libxfs_iput(xfs_inode_t *ip, uint lock_flags)
704 {
705 cache_node_put(libxfs_icache, (struct cache_node *)ip);
706 }
707
708 static struct cache_node *
709 libxfs_ialloc(cache_key_t key)
710 {
711 return kmem_zone_zalloc(xfs_inode_zone, 0);
712 }
713
714 static void
715 libxfs_idestroy(xfs_inode_t *ip)
716 {
717 switch (ip->i_d.di_mode & S_IFMT) {
718 case S_IFREG:
719 case S_IFDIR:
720 case S_IFLNK:
721 libxfs_idestroy_fork(ip, XFS_DATA_FORK);
722 break;
723 }
724 if (ip->i_afp)
725 libxfs_idestroy_fork(ip, XFS_ATTR_FORK);
726 }
727
728 static void
729 libxfs_irelse(struct cache_node *node)
730 {
731 xfs_inode_t *ip = (xfs_inode_t *)node;
732
733 if (ip != NULL) {
734 if (ip->i_itemp)
735 kmem_zone_free(xfs_ili_zone, ip->i_itemp);
736 ip->i_itemp = NULL;
737 libxfs_idestroy(ip);
738 kmem_zone_free(xfs_inode_zone, ip);
739 ip = NULL;
740 }
741 }
742
743 void
744 libxfs_icache_purge(void)
745 {
746 cache_purge(libxfs_icache);
747 }
748
749 struct cache_operations libxfs_icache_operations = {
750 /* .hash */ libxfs_ihash,
751 /* .alloc */ libxfs_ialloc,
752 /* .flush */ NULL,
753 /* .relse */ libxfs_irelse,
754 /* .compare */ libxfs_icompare,
755 /* .bulkrelse */ NULL
756 };