]>
Commit | Line | Data |
---|---|---|
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 | 26 | void |
75c8b434 | 27 | libxfs_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 | 70 | static 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 | ||
91 | static 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 | ||
100 | int | |
101 | libxfs_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 |
130 | int |
131 | libxfs_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 | 200 | xfs_buf_t *libxfs_readbuf(struct xfs_buftarg *, xfs_daddr_t, int, int, |
f756f80c | 201 | const struct xfs_buf_ops *); |
75c8b434 | 202 | xfs_buf_t *libxfs_readbuf_map(struct xfs_buftarg *, struct xfs_buf_map *, |
f756f80c | 203 | int, int, const struct xfs_buf_ops *); |
2556c98b | 204 | int libxfs_writebuf(xfs_buf_t *, int); |
75c8b434 | 205 | xfs_buf_t *libxfs_getbuf(struct xfs_buftarg *, xfs_daddr_t, int); |
7e3ab890 DC |
206 | xfs_buf_t *libxfs_getbuf_map(struct xfs_buftarg *, struct xfs_buf_map *, |
207 | int, int); | |
75c8b434 DC |
208 | xfs_buf_t *libxfs_getbuf_flags(struct xfs_buftarg *, xfs_daddr_t, int, |
209 | unsigned int); | |
2556c98b BN |
210 | void libxfs_putbuf (xfs_buf_t *); |
211 | ||
a2ceac1f DC |
212 | #define __add_trace(bp, func, file, line) \ |
213 | do { \ | |
214 | if (bp) { \ | |
215 | (bp)->b_func = (func); \ | |
216 | (bp)->b_file = (file); \ | |
217 | (bp)->b_line = (line); \ | |
218 | } \ | |
219 | } while (0) | |
220 | ||
2556c98b | 221 | xfs_buf_t * |
a2ceac1f | 222 | libxfs_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 |
231 | xfs_buf_t * |
232 | libxfs_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 | ||
241 | int | |
242 | libxfs_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 | ||
248 | xfs_buf_t * | |
a2ceac1f | 249 | libxfs_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 |
257 | xfs_buf_t * |
258 | libxfs_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 |
267 | xfs_buf_t * |
268 | libxfs_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 |
276 | void |
277 | libxfs_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 |
287 | xfs_buf_t * |
288 | libxfs_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 | 294 | kmem_zone_t *xfs_buf_zone; |
69ec88b5 BN |
295 | |
296 | static 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 | */ | |
308 | struct 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 | |
316 | static unsigned int | |
317 | libxfs_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 | ||
322 | static int | |
323 | libxfs_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 | ||
348 | void | |
349 | libxfs_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 | 356 | static 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 | 384 | static void |
75c8b434 DC |
385 | libxfs_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 | ||
391 | static void | |
75c8b434 DC |
392 | libxfs_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 | 420 | xfs_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 | ||
456 | xfs_buf_t * | |
75c8b434 | 457 | libxfs_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 | 474 | xfs_buf_t * |
75c8b434 | 475 | libxfs_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 | |
508 | struct list_head lock_buf_list = {&lock_buf_list, &lock_buf_list}; | |
509 | int lock_buf_count = 0; | |
510 | #endif | |
e6b359b3 | 511 | |
d0572de5 BN |
512 | extern int use_xfs_buf_lock; |
513 | ||
a2ceac1f DC |
514 | static 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 |
562 | out_put: |
563 | cache_node_put(libxfs_bcache, (struct cache_node *)bp); | |
564 | return NULL; | |
f1b058f9 NS |
565 | } |
566 | ||
a2ceac1f | 567 | struct xfs_buf * |
75c8b434 DC |
568 | libxfs_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 | 580 | struct xfs_buf * |
75c8b434 | 581 | libxfs_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 | 586 | struct xfs_buf * |
7e3ab890 DC |
587 | libxfs_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 | ||
f388124d DC |
593 | if (nmaps == 1) |
594 | return libxfs_getbuf_flags(btp, map[0].bm_bn, map[0].bm_len, | |
595 | flags); | |
596 | ||
75c8b434 | 597 | key.buftarg = btp; |
a2ceac1f DC |
598 | key.blkno = map[0].bm_bn; |
599 | for (i = 0; i < nmaps; i++) { | |
600 | key.bblen += map[i].bm_len; | |
601 | } | |
602 | key.map = map; | |
603 | key.nmaps = nmaps; | |
604 | ||
7e3ab890 | 605 | return __cache_lookup(&key, flags); |
a2ceac1f DC |
606 | } |
607 | ||
f1b058f9 NS |
608 | void |
609 | libxfs_putbuf(xfs_buf_t *bp) | |
610 | { | |
2556c98b BN |
611 | #ifdef XFS_BUF_TRACING |
612 | pthread_mutex_lock(&libxfs_bcache->c_mutex); | |
613 | lock_buf_count--; | |
614 | ASSERT(lock_buf_count >= 0); | |
615 | list_del_init(&bp->b_lock_list); | |
616 | pthread_mutex_unlock(&libxfs_bcache->c_mutex); | |
617 | #endif | |
50722af1 CH |
618 | if (use_xfs_buf_lock) { |
619 | if (bp->b_recur) { | |
620 | bp->b_recur--; | |
621 | } else { | |
622 | bp->b_holder = 0; | |
623 | pthread_mutex_unlock(&bp->b_lock); | |
624 | } | |
625 | } | |
a040d7c9 | 626 | cache_node_put(libxfs_bcache, (struct cache_node *)bp); |
f1b058f9 NS |
627 | } |
628 | ||
629 | void | |
630 | libxfs_purgebuf(xfs_buf_t *bp) | |
631 | { | |
a2ceac1f | 632 | struct xfs_bufkey key = {0}; |
f1b058f9 | 633 | |
75c8b434 | 634 | key.buftarg = bp->b_target; |
5dfa5cd2 | 635 | key.blkno = bp->b_bn; |
75c8b434 | 636 | key.bblen = bp->b_length; |
f1b058f9 NS |
637 | |
638 | cache_node_purge(libxfs_bcache, &key, (struct cache_node *)bp); | |
639 | } | |
2bd0ea18 | 640 | |
f1b058f9 | 641 | static struct cache_node * |
2556c98b | 642 | libxfs_balloc(cache_key_t key) |
f1b058f9 | 643 | { |
a2ceac1f | 644 | struct xfs_bufkey *bufkey = (struct xfs_bufkey *)key; |
2556c98b | 645 | |
a2ceac1f DC |
646 | if (bufkey->map) |
647 | return (struct cache_node *) | |
75c8b434 | 648 | libxfs_getbufr_map(bufkey->buftarg, |
a2ceac1f DC |
649 | bufkey->blkno, bufkey->bblen, |
650 | bufkey->map, bufkey->nmaps); | |
75c8b434 | 651 | return (struct cache_node *)libxfs_getbufr(bufkey->buftarg, |
a2ceac1f | 652 | bufkey->blkno, bufkey->bblen); |
2bd0ea18 NS |
653 | } |
654 | ||
a2ceac1f DC |
655 | |
656 | static int | |
657 | __read_buf(int fd, void *buf, int len, off64_t offset, int flags) | |
2bd0ea18 | 658 | { |
bcea58c7 | 659 | int sts; |
2bd0ea18 | 660 | |
a2ceac1f | 661 | sts = pread64(fd, buf, len, offset); |
bcea58c7 | 662 | if (sts < 0) { |
a2ceac1f | 663 | int error = errno; |
9440d84d | 664 | fprintf(stderr, _("%s: read failed: %s\n"), |
c3928e39 | 665 | progname, strerror(error)); |
9440d84d | 666 | if (flags & LIBXFS_EXIT_ON_FAILURE) |
2bd0ea18 | 667 | exit(1); |
c3928e39 | 668 | return error; |
a2ceac1f | 669 | } else if (sts != len) { |
bcea58c7 | 670 | fprintf(stderr, _("%s: error - read only %d of %d bytes\n"), |
a2ceac1f | 671 | progname, sts, len); |
bcea58c7 CH |
672 | if (flags & LIBXFS_EXIT_ON_FAILURE) |
673 | exit(1); | |
674 | return EIO; | |
2bd0ea18 | 675 | } |
a2ceac1f DC |
676 | return 0; |
677 | } | |
678 | ||
679 | int | |
75c8b434 DC |
680 | libxfs_readbufr(struct xfs_buftarg *btp, xfs_daddr_t blkno, xfs_buf_t *bp, |
681 | int len, int flags) | |
a2ceac1f | 682 | { |
75c8b434 | 683 | int fd = libxfs_device_to_fd(btp->dev); |
a2ceac1f DC |
684 | int bytes = BBTOB(len); |
685 | int error; | |
686 | ||
687 | ASSERT(BBTOB(len) <= bp->b_bcount); | |
688 | ||
689 | error = __read_buf(fd, bp->b_addr, bytes, LIBXFS_BBTOOFF64(blkno), flags); | |
690 | if (!error && | |
75c8b434 | 691 | bp->b_target->dev == btp->dev && |
5dfa5cd2 | 692 | bp->b_bn == blkno && |
f1b058f9 NS |
693 | bp->b_bcount == bytes) |
694 | bp->b_flags |= LIBXFS_B_UPTODATE; | |
a2ceac1f DC |
695 | #ifdef IO_DEBUG |
696 | printf("%lx: %s: read %u bytes, error %d, blkno=0x%llx(0x%llx), %p\n", | |
697 | pthread_self(), __FUNCTION__, bytes, error, | |
698 | (long long)LIBXFS_BBTOOFF64(blkno), (long long)blkno, bp); | |
699 | #endif | |
700 | return error; | |
2bd0ea18 NS |
701 | } |
702 | ||
703 | xfs_buf_t * | |
75c8b434 DC |
704 | libxfs_readbuf(struct xfs_buftarg *btp, xfs_daddr_t blkno, int len, int flags, |
705 | const struct xfs_buf_ops *ops) | |
2bd0ea18 | 706 | { |
f1b058f9 | 707 | xfs_buf_t *bp; |
2bd0ea18 NS |
708 | int error; |
709 | ||
75c8b434 DC |
710 | bp = libxfs_getbuf(btp, blkno, len); |
711 | if (!bp) | |
712 | return NULL; | |
713 | if ((bp->b_flags & (LIBXFS_B_UPTODATE|LIBXFS_B_DIRTY))) | |
714 | return bp; | |
715 | ||
716 | /* | |
717 | * only set the ops on a cache miss (i.e. first physical read) as the | |
718 | * verifier may change the ops to match the typ eof buffer it contains. | |
719 | * A cache hit might reset the verifier to the original type if we set | |
720 | * it again, but it won't get called again and set to match the buffer | |
721 | * contents. *cough* xfs_da_node_buf_ops *cough*. | |
722 | */ | |
723 | bp->b_error = 0; | |
724 | bp->b_ops = ops; | |
725 | error = libxfs_readbufr(btp, blkno, bp, len, flags); | |
726 | if (error) | |
727 | bp->b_error = error; | |
728 | else if (bp->b_ops) | |
729 | bp->b_ops->verify_read(bp); | |
f1b058f9 | 730 | return bp; |
2bd0ea18 NS |
731 | } |
732 | ||
800db1c1 | 733 | int |
6d5e5ee0 | 734 | libxfs_readbufr_map(struct xfs_buftarg *btp, struct xfs_buf *bp, int flags) |
a2ceac1f | 735 | { |
800db1c1 DC |
736 | int fd = libxfs_device_to_fd(btp->dev); |
737 | int error = 0; | |
738 | char *buf; | |
739 | int i; | |
75c8b434 | 740 | |
75c8b434 | 741 | fd = libxfs_device_to_fd(btp->dev); |
a2ceac1f DC |
742 | buf = bp->b_addr; |
743 | for (i = 0; i < bp->b_nmaps; i++) { | |
744 | off64_t offset = LIBXFS_BBTOOFF64(bp->b_map[i].bm_bn); | |
745 | int len = BBTOB(bp->b_map[i].bm_len); | |
746 | ||
a2ceac1f DC |
747 | error = __read_buf(fd, buf, len, offset, flags); |
748 | if (error) { | |
749 | bp->b_error = error; | |
750 | break; | |
751 | } | |
752 | buf += len; | |
753 | offset += len; | |
754 | } | |
755 | ||
64eb960f | 756 | if (!error) |
800db1c1 DC |
757 | bp->b_flags |= LIBXFS_B_UPTODATE; |
758 | #ifdef IO_DEBUG | |
759 | printf("%lx: %s: read %u bytes, error %d, blkno=0x%llx(0x%llx), %p\n", | |
760 | pthread_self(), __FUNCTION__, , error, | |
761 | (long long)LIBXFS_BBTOOFF64(blkno), (long long)blkno, bp); | |
762 | #endif | |
763 | return error; | |
764 | } | |
765 | ||
766 | struct xfs_buf * | |
767 | libxfs_readbuf_map(struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps, | |
768 | int flags, const struct xfs_buf_ops *ops) | |
769 | { | |
770 | struct xfs_buf *bp; | |
771 | int error = 0; | |
772 | ||
773 | if (nmaps == 1) | |
774 | return libxfs_readbuf(btp, map[0].bm_bn, map[0].bm_len, | |
775 | flags, ops); | |
776 | ||
7e3ab890 | 777 | bp = libxfs_getbuf_map(btp, map, nmaps, 0); |
800db1c1 DC |
778 | if (!bp) |
779 | return NULL; | |
780 | ||
781 | bp->b_error = 0; | |
782 | bp->b_ops = ops; | |
783 | if ((bp->b_flags & (LIBXFS_B_UPTODATE|LIBXFS_B_DIRTY))) | |
784 | return bp; | |
785 | ||
6d5e5ee0 | 786 | error = libxfs_readbufr_map(btp, bp, flags); |
75c8b434 | 787 | if (!error) { |
a2ceac1f | 788 | bp->b_flags |= LIBXFS_B_UPTODATE; |
75c8b434 DC |
789 | if (bp->b_ops) |
790 | bp->b_ops->verify_read(bp); | |
791 | } | |
a2ceac1f DC |
792 | #ifdef IO_DEBUG |
793 | printf("%lx: %s: read %lu bytes, error %d, blkno=%llu(%llu), %p\n", | |
794 | pthread_self(), __FUNCTION__, buf - (char *)bp->b_addr, error, | |
5dfa5cd2 | 795 | (long long)LIBXFS_BBTOOFF64(bp->b_bn), (long long)bp->b_bn, bp); |
a2ceac1f DC |
796 | #endif |
797 | return bp; | |
798 | } | |
799 | ||
800 | static int | |
801 | __write_buf(int fd, void *buf, int len, off64_t offset, int flags) | |
2bd0ea18 NS |
802 | { |
803 | int sts; | |
2bd0ea18 | 804 | |
a2ceac1f | 805 | sts = pwrite64(fd, buf, len, offset); |
2bd0ea18 | 806 | if (sts < 0) { |
a2ceac1f | 807 | int error = errno; |
9440d84d | 808 | fprintf(stderr, _("%s: pwrite64 failed: %s\n"), |
c3928e39 | 809 | progname, strerror(error)); |
a2ceac1f | 810 | if (flags & LIBXFS_B_EXIT) |
2bd0ea18 | 811 | exit(1); |
c3928e39 | 812 | return error; |
a2ceac1f DC |
813 | } else if (sts != len) { |
814 | fprintf(stderr, _("%s: error - pwrite64 only %d of %d bytes\n"), | |
815 | progname, sts, len); | |
816 | if (flags & LIBXFS_B_EXIT) | |
2bd0ea18 NS |
817 | exit(1); |
818 | return EIO; | |
819 | } | |
a2ceac1f DC |
820 | return 0; |
821 | } | |
822 | ||
823 | int | |
824 | libxfs_writebufr(xfs_buf_t *bp) | |
825 | { | |
75c8b434 | 826 | int fd = libxfs_device_to_fd(bp->b_target->dev); |
a2ceac1f DC |
827 | int error = 0; |
828 | ||
75c8b434 DC |
829 | /* |
830 | * we never write buffers that are marked stale. This indicates they | |
831 | * contain data that has been invalidated, and even if the buffer is | |
832 | * dirty it must *never* be written. Verifiers are wonderful for finding | |
833 | * bugs like this. Make sure the error is obvious as to the cause. | |
834 | */ | |
835 | if (bp->b_flags & LIBXFS_B_STALE) { | |
836 | bp->b_error = ESTALE; | |
837 | return bp->b_error; | |
838 | } | |
839 | ||
840 | /* | |
841 | * clear any pre-existing error status on the buffer. This can occur if | |
842 | * the buffer is corrupt on disk and the repair process doesn't clear | |
843 | * the error before fixing and writing it back. | |
844 | */ | |
845 | bp->b_error = 0; | |
846 | if (bp->b_ops) { | |
847 | bp->b_ops->verify_write(bp); | |
848 | if (bp->b_error) { | |
849 | fprintf(stderr, | |
850 | _("%s: write verifer failed on bno 0x%llx/0x%x\n"), | |
851 | __func__, (long long)bp->b_bn, bp->b_bcount); | |
852 | return bp->b_error; | |
853 | } | |
854 | } | |
855 | ||
a2ceac1f DC |
856 | if (!(bp->b_flags & LIBXFS_B_DISCONTIG)) { |
857 | error = __write_buf(fd, bp->b_addr, bp->b_bcount, | |
5dfa5cd2 | 858 | LIBXFS_BBTOOFF64(bp->b_bn), bp->b_flags); |
a2ceac1f DC |
859 | } else { |
860 | int i; | |
861 | char *buf = bp->b_addr; | |
862 | ||
863 | for (i = 0; i < bp->b_nmaps; i++) { | |
864 | off64_t offset = LIBXFS_BBTOOFF64(bp->b_map[i].bm_bn); | |
865 | int len = BBTOB(bp->b_map[i].bm_len); | |
866 | ||
867 | error = __write_buf(fd, buf, len, offset, bp->b_flags); | |
868 | if (error) { | |
869 | bp->b_error = error; | |
870 | break; | |
871 | } | |
872 | buf += len; | |
873 | offset += len; | |
874 | } | |
875 | } | |
876 | ||
f1b058f9 | 877 | #ifdef IO_DEBUG |
2556c98b BN |
878 | printf("%lx: %s: wrote %u bytes, blkno=%llu(%llu), %p\n", |
879 | pthread_self(), __FUNCTION__, bp->b_bcount, | |
5dfa5cd2 DC |
880 | (long long)LIBXFS_BBTOOFF64(bp->b_bn), |
881 | (long long)bp->b_bn, bp); | |
f1b058f9 | 882 | #endif |
a2ceac1f DC |
883 | if (!error) { |
884 | bp->b_flags |= LIBXFS_B_UPTODATE; | |
885 | bp->b_flags &= ~(LIBXFS_B_DIRTY | LIBXFS_B_EXIT); | |
886 | } | |
887 | return error; | |
2bd0ea18 NS |
888 | } |
889 | ||
890 | int | |
f1b058f9 | 891 | libxfs_writebuf_int(xfs_buf_t *bp, int flags) |
2bd0ea18 | 892 | { |
f1b058f9 NS |
893 | bp->b_flags |= (LIBXFS_B_DIRTY | flags); |
894 | return 0; | |
895 | } | |
896 | ||
897 | int | |
898 | libxfs_writebuf(xfs_buf_t *bp, int flags) | |
899 | { | |
e0607266 DC |
900 | #ifdef IO_DEBUG |
901 | printf("%lx: %s: dirty blkno=%llu(%llu)\n", | |
902 | pthread_self(), __FUNCTION__, | |
903 | (long long)LIBXFS_BBTOOFF64(bp->b_bn), | |
904 | (long long)bp->b_bn); | |
905 | #endif | |
f1b058f9 NS |
906 | bp->b_flags |= (LIBXFS_B_DIRTY | flags); |
907 | libxfs_putbuf(bp); | |
908 | return 0; | |
2bd0ea18 NS |
909 | } |
910 | ||
57c9fccb | 911 | void |
f1b058f9 | 912 | libxfs_iomove(xfs_buf_t *bp, uint boff, int len, void *data, int flags) |
57c9fccb | 913 | { |
f1b058f9 NS |
914 | #ifdef IO_DEBUG |
915 | if (boff + len > bp->b_bcount) { | |
2556c98b | 916 | printf("Badness, iomove out of range!\n" |
a2ceac1f | 917 | "bp=(bno 0x%llx, bytes %u) range=(boff %u, bytes %u)\n", |
5dfa5cd2 | 918 | (long long)bp->b_bn, bp->b_bcount, boff, len); |
57c9fccb | 919 | abort(); |
f1b058f9 NS |
920 | } |
921 | #endif | |
57c9fccb NS |
922 | switch (flags) { |
923 | case LIBXFS_BZERO: | |
f1b058f9 | 924 | memset(bp->b_addr + boff, 0, len); |
57c9fccb NS |
925 | break; |
926 | case LIBXFS_BREAD: | |
f1b058f9 | 927 | memcpy(data, bp->b_addr + boff, len); |
57c9fccb NS |
928 | break; |
929 | case LIBXFS_BWRITE: | |
f1b058f9 | 930 | memcpy(bp->b_addr + boff, data, len); |
57c9fccb NS |
931 | break; |
932 | } | |
933 | } | |
934 | ||
33165ec3 | 935 | static void |
69ec88b5 | 936 | libxfs_brelse(struct cache_node *node) |
33165ec3 BN |
937 | { |
938 | xfs_buf_t *bp = (xfs_buf_t *)node; | |
939 | ||
69ec88b5 BN |
940 | if (bp != NULL) { |
941 | if (bp->b_flags & LIBXFS_B_DIRTY) | |
942 | libxfs_writebufr(bp); | |
943 | pthread_mutex_lock(&xfs_buf_freelist.cm_mutex); | |
944 | list_add(&bp->b_node.cn_mru, &xfs_buf_freelist.cm_list); | |
945 | pthread_mutex_unlock(&xfs_buf_freelist.cm_mutex); | |
946 | } | |
33165ec3 BN |
947 | } |
948 | ||
e08f5594 | 949 | static unsigned int |
69ec88b5 BN |
950 | libxfs_bulkrelse( |
951 | struct cache *cache, | |
952 | struct list_head *list) | |
2556c98b | 953 | { |
69ec88b5 | 954 | xfs_buf_t *bp; |
e08f5594 | 955 | int count = 0; |
2556c98b | 956 | |
69ec88b5 | 957 | if (list_empty(list)) |
e08f5594 | 958 | return 0 ; |
69ec88b5 BN |
959 | |
960 | list_for_each_entry(bp, list, b_node.cn_mru) { | |
2556c98b BN |
961 | if (bp->b_flags & LIBXFS_B_DIRTY) |
962 | libxfs_writebufr(bp); | |
e08f5594 | 963 | count++; |
2556c98b | 964 | } |
69ec88b5 BN |
965 | |
966 | pthread_mutex_lock(&xfs_buf_freelist.cm_mutex); | |
967 | __list_splice(list, &xfs_buf_freelist.cm_list); | |
968 | pthread_mutex_unlock(&xfs_buf_freelist.cm_mutex); | |
e08f5594 BN |
969 | |
970 | return count; | |
69ec88b5 BN |
971 | } |
972 | ||
973 | static void | |
974 | libxfs_bflush(struct cache_node *node) | |
975 | { | |
976 | xfs_buf_t *bp = (xfs_buf_t *)node; | |
977 | ||
978 | if ((bp != NULL) && (bp->b_flags & LIBXFS_B_DIRTY)) | |
979 | libxfs_writebufr(bp); | |
2556c98b BN |
980 | } |
981 | ||
982 | void | |
983 | libxfs_putbufr(xfs_buf_t *bp) | |
984 | { | |
985 | libxfs_brelse((struct cache_node *)bp); | |
986 | } | |
987 | ||
988 | ||
f1b058f9 NS |
989 | void |
990 | libxfs_bcache_purge(void) | |
991 | { | |
992 | cache_purge(libxfs_bcache); | |
993 | } | |
994 | ||
e8cb94ee | 995 | void |
33165ec3 BN |
996 | libxfs_bcache_flush(void) |
997 | { | |
998 | cache_flush(libxfs_bcache); | |
999 | } | |
1000 | ||
2556c98b BN |
1001 | int |
1002 | libxfs_bcache_overflowed(void) | |
1003 | { | |
1004 | return cache_overflowed(libxfs_bcache); | |
1005 | } | |
1006 | ||
f1b058f9 NS |
1007 | struct cache_operations libxfs_bcache_operations = { |
1008 | /* .hash */ libxfs_bhash, | |
1009 | /* .alloc */ libxfs_balloc, | |
33165ec3 | 1010 | /* .flush */ libxfs_bflush, |
f1b058f9 NS |
1011 | /* .relse */ libxfs_brelse, |
1012 | /* .compare */ libxfs_bcompare, | |
69ec88b5 | 1013 | /* .bulkrelse */libxfs_bulkrelse |
f1b058f9 NS |
1014 | }; |
1015 | ||
2bd0ea18 | 1016 | |
f1b058f9 | 1017 | /* |
3a19fb7d | 1018 | * Inode cache stubs. |
f1b058f9 NS |
1019 | */ |
1020 | ||
5e656dbb BN |
1021 | extern kmem_zone_t *xfs_ili_zone; |
1022 | extern kmem_zone_t *xfs_inode_zone; | |
f1b058f9 | 1023 | |
2bd0ea18 NS |
1024 | int |
1025 | libxfs_iget(xfs_mount_t *mp, xfs_trans_t *tp, xfs_ino_t ino, uint lock_flags, | |
1026 | xfs_inode_t **ipp, xfs_daddr_t bno) | |
1027 | { | |
1028 | xfs_inode_t *ip; | |
f1b058f9 | 1029 | int error = 0; |
2bd0ea18 | 1030 | |
3a19fb7d CH |
1031 | ip = kmem_zone_zalloc(xfs_inode_zone, 0); |
1032 | if (!ip) | |
1033 | return ENOMEM; | |
2bd0ea18 | 1034 | |
3a19fb7d CH |
1035 | ip->i_ino = ino; |
1036 | ip->i_mount = mp; | |
1037 | error = xfs_iread(mp, tp, ip, bno); | |
1038 | if (error) { | |
1039 | kmem_zone_free(xfs_inode_zone, ip); | |
1040 | *ipp = NULL; | |
1041 | return error; | |
1042 | } | |
f1b058f9 | 1043 | |
3a19fb7d CH |
1044 | *ipp = ip; |
1045 | return 0; | |
f1b058f9 NS |
1046 | } |
1047 | ||
1048 | static void | |
014e5f6d ES |
1049 | libxfs_idestroy(xfs_inode_t *ip) |
1050 | { | |
1051 | switch (ip->i_d.di_mode & S_IFMT) { | |
1052 | case S_IFREG: | |
1053 | case S_IFDIR: | |
1054 | case S_IFLNK: | |
1055 | libxfs_idestroy_fork(ip, XFS_DATA_FORK); | |
1056 | break; | |
1057 | } | |
1058 | if (ip->i_afp) | |
1059 | libxfs_idestroy_fork(ip, XFS_ATTR_FORK); | |
1060 | } | |
1061 | ||
2bd0ea18 | 1062 | void |
3a19fb7d | 1063 | libxfs_iput(xfs_inode_t *ip, uint lock_flags) |
2bd0ea18 | 1064 | { |
3a19fb7d CH |
1065 | if (ip->i_itemp) |
1066 | kmem_zone_free(xfs_ili_zone, ip->i_itemp); | |
1067 | ip->i_itemp = NULL; | |
1068 | libxfs_idestroy(ip); | |
1069 | kmem_zone_free(xfs_inode_zone, ip); | |
2bd0ea18 | 1070 | } |