]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libxfs/rdwr.c
libxfs: add a flags field to libxfs_getbuf_map
[thirdparty/xfsprogs-dev.git] / libxfs / rdwr.c
CommitLineData
2bd0ea18 1/*
f1b058f9 2 * Copyright (c) 2000-2006 Silicon Graphics, Inc.
da23017d 3 * All Rights Reserved.
2bd0ea18 4 *
da23017d
NS
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
2bd0ea18
NS
7 * published by the Free Software Foundation.
8 *
da23017d
NS
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.
2bd0ea18 13 *
da23017d
NS
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
2bd0ea18
NS
17 */
18
1d7e80ee 19#include <xfs/libxfs.h>
1aef52f8 20#include "init.h"
2bd0ea18 21
5000d01d 22#define BDSTRAT_SIZE (256 * 1024)
2bd0ea18 23
2556c98b
BN
24#define IO_BCOMPARE_CHECK
25
2bd0ea18 26void
75c8b434 27libxfs_device_zero(struct xfs_buftarg *btp, xfs_daddr_t start, uint len)
2bd0ea18 28{
3cc4d0db
NS
29 xfs_off_t start_offset, end_offset, offset;
30 ssize_t zsize, bytes;
2bd0ea18 31 char *z;
3cc4d0db 32 int fd;
2bd0ea18 33
3cc4d0db 34 zsize = min(BDSTRAT_SIZE, BBTOB(len));
b74a1f6a 35 if ((z = memalign(libxfs_device_alignment(), zsize)) == NULL) {
9440d84d
NS
36 fprintf(stderr,
37 _("%s: %s can't memalign %d bytes: %s\n"),
7dfd8291 38 progname, __FUNCTION__, (int)zsize, strerror(errno));
2bd0ea18
NS
39 exit(1);
40 }
3cc4d0db
NS
41 memset(z, 0, zsize);
42
75c8b434 43 fd = libxfs_device_to_fd(btp->dev);
cb5b3ef4 44 start_offset = LIBXFS_BBTOOFF64(start);
3cc4d0db
NS
45
46 if ((lseek64(fd, start_offset, SEEK_SET)) < 0) {
47 fprintf(stderr, _("%s: %s seek to offset %llu failed: %s\n"),
7dfd8291
NS
48 progname, __FUNCTION__,
49 (unsigned long long)start_offset, strerror(errno));
3cc4d0db
NS
50 exit(1);
51 }
52
cb5b3ef4 53 end_offset = LIBXFS_BBTOOFF64(start + len) - start_offset;
3cc4d0db
NS
54 for (offset = 0; offset < end_offset; ) {
55 bytes = min((ssize_t)(end_offset - offset), zsize);
56 if ((bytes = write(fd, z, bytes)) < 0) {
57 fprintf(stderr, _("%s: %s write failed: %s\n"),
9440d84d 58 progname, __FUNCTION__, strerror(errno));
2bd0ea18 59 exit(1);
3cc4d0db
NS
60 } else if (bytes == 0) {
61 fprintf(stderr, _("%s: %s not progressing?\n"),
62 progname, __FUNCTION__);
63 exit(1);
2bd0ea18 64 }
3cc4d0db 65 offset += bytes;
2bd0ea18
NS
66 }
67 free(z);
68}
69
989b74bc 70static void unmount_record(void *p)
2bd0ea18 71{
989b74bc 72 xlog_op_header_t *op = (xlog_op_header_t *)p;
5000d01d
SL
73 /* the data section must be 32 bit size aligned */
74 struct {
75 __uint16_t magic;
76 __uint16_t pad1;
77 __uint32_t pad2; /* may as well make it 64 bits */
78 } magic = { XLOG_UNMOUNT_TYPE, 0, 0 };
79
989b74bc 80 memset(p, 0, BBSIZE);
5e656dbb
BN
81 op->oh_tid = cpu_to_be32(1);
82 op->oh_len = cpu_to_be32(sizeof(magic));
83 op->oh_clientid = XFS_LOG;
84 op->oh_flags = XLOG_UNMOUNT_TRANS;
85 op->oh_res2 = 0;
989b74bc
NS
86
87 /* and the data for this op */
1552a820 88 memcpy((char *)p + sizeof(xlog_op_header_t), &magic, sizeof(magic));
989b74bc
NS
89}
90
91static xfs_caddr_t next(xfs_caddr_t ptr, int offset, void *private)
92{
93 xfs_buf_t *buf = (xfs_buf_t *)private;
94
95 if (XFS_BUF_COUNT(buf) < (int)(ptr - XFS_BUF_PTR(buf)) + offset)
96 abort();
97 return ptr + offset;
98}
99
100int
101libxfs_log_clear(
75c8b434 102 struct xfs_buftarg *btp,
989b74bc
NS
103 xfs_daddr_t start,
104 uint length,
105 uuid_t *fs_uuid,
106 int version,
107 int sunit,
108 int fmt)
109{
e6b359b3 110 xfs_buf_t *bp;
989b74bc
NS
111 int len;
112
75c8b434 113 if (!btp->dev || !fs_uuid)
2bd0ea18 114 return -EINVAL;
5000d01d
SL
115
116 /* first zero the log */
75c8b434 117 libxfs_device_zero(btp, start, length);
5000d01d
SL
118
119 /* then write a log record header */
989b74bc
NS
120 len = ((version == 2) && sunit) ? BTOBB(sunit) : 2;
121 len = MAX(len, 2);
75c8b434 122 bp = libxfs_getbufr(btp, start, len);
e6b359b3
NS
123 libxfs_log_header(XFS_BUF_PTR(bp),
124 fs_uuid, version, sunit, fmt, next, bp);
125 bp->b_flags |= LIBXFS_B_DIRTY;
126 libxfs_putbufr(bp);
989b74bc
NS
127 return 0;
128}
5000d01d 129
989b74bc
NS
130int
131libxfs_log_header(
132 xfs_caddr_t caddr,
133 uuid_t *fs_uuid,
134 int version,
135 int sunit,
136 int fmt,
137 libxfs_get_block_t *nextfunc,
138 void *private)
139{
140 xlog_rec_header_t *head = (xlog_rec_header_t *)caddr;
141 xfs_caddr_t p = caddr;
5e656dbb 142 __be32 cycle_lsn;
989b74bc
NS
143 int i, len;
144
145 len = ((version == 2) && sunit) ? BTOBB(sunit) : 1;
5000d01d
SL
146
147 /* note that oh_tid actually contains the cycle number
148 * and the tid is stored in h_cycle_data[0] - that's the
149 * way things end up on disk.
150 */
989b74bc 151 memset(p, 0, BBSIZE);
5e656dbb
BN
152 head->h_magicno = cpu_to_be32(XLOG_HEADER_MAGIC_NUM);
153 head->h_cycle = cpu_to_be32(1);
154 head->h_version = cpu_to_be32(version);
73bf5988 155 if (len != 1)
5e656dbb 156 head->h_len = cpu_to_be32(sunit - BBSIZE);
73bf5988 157 else
5e656dbb 158 head->h_len = cpu_to_be32(20);
a2ceac1f 159 head->h_crc = cpu_to_be32(0);
5e656dbb
BN
160 head->h_prev_block = cpu_to_be32(-1);
161 head->h_num_logops = cpu_to_be32(1);
162 head->h_cycle_data[0] = cpu_to_be32(0xb0c0d0d0);
163 head->h_fmt = cpu_to_be32(fmt);
164 head->h_size = cpu_to_be32(XLOG_HEADER_CYCLE_SIZE);
5000d01d 165
5e656dbb
BN
166 head->h_lsn = cpu_to_be64(xlog_assign_lsn(1, 0));
167 head->h_tail_lsn = cpu_to_be64(xlog_assign_lsn(1, 0));
5000d01d 168
6699422d 169 memcpy(&head->h_fs_uuid, fs_uuid, sizeof(uuid_t));
73bf5988 170
989b74bc
NS
171 len = MAX(len, 2);
172 p = nextfunc(p, BBSIZE, private);
173 unmount_record(p);
73bf5988 174
46eca962 175 cycle_lsn = CYCLE_LSN_DISK(head->h_lsn);
989b74bc
NS
176 for (i = 2; i < len; i++) {
177 p = nextfunc(p, BBSIZE, private);
178 memset(p, 0, BBSIZE);
5e656dbb 179 *(__be32 *)p = cycle_lsn;
73bf5988 180 }
5000d01d 181
989b74bc 182 return BBTOB(len);
2bd0ea18
NS
183}
184
2556c98b
BN
185/*
186 * Simple I/O (buffer cache) interface
187 */
188
189
190#ifdef XFS_BUF_TRACING
191
192#undef libxfs_readbuf
a2ceac1f 193#undef libxfs_readbuf_map
2556c98b
BN
194#undef libxfs_writebuf
195#undef libxfs_getbuf
a2ceac1f 196#undef libxfs_getbuf_map
2ae22647 197#undef libxfs_getbuf_flags
2556c98b
BN
198#undef libxfs_putbuf
199
75c8b434 200xfs_buf_t *libxfs_readbuf(struct xfs_buftarg *, xfs_daddr_t, int, int,
f756f80c 201 const struct xfs_buf_ops *);
75c8b434 202xfs_buf_t *libxfs_readbuf_map(struct xfs_buftarg *, struct xfs_buf_map *,
f756f80c 203 int, int, const struct xfs_buf_ops *);
2556c98b 204int libxfs_writebuf(xfs_buf_t *, int);
75c8b434 205xfs_buf_t *libxfs_getbuf(struct xfs_buftarg *, xfs_daddr_t, int);
7e3ab890
DC
206xfs_buf_t *libxfs_getbuf_map(struct xfs_buftarg *, struct xfs_buf_map *,
207 int, int);
75c8b434
DC
208xfs_buf_t *libxfs_getbuf_flags(struct xfs_buftarg *, xfs_daddr_t, int,
209 unsigned int);
2556c98b
BN
210void libxfs_putbuf (xfs_buf_t *);
211
a2ceac1f
DC
212#define __add_trace(bp, func, file, line) \
213do { \
214 if (bp) { \
215 (bp)->b_func = (func); \
216 (bp)->b_file = (file); \
217 (bp)->b_line = (line); \
218 } \
219} while (0)
220
2556c98b 221xfs_buf_t *
a2ceac1f 222libxfs_trace_readbuf(const char *func, const char *file, int line,
75c8b434
DC
223 struct xfs_buftarg *btp, xfs_daddr_t blkno, int len, int flags,
224 const struct xfs_buf_ops *ops)
2556c98b 225{
75c8b434 226 xfs_buf_t *bp = libxfs_readbuf(btp, blkno, len, flags, ops);
a2ceac1f
DC
227 __add_trace(bp, func, file, line);
228 return bp;
229}
2556c98b 230
a2ceac1f
DC
231xfs_buf_t *
232libxfs_trace_readbuf_map(const char *func, const char *file, int line,
75c8b434
DC
233 struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps, int flags,
234 const struct xfs_buf_ops *ops)
a2ceac1f 235{
75c8b434 236 xfs_buf_t *bp = libxfs_readbuf_map(btp, map, nmaps, flags, ops);
a2ceac1f 237 __add_trace(bp, func, file, line);
2556c98b
BN
238 return bp;
239}
240
241int
242libxfs_trace_writebuf(const char *func, const char *file, int line, xfs_buf_t *bp, int flags)
243{
a2ceac1f 244 __add_trace(bp, func, file, line);
2556c98b
BN
245 return libxfs_writebuf(bp, flags);
246}
247
248xfs_buf_t *
a2ceac1f 249libxfs_trace_getbuf(const char *func, const char *file, int line,
75c8b434 250 struct xfs_buftarg *btp, xfs_daddr_t blkno, int len)
2556c98b 251{
75c8b434 252 xfs_buf_t *bp = libxfs_getbuf(btp, blkno, len);
a2ceac1f
DC
253 __add_trace(bp, func, file, line);
254 return bp;
255}
2556c98b 256
a2ceac1f
DC
257xfs_buf_t *
258libxfs_trace_getbuf_map(const char *func, const char *file, int line,
7e3ab890
DC
259 struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps,
260 int flags)
a2ceac1f 261{
7e3ab890 262 xfs_buf_t *bp = libxfs_getbuf_map(btp, map, nmaps, flags);
a2ceac1f 263 __add_trace(bp, func, file, line);
2556c98b
BN
264 return bp;
265}
266
2ae22647
CH
267xfs_buf_t *
268libxfs_trace_getbuf_flags(const char *func, const char *file, int line,
75c8b434 269 struct xfs_buftarg *btp, xfs_daddr_t blkno, int len, unsigned int flags)
2ae22647 270{
75c8b434 271 xfs_buf_t *bp = libxfs_getbuf_flags(btp, blkno, len, flags);
a2ceac1f 272 __add_trace(bp, func, file, line);
2ae22647
CH
273 return bp;
274}
275
2556c98b
BN
276void
277libxfs_trace_putbuf(const char *func, const char *file, int line, xfs_buf_t *bp)
278{
a2ceac1f 279 __add_trace(bp, func, file, line);
2556c98b
BN
280 libxfs_putbuf(bp);
281}
282
283
284#endif
285
286
f1b058f9
NS
287xfs_buf_t *
288libxfs_getsb(xfs_mount_t *mp, int flags)
289{
75c8b434
DC
290 return libxfs_readbuf(mp->m_ddev_targp, XFS_SB_DADDR,
291 XFS_FSS_TO_BB(mp, 1), flags, &xfs_sb_buf_ops);
f1b058f9
NS
292}
293
5e656dbb 294kmem_zone_t *xfs_buf_zone;
69ec88b5
BN
295
296static struct cache_mru xfs_buf_freelist =
297 {{&xfs_buf_freelist.cm_list, &xfs_buf_freelist.cm_list},
298 0, PTHREAD_MUTEX_INITIALIZER };
f1b058f9 299
a2ceac1f
DC
300/*
301 * The bufkey is used to pass the new buffer information to the cache object
302 * allocation routine. Because discontiguous buffers need to pass different
303 * information, we need fields to pass that information. However, because the
304 * blkno and bblen is needed for the initial cache entry lookup (i.e. for
305 * bcompare) the fact that the map/nmaps is non-null to switch to discontiguous
306 * buffer initialisation instead of a contiguous buffer.
307 */
308struct xfs_bufkey {
75c8b434 309 struct xfs_buftarg *buftarg;
a2ceac1f
DC
310 xfs_daddr_t blkno;
311 unsigned int bblen;
312 struct xfs_buf_map *map;
313 int nmaps;
314};
f1b058f9
NS
315
316static unsigned int
317libxfs_bhash(cache_key_t key, unsigned int hashsize)
318{
a2ceac1f 319 return (((unsigned int)((struct xfs_bufkey *)key)->blkno) >> 5) % hashsize;
f1b058f9
NS
320}
321
322static int
323libxfs_bcompare(struct cache_node *node, cache_key_t key)
324{
a2ceac1f
DC
325 struct xfs_buf *bp = (struct xfs_buf *)node;
326 struct xfs_bufkey *bkey = (struct xfs_bufkey *)key;
f1b058f9 327
75c8b434 328 if (bp->b_target->dev == bkey->buftarg->dev &&
ba9ecd40
DC
329 bp->b_bn == bkey->blkno) {
330 if (bp->b_bcount == BBTOB(bkey->bblen))
331 return CACHE_HIT;
332#ifdef IO_BCOMPARE_CHECK
333 if (!(libxfs_bcache->c_flags & CACHE_MISCOMPARE_PURGE)) {
334 fprintf(stderr,
335 "%lx: Badness in key lookup (length)\n"
336 "bp=(bno 0x%llx, len %u bytes) key=(bno 0x%llx, len %u bytes)\n",
337 pthread_self(),
338 (unsigned long long)bp->b_bn, (int)bp->b_bcount,
339 (unsigned long long)bkey->blkno,
340 BBTOB(bkey->bblen));
341 }
f1b058f9 342#endif
ba9ecd40
DC
343 return CACHE_PURGE;
344 }
345 return CACHE_MISS;
f1b058f9
NS
346}
347
348void
349libxfs_bprint(xfs_buf_t *bp)
350{
351 fprintf(stderr, "Buffer 0x%p blkno=%llu bytes=%u flags=0x%x count=%u\n",
5dfa5cd2 352 bp, (unsigned long long)bp->b_bn, (unsigned)bp->b_bcount,
f1b058f9
NS
353 bp->b_flags, bp->b_node.cn_count);
354}
355
e6b359b3 356static void
75c8b434
DC
357__initbuf(xfs_buf_t *bp, struct xfs_buftarg *btp, xfs_daddr_t bno,
358 unsigned int bytes)
e6b359b3
NS
359{
360 bp->b_flags = 0;
5dfa5cd2 361 bp->b_bn = bno;
e6b359b3 362 bp->b_bcount = bytes;
a2ceac1f 363 bp->b_length = BTOBB(bytes);
75c8b434 364 bp->b_target = btp;
a6a7776a 365 bp->b_error = 0;
69ec88b5
BN
366 if (!bp->b_addr)
367 bp->b_addr = memalign(libxfs_device_alignment(), bytes);
e6b359b3
NS
368 if (!bp->b_addr) {
369 fprintf(stderr,
370 _("%s: %s can't memalign %u bytes: %s\n"),
371 progname, __FUNCTION__, bytes,
372 strerror(errno));
373 exit(1);
374 }
2556c98b
BN
375#ifdef XFS_BUF_TRACING
376 list_head_init(&bp->b_lock_list);
377#endif
378 pthread_mutex_init(&bp->b_lock, NULL);
50722af1
CH
379 bp->b_holder = 0;
380 bp->b_recur = 0;
75c8b434 381 bp->b_ops = NULL;
e6b359b3
NS
382}
383
a2ceac1f 384static void
75c8b434
DC
385libxfs_initbuf(xfs_buf_t *bp, struct xfs_buftarg *btp, xfs_daddr_t bno,
386 unsigned int bytes)
a2ceac1f 387{
75c8b434 388 __initbuf(bp, btp, bno, bytes);
a2ceac1f
DC
389}
390
391static void
75c8b434
DC
392libxfs_initbuf_map(xfs_buf_t *bp, struct xfs_buftarg *btp,
393 struct xfs_buf_map *map, int nmaps)
a2ceac1f
DC
394{
395 unsigned int bytes = 0;
396 int i;
397
398 bytes = sizeof(struct xfs_buf_map) * nmaps;
399 bp->b_map = malloc(bytes);
400 if (!bp->b_map) {
401 fprintf(stderr,
402 _("%s: %s can't malloc %u bytes: %s\n"),
403 progname, __FUNCTION__, bytes,
404 strerror(errno));
405 exit(1);
406 }
407 bp->b_nmaps = nmaps;
408
409 bytes = 0;
410 for ( i = 0; i < nmaps; i++) {
411 bp->b_map[i].bm_bn = map[i].bm_bn;
412 bp->b_map[i].bm_len = map[i].bm_len;
413 bytes += BBTOB(map[i].bm_len);
414 }
415
75c8b434 416 __initbuf(bp, btp, map[0].bm_bn, bytes);
a2ceac1f
DC
417 bp->b_flags |= LIBXFS_B_DISCONTIG;
418}
419
e6b359b3 420xfs_buf_t *
a2ceac1f 421__libxfs_getbufr(int blen)
e6b359b3
NS
422{
423 xfs_buf_t *bp;
69ec88b5
BN
424
425 /*
426 * first look for a buffer that can be used as-is,
427 * if one cannot be found, see if there is a buffer,
ff1f79a7 428 * and if so, free its buffer and set b_addr to NULL
69ec88b5
BN
429 * before calling libxfs_initbuf.
430 */
431 pthread_mutex_lock(&xfs_buf_freelist.cm_mutex);
432 if (!list_empty(&xfs_buf_freelist.cm_list)) {
433 list_for_each_entry(bp, &xfs_buf_freelist.cm_list, b_node.cn_mru) {
434 if (bp->b_bcount == blen) {
435 list_del_init(&bp->b_node.cn_mru);
436 break;
437 }
438 }
439 if (&bp->b_node.cn_mru == &xfs_buf_freelist.cm_list) {
440 bp = list_entry(xfs_buf_freelist.cm_list.next,
441 xfs_buf_t, b_node.cn_mru);
442 list_del_init(&bp->b_node.cn_mru);
443 free(bp->b_addr);
444 bp->b_addr = NULL;
a2ceac1f
DC
445 free(bp->b_map);
446 bp->b_map = NULL;
69ec88b5
BN
447 }
448 } else
5e656dbb 449 bp = kmem_zone_zalloc(xfs_buf_zone, 0);
69ec88b5 450 pthread_mutex_unlock(&xfs_buf_freelist.cm_mutex);
e0607266 451 bp->b_ops = NULL;
e6b359b3 452
a2ceac1f
DC
453 return bp;
454}
455
456xfs_buf_t *
75c8b434 457libxfs_getbufr(struct xfs_buftarg *btp, xfs_daddr_t blkno, int bblen)
a2ceac1f
DC
458{
459 xfs_buf_t *bp;
460 int blen = BBTOB(bblen);
461
462 bp =__libxfs_getbufr(blen);
463 if (bp)
75c8b434 464 libxfs_initbuf(bp, btp, blkno, blen);
2556c98b 465#ifdef IO_DEBUG
a2ceac1f 466 printf("%lx: %s: allocated %u bytes buffer, key=0x%llx(0x%llx), %p\n",
f63fd268 467 pthread_self(), __FUNCTION__, blen,
2556c98b
BN
468 (long long)LIBXFS_BBTOOFF64(blkno), (long long)blkno, bp);
469#endif
69ec88b5 470
e6b359b3
NS
471 return bp;
472}
473
a2ceac1f 474xfs_buf_t *
75c8b434 475libxfs_getbufr_map(struct xfs_buftarg *btp, xfs_daddr_t blkno, int bblen,
a2ceac1f
DC
476 struct xfs_buf_map *map, int nmaps)
477{
478 xfs_buf_t *bp;
479 int blen = BBTOB(bblen);
480
481 if (!map || !nmaps) {
482 fprintf(stderr,
483 _("%s: %s invalid map %p or nmaps %d\n"),
484 progname, __FUNCTION__, map, nmaps);
485 exit(1);
486 }
487
488 if (blkno != map[0].bm_bn) {
489 fprintf(stderr,
490 _("%s: %s map blkno %lx doesn't match key %lx\n"),
491 progname, __FUNCTION__, map[0].bm_bn, blkno);
492 exit(1);
493 }
494
495 bp =__libxfs_getbufr(blen);
496 if (bp)
75c8b434 497 libxfs_initbuf_map(bp, btp, map, nmaps);
a2ceac1f
DC
498#ifdef IO_DEBUG
499 printf("%lx: %s: allocated %u bytes buffer, key=0x%llx(0x%llx), %p\n",
500 pthread_self(), __FUNCTION__, blen,
501 (long long)LIBXFS_BBTOOFF64(blkno), (long long)blkno, bp);
502#endif
503
504 return bp;
505}
2556c98b
BN
506
507#ifdef XFS_BUF_TRACING
508struct list_head lock_buf_list = {&lock_buf_list, &lock_buf_list};
509int lock_buf_count = 0;
510#endif
e6b359b3 511
d0572de5
BN
512extern int use_xfs_buf_lock;
513
a2ceac1f
DC
514static struct xfs_buf *
515__cache_lookup(struct xfs_bufkey *key, unsigned int flags)
2bd0ea18 516{
a2ceac1f 517 struct xfs_buf *bp;
2556c98b 518
a2ceac1f 519 cache_node_get(libxfs_bcache, key, (struct cache_node **)&bp);
2ae22647
CH
520 if (!bp)
521 return NULL;
522
523 if (use_xfs_buf_lock) {
50722af1
CH
524 int ret;
525
526 ret = pthread_mutex_trylock(&bp->b_lock);
527 if (ret) {
528 ASSERT(ret == EAGAIN);
529 if (flags & LIBXFS_GETBUF_TRYLOCK)
530 goto out_put;
531
532 if (pthread_equal(bp->b_holder, pthread_self())) {
533 fprintf(stderr,
534 _("Warning: recursive buffer locking at block %" PRIu64 " detected\n"),
a2ceac1f 535 key->blkno);
50722af1
CH
536 bp->b_recur++;
537 return bp;
538 } else {
539 pthread_mutex_lock(&bp->b_lock);
2ae22647 540 }
2ae22647 541 }
50722af1
CH
542
543 bp->b_holder = pthread_self();
2ae22647
CH
544 }
545
546 cache_node_set_priority(libxfs_bcache, (struct cache_node *)bp,
547 cache_node_get_priority((struct cache_node *)bp) -
a040d7c9 548 CACHE_PREFETCH_PRIORITY);
2556c98b 549#ifdef XFS_BUF_TRACING
2ae22647
CH
550 pthread_mutex_lock(&libxfs_bcache->c_mutex);
551 lock_buf_count++;
552 list_add(&bp->b_lock_list, &lock_buf_list);
553 pthread_mutex_unlock(&libxfs_bcache->c_mutex);
2556c98b 554#endif
2bd0ea18 555#ifdef IO_DEBUG
a2ceac1f
DC
556 printf("%lx %s: hit buffer %p for bno = 0x%llx/0x%llx\n",
557 pthread_self(), __FUNCTION__,
558 bp, bp->b_bn, (long long)LIBXFS_BBTOOFF64(key->blkno));
2bd0ea18 559#endif
2556c98b 560
f1b058f9 561 return bp;
50722af1
CH
562out_put:
563 cache_node_put(libxfs_bcache, (struct cache_node *)bp);
564 return NULL;
f1b058f9
NS
565}
566
a2ceac1f 567struct xfs_buf *
75c8b434
DC
568libxfs_getbuf_flags(struct xfs_buftarg *btp, xfs_daddr_t blkno, int len,
569 unsigned int flags)
a2ceac1f
DC
570{
571 struct xfs_bufkey key = {0};
572
75c8b434 573 key.buftarg = btp;
a2ceac1f
DC
574 key.blkno = blkno;
575 key.bblen = len;
576
577 return __cache_lookup(&key, flags);
578}
579
2ae22647 580struct xfs_buf *
75c8b434 581libxfs_getbuf(struct xfs_buftarg *btp, xfs_daddr_t blkno, int len)
2ae22647 582{
75c8b434 583 return libxfs_getbuf_flags(btp, blkno, len, 0);
2ae22647
CH
584}
585
a2ceac1f 586struct xfs_buf *
7e3ab890
DC
587libxfs_getbuf_map(struct xfs_buftarg *btp, struct xfs_buf_map *map,
588 int nmaps, int flags)
a2ceac1f
DC
589{
590 struct xfs_bufkey key = {0};
591 int i;
592
75c8b434 593 key.buftarg = btp;
a2ceac1f
DC
594 key.blkno = map[0].bm_bn;
595 for (i = 0; i < nmaps; i++) {
596 key.bblen += map[i].bm_len;
597 }
598 key.map = map;
599 key.nmaps = nmaps;
600
7e3ab890 601 return __cache_lookup(&key, flags);
a2ceac1f
DC
602}
603
f1b058f9
NS
604void
605libxfs_putbuf(xfs_buf_t *bp)
606{
2556c98b
BN
607#ifdef XFS_BUF_TRACING
608 pthread_mutex_lock(&libxfs_bcache->c_mutex);
609 lock_buf_count--;
610 ASSERT(lock_buf_count >= 0);
611 list_del_init(&bp->b_lock_list);
612 pthread_mutex_unlock(&libxfs_bcache->c_mutex);
613#endif
50722af1
CH
614 if (use_xfs_buf_lock) {
615 if (bp->b_recur) {
616 bp->b_recur--;
617 } else {
618 bp->b_holder = 0;
619 pthread_mutex_unlock(&bp->b_lock);
620 }
621 }
a040d7c9 622 cache_node_put(libxfs_bcache, (struct cache_node *)bp);
f1b058f9
NS
623}
624
625void
626libxfs_purgebuf(xfs_buf_t *bp)
627{
a2ceac1f 628 struct xfs_bufkey key = {0};
f1b058f9 629
75c8b434 630 key.buftarg = bp->b_target;
5dfa5cd2 631 key.blkno = bp->b_bn;
75c8b434 632 key.bblen = bp->b_length;
f1b058f9
NS
633
634 cache_node_purge(libxfs_bcache, &key, (struct cache_node *)bp);
635}
2bd0ea18 636
f1b058f9 637static struct cache_node *
2556c98b 638libxfs_balloc(cache_key_t key)
f1b058f9 639{
a2ceac1f 640 struct xfs_bufkey *bufkey = (struct xfs_bufkey *)key;
2556c98b 641
a2ceac1f
DC
642 if (bufkey->map)
643 return (struct cache_node *)
75c8b434 644 libxfs_getbufr_map(bufkey->buftarg,
a2ceac1f
DC
645 bufkey->blkno, bufkey->bblen,
646 bufkey->map, bufkey->nmaps);
75c8b434 647 return (struct cache_node *)libxfs_getbufr(bufkey->buftarg,
a2ceac1f 648 bufkey->blkno, bufkey->bblen);
2bd0ea18
NS
649}
650
a2ceac1f
DC
651
652static int
653__read_buf(int fd, void *buf, int len, off64_t offset, int flags)
2bd0ea18 654{
bcea58c7 655 int sts;
2bd0ea18 656
a2ceac1f 657 sts = pread64(fd, buf, len, offset);
bcea58c7 658 if (sts < 0) {
a2ceac1f 659 int error = errno;
9440d84d 660 fprintf(stderr, _("%s: read failed: %s\n"),
c3928e39 661 progname, strerror(error));
9440d84d 662 if (flags & LIBXFS_EXIT_ON_FAILURE)
2bd0ea18 663 exit(1);
c3928e39 664 return error;
a2ceac1f 665 } else if (sts != len) {
bcea58c7 666 fprintf(stderr, _("%s: error - read only %d of %d bytes\n"),
a2ceac1f 667 progname, sts, len);
bcea58c7
CH
668 if (flags & LIBXFS_EXIT_ON_FAILURE)
669 exit(1);
670 return EIO;
2bd0ea18 671 }
a2ceac1f
DC
672 return 0;
673}
674
675int
75c8b434
DC
676libxfs_readbufr(struct xfs_buftarg *btp, xfs_daddr_t blkno, xfs_buf_t *bp,
677 int len, int flags)
a2ceac1f 678{
75c8b434 679 int fd = libxfs_device_to_fd(btp->dev);
a2ceac1f
DC
680 int bytes = BBTOB(len);
681 int error;
682
683 ASSERT(BBTOB(len) <= bp->b_bcount);
684
685 error = __read_buf(fd, bp->b_addr, bytes, LIBXFS_BBTOOFF64(blkno), flags);
686 if (!error &&
75c8b434 687 bp->b_target->dev == btp->dev &&
5dfa5cd2 688 bp->b_bn == blkno &&
f1b058f9
NS
689 bp->b_bcount == bytes)
690 bp->b_flags |= LIBXFS_B_UPTODATE;
a2ceac1f
DC
691#ifdef IO_DEBUG
692 printf("%lx: %s: read %u bytes, error %d, blkno=0x%llx(0x%llx), %p\n",
693 pthread_self(), __FUNCTION__, bytes, error,
694 (long long)LIBXFS_BBTOOFF64(blkno), (long long)blkno, bp);
695#endif
696 return error;
2bd0ea18
NS
697}
698
699xfs_buf_t *
75c8b434
DC
700libxfs_readbuf(struct xfs_buftarg *btp, xfs_daddr_t blkno, int len, int flags,
701 const struct xfs_buf_ops *ops)
2bd0ea18 702{
f1b058f9 703 xfs_buf_t *bp;
2bd0ea18
NS
704 int error;
705
75c8b434
DC
706 bp = libxfs_getbuf(btp, blkno, len);
707 if (!bp)
708 return NULL;
709 if ((bp->b_flags & (LIBXFS_B_UPTODATE|LIBXFS_B_DIRTY)))
710 return bp;
711
712 /*
713 * only set the ops on a cache miss (i.e. first physical read) as the
714 * verifier may change the ops to match the typ eof buffer it contains.
715 * A cache hit might reset the verifier to the original type if we set
716 * it again, but it won't get called again and set to match the buffer
717 * contents. *cough* xfs_da_node_buf_ops *cough*.
718 */
719 bp->b_error = 0;
720 bp->b_ops = ops;
721 error = libxfs_readbufr(btp, blkno, bp, len, flags);
722 if (error)
723 bp->b_error = error;
724 else if (bp->b_ops)
725 bp->b_ops->verify_read(bp);
f1b058f9 726 return bp;
2bd0ea18
NS
727}
728
800db1c1
DC
729int
730libxfs_readbufr_map(struct xfs_buftarg *btp, struct xfs_buf *bp,
731 struct xfs_buf_map *map, int nmaps, int flags)
a2ceac1f 732{
800db1c1
DC
733 int fd = libxfs_device_to_fd(btp->dev);
734 int error = 0;
735 char *buf;
736 int i;
75c8b434 737
800db1c1 738 ASSERT(BBTOB(len) <= bp->b_bcount);
a2ceac1f 739
800db1c1 740 ASSERT(bp->b_nmaps == nmaps);
a2ceac1f 741
75c8b434 742 fd = libxfs_device_to_fd(btp->dev);
a2ceac1f
DC
743 buf = bp->b_addr;
744 for (i = 0; i < bp->b_nmaps; i++) {
745 off64_t offset = LIBXFS_BBTOOFF64(bp->b_map[i].bm_bn);
746 int len = BBTOB(bp->b_map[i].bm_len);
747
748 ASSERT(bp->b_map[i].bm_bn == map[i].bm_bn);
749 ASSERT(bp->b_map[i].bm_len == map[i].bm_len);
750
751 error = __read_buf(fd, buf, len, offset, flags);
752 if (error) {
753 bp->b_error = error;
754 break;
755 }
756 buf += len;
757 offset += len;
758 }
759
64eb960f 760 if (!error)
800db1c1
DC
761 bp->b_flags |= LIBXFS_B_UPTODATE;
762#ifdef IO_DEBUG
763 printf("%lx: %s: read %u bytes, error %d, blkno=0x%llx(0x%llx), %p\n",
764 pthread_self(), __FUNCTION__, , error,
765 (long long)LIBXFS_BBTOOFF64(blkno), (long long)blkno, bp);
766#endif
767 return error;
768}
769
770struct xfs_buf *
771libxfs_readbuf_map(struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps,
772 int flags, const struct xfs_buf_ops *ops)
773{
774 struct xfs_buf *bp;
775 int error = 0;
776
777 if (nmaps == 1)
778 return libxfs_readbuf(btp, map[0].bm_bn, map[0].bm_len,
779 flags, ops);
780
7e3ab890 781 bp = libxfs_getbuf_map(btp, map, nmaps, 0);
800db1c1
DC
782 if (!bp)
783 return NULL;
784
785 bp->b_error = 0;
786 bp->b_ops = ops;
787 if ((bp->b_flags & (LIBXFS_B_UPTODATE|LIBXFS_B_DIRTY)))
788 return bp;
789
790 error = libxfs_readbufr_map(btp, bp, map, nmaps, flags);
75c8b434 791 if (!error) {
a2ceac1f 792 bp->b_flags |= LIBXFS_B_UPTODATE;
75c8b434
DC
793 if (bp->b_ops)
794 bp->b_ops->verify_read(bp);
795 }
a2ceac1f
DC
796#ifdef IO_DEBUG
797 printf("%lx: %s: read %lu bytes, error %d, blkno=%llu(%llu), %p\n",
798 pthread_self(), __FUNCTION__, buf - (char *)bp->b_addr, error,
5dfa5cd2 799 (long long)LIBXFS_BBTOOFF64(bp->b_bn), (long long)bp->b_bn, bp);
a2ceac1f
DC
800#endif
801 return bp;
802}
803
804static int
805__write_buf(int fd, void *buf, int len, off64_t offset, int flags)
2bd0ea18
NS
806{
807 int sts;
2bd0ea18 808
a2ceac1f 809 sts = pwrite64(fd, buf, len, offset);
2bd0ea18 810 if (sts < 0) {
a2ceac1f 811 int error = errno;
9440d84d 812 fprintf(stderr, _("%s: pwrite64 failed: %s\n"),
c3928e39 813 progname, strerror(error));
a2ceac1f 814 if (flags & LIBXFS_B_EXIT)
2bd0ea18 815 exit(1);
c3928e39 816 return error;
a2ceac1f
DC
817 } else if (sts != len) {
818 fprintf(stderr, _("%s: error - pwrite64 only %d of %d bytes\n"),
819 progname, sts, len);
820 if (flags & LIBXFS_B_EXIT)
2bd0ea18
NS
821 exit(1);
822 return EIO;
823 }
a2ceac1f
DC
824 return 0;
825}
826
827int
828libxfs_writebufr(xfs_buf_t *bp)
829{
75c8b434 830 int fd = libxfs_device_to_fd(bp->b_target->dev);
a2ceac1f
DC
831 int error = 0;
832
75c8b434
DC
833 /*
834 * we never write buffers that are marked stale. This indicates they
835 * contain data that has been invalidated, and even if the buffer is
836 * dirty it must *never* be written. Verifiers are wonderful for finding
837 * bugs like this. Make sure the error is obvious as to the cause.
838 */
839 if (bp->b_flags & LIBXFS_B_STALE) {
840 bp->b_error = ESTALE;
841 return bp->b_error;
842 }
843
844 /*
845 * clear any pre-existing error status on the buffer. This can occur if
846 * the buffer is corrupt on disk and the repair process doesn't clear
847 * the error before fixing and writing it back.
848 */
849 bp->b_error = 0;
850 if (bp->b_ops) {
851 bp->b_ops->verify_write(bp);
852 if (bp->b_error) {
853 fprintf(stderr,
854 _("%s: write verifer failed on bno 0x%llx/0x%x\n"),
855 __func__, (long long)bp->b_bn, bp->b_bcount);
856 return bp->b_error;
857 }
858 }
859
a2ceac1f
DC
860 if (!(bp->b_flags & LIBXFS_B_DISCONTIG)) {
861 error = __write_buf(fd, bp->b_addr, bp->b_bcount,
5dfa5cd2 862 LIBXFS_BBTOOFF64(bp->b_bn), bp->b_flags);
a2ceac1f
DC
863 } else {
864 int i;
865 char *buf = bp->b_addr;
866
867 for (i = 0; i < bp->b_nmaps; i++) {
868 off64_t offset = LIBXFS_BBTOOFF64(bp->b_map[i].bm_bn);
869 int len = BBTOB(bp->b_map[i].bm_len);
870
871 error = __write_buf(fd, buf, len, offset, bp->b_flags);
872 if (error) {
873 bp->b_error = error;
874 break;
875 }
876 buf += len;
877 offset += len;
878 }
879 }
880
f1b058f9 881#ifdef IO_DEBUG
2556c98b
BN
882 printf("%lx: %s: wrote %u bytes, blkno=%llu(%llu), %p\n",
883 pthread_self(), __FUNCTION__, bp->b_bcount,
5dfa5cd2
DC
884 (long long)LIBXFS_BBTOOFF64(bp->b_bn),
885 (long long)bp->b_bn, bp);
f1b058f9 886#endif
a2ceac1f
DC
887 if (!error) {
888 bp->b_flags |= LIBXFS_B_UPTODATE;
889 bp->b_flags &= ~(LIBXFS_B_DIRTY | LIBXFS_B_EXIT);
890 }
891 return error;
2bd0ea18
NS
892}
893
894int
f1b058f9 895libxfs_writebuf_int(xfs_buf_t *bp, int flags)
2bd0ea18 896{
f1b058f9
NS
897 bp->b_flags |= (LIBXFS_B_DIRTY | flags);
898 return 0;
899}
900
901int
902libxfs_writebuf(xfs_buf_t *bp, int flags)
903{
e0607266
DC
904#ifdef IO_DEBUG
905 printf("%lx: %s: dirty blkno=%llu(%llu)\n",
906 pthread_self(), __FUNCTION__,
907 (long long)LIBXFS_BBTOOFF64(bp->b_bn),
908 (long long)bp->b_bn);
909#endif
f1b058f9
NS
910 bp->b_flags |= (LIBXFS_B_DIRTY | flags);
911 libxfs_putbuf(bp);
912 return 0;
2bd0ea18
NS
913}
914
57c9fccb 915void
f1b058f9 916libxfs_iomove(xfs_buf_t *bp, uint boff, int len, void *data, int flags)
57c9fccb 917{
f1b058f9
NS
918#ifdef IO_DEBUG
919 if (boff + len > bp->b_bcount) {
2556c98b 920 printf("Badness, iomove out of range!\n"
a2ceac1f 921 "bp=(bno 0x%llx, bytes %u) range=(boff %u, bytes %u)\n",
5dfa5cd2 922 (long long)bp->b_bn, bp->b_bcount, boff, len);
57c9fccb 923 abort();
f1b058f9
NS
924 }
925#endif
57c9fccb
NS
926 switch (flags) {
927 case LIBXFS_BZERO:
f1b058f9 928 memset(bp->b_addr + boff, 0, len);
57c9fccb
NS
929 break;
930 case LIBXFS_BREAD:
f1b058f9 931 memcpy(data, bp->b_addr + boff, len);
57c9fccb
NS
932 break;
933 case LIBXFS_BWRITE:
f1b058f9 934 memcpy(bp->b_addr + boff, data, len);
57c9fccb
NS
935 break;
936 }
937}
938
33165ec3 939static void
69ec88b5 940libxfs_brelse(struct cache_node *node)
33165ec3
BN
941{
942 xfs_buf_t *bp = (xfs_buf_t *)node;
943
69ec88b5
BN
944 if (bp != NULL) {
945 if (bp->b_flags & LIBXFS_B_DIRTY)
946 libxfs_writebufr(bp);
947 pthread_mutex_lock(&xfs_buf_freelist.cm_mutex);
948 list_add(&bp->b_node.cn_mru, &xfs_buf_freelist.cm_list);
949 pthread_mutex_unlock(&xfs_buf_freelist.cm_mutex);
950 }
33165ec3
BN
951}
952
e08f5594 953static unsigned int
69ec88b5
BN
954libxfs_bulkrelse(
955 struct cache *cache,
956 struct list_head *list)
2556c98b 957{
69ec88b5 958 xfs_buf_t *bp;
e08f5594 959 int count = 0;
2556c98b 960
69ec88b5 961 if (list_empty(list))
e08f5594 962 return 0 ;
69ec88b5
BN
963
964 list_for_each_entry(bp, list, b_node.cn_mru) {
2556c98b
BN
965 if (bp->b_flags & LIBXFS_B_DIRTY)
966 libxfs_writebufr(bp);
e08f5594 967 count++;
2556c98b 968 }
69ec88b5
BN
969
970 pthread_mutex_lock(&xfs_buf_freelist.cm_mutex);
971 __list_splice(list, &xfs_buf_freelist.cm_list);
972 pthread_mutex_unlock(&xfs_buf_freelist.cm_mutex);
e08f5594
BN
973
974 return count;
69ec88b5
BN
975}
976
977static void
978libxfs_bflush(struct cache_node *node)
979{
980 xfs_buf_t *bp = (xfs_buf_t *)node;
981
982 if ((bp != NULL) && (bp->b_flags & LIBXFS_B_DIRTY))
983 libxfs_writebufr(bp);
2556c98b
BN
984}
985
986void
987libxfs_putbufr(xfs_buf_t *bp)
988{
989 libxfs_brelse((struct cache_node *)bp);
990}
991
992
f1b058f9
NS
993void
994libxfs_bcache_purge(void)
995{
996 cache_purge(libxfs_bcache);
997}
998
e8cb94ee 999void
33165ec3
BN
1000libxfs_bcache_flush(void)
1001{
1002 cache_flush(libxfs_bcache);
1003}
1004
2556c98b
BN
1005int
1006libxfs_bcache_overflowed(void)
1007{
1008 return cache_overflowed(libxfs_bcache);
1009}
1010
f1b058f9
NS
1011struct cache_operations libxfs_bcache_operations = {
1012 /* .hash */ libxfs_bhash,
1013 /* .alloc */ libxfs_balloc,
33165ec3 1014 /* .flush */ libxfs_bflush,
f1b058f9
NS
1015 /* .relse */ libxfs_brelse,
1016 /* .compare */ libxfs_bcompare,
69ec88b5 1017 /* .bulkrelse */libxfs_bulkrelse
f1b058f9
NS
1018};
1019
2bd0ea18 1020
f1b058f9 1021/*
3a19fb7d 1022 * Inode cache stubs.
f1b058f9
NS
1023 */
1024
5e656dbb
BN
1025extern kmem_zone_t *xfs_ili_zone;
1026extern kmem_zone_t *xfs_inode_zone;
f1b058f9 1027
2bd0ea18
NS
1028int
1029libxfs_iget(xfs_mount_t *mp, xfs_trans_t *tp, xfs_ino_t ino, uint lock_flags,
1030 xfs_inode_t **ipp, xfs_daddr_t bno)
1031{
1032 xfs_inode_t *ip;
f1b058f9 1033 int error = 0;
2bd0ea18 1034
3a19fb7d
CH
1035 ip = kmem_zone_zalloc(xfs_inode_zone, 0);
1036 if (!ip)
1037 return ENOMEM;
2bd0ea18 1038
3a19fb7d
CH
1039 ip->i_ino = ino;
1040 ip->i_mount = mp;
1041 error = xfs_iread(mp, tp, ip, bno);
1042 if (error) {
1043 kmem_zone_free(xfs_inode_zone, ip);
1044 *ipp = NULL;
1045 return error;
1046 }
f1b058f9 1047
3a19fb7d
CH
1048 *ipp = ip;
1049 return 0;
f1b058f9
NS
1050}
1051
1052static void
014e5f6d
ES
1053libxfs_idestroy(xfs_inode_t *ip)
1054{
1055 switch (ip->i_d.di_mode & S_IFMT) {
1056 case S_IFREG:
1057 case S_IFDIR:
1058 case S_IFLNK:
1059 libxfs_idestroy_fork(ip, XFS_DATA_FORK);
1060 break;
1061 }
1062 if (ip->i_afp)
1063 libxfs_idestroy_fork(ip, XFS_ATTR_FORK);
1064}
1065
2bd0ea18 1066void
3a19fb7d 1067libxfs_iput(xfs_inode_t *ip, uint lock_flags)
2bd0ea18 1068{
3a19fb7d
CH
1069 if (ip->i_itemp)
1070 kmem_zone_free(xfs_ili_zone, ip->i_itemp);
1071 ip->i_itemp = NULL;
1072 libxfs_idestroy(ip);
1073 kmem_zone_free(xfs_inode_zone, ip);
2bd0ea18 1074}