]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libxfs/rdwr.c
Fix dirv2 rebuild in phase6
[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 static inline void *
28 libxfs_memalign(size_t size)
29 {
30 static size_t memalignment;
31
32 if (!memalignment)
33 memalignment = platform_memalignment();
34 return memalign(memalignment, size);
35 }
36
37 void
38 libxfs_device_zero(dev_t dev, xfs_daddr_t start, uint len)
39 {
40 xfs_off_t start_offset, end_offset, offset;
41 ssize_t zsize, bytes;
42 char *z;
43 int fd;
44
45 zsize = min(BDSTRAT_SIZE, BBTOB(len));
46 if ((z = libxfs_memalign(zsize)) == NULL) {
47 fprintf(stderr,
48 _("%s: %s can't memalign %d bytes: %s\n"),
49 progname, __FUNCTION__, (int)zsize, strerror(errno));
50 exit(1);
51 }
52 memset(z, 0, zsize);
53
54 fd = libxfs_device_to_fd(dev);
55 start_offset = LIBXFS_BBTOOFF64(start);
56
57 if ((lseek64(fd, start_offset, SEEK_SET)) < 0) {
58 fprintf(stderr, _("%s: %s seek to offset %llu failed: %s\n"),
59 progname, __FUNCTION__,
60 (unsigned long long)start_offset, strerror(errno));
61 exit(1);
62 }
63
64 end_offset = LIBXFS_BBTOOFF64(start + len) - start_offset;
65 for (offset = 0; offset < end_offset; ) {
66 bytes = min((ssize_t)(end_offset - offset), zsize);
67 if ((bytes = write(fd, z, bytes)) < 0) {
68 fprintf(stderr, _("%s: %s write failed: %s\n"),
69 progname, __FUNCTION__, strerror(errno));
70 exit(1);
71 } else if (bytes == 0) {
72 fprintf(stderr, _("%s: %s not progressing?\n"),
73 progname, __FUNCTION__);
74 exit(1);
75 }
76 offset += bytes;
77 }
78 free(z);
79 }
80
81 static void unmount_record(void *p)
82 {
83 xlog_op_header_t *op = (xlog_op_header_t *)p;
84 /* the data section must be 32 bit size aligned */
85 struct {
86 __uint16_t magic;
87 __uint16_t pad1;
88 __uint32_t pad2; /* may as well make it 64 bits */
89 } magic = { XLOG_UNMOUNT_TYPE, 0, 0 };
90
91 memset(p, 0, BBSIZE);
92 INT_SET(op->oh_tid, ARCH_CONVERT, 1);
93 INT_SET(op->oh_len, ARCH_CONVERT, sizeof(magic));
94 INT_SET(op->oh_clientid, ARCH_CONVERT, XFS_LOG);
95 INT_SET(op->oh_flags, ARCH_CONVERT, XLOG_UNMOUNT_TRANS);
96 INT_SET(op->oh_res2, ARCH_CONVERT, 0);
97
98 /* and the data for this op */
99 memcpy((char *)p + sizeof(xlog_op_header_t), &magic, sizeof(magic));
100 }
101
102 static xfs_caddr_t next(xfs_caddr_t ptr, int offset, void *private)
103 {
104 xfs_buf_t *buf = (xfs_buf_t *)private;
105
106 if (XFS_BUF_COUNT(buf) < (int)(ptr - XFS_BUF_PTR(buf)) + offset)
107 abort();
108 return ptr + offset;
109 }
110
111 int
112 libxfs_log_clear(
113 dev_t device,
114 xfs_daddr_t start,
115 uint length,
116 uuid_t *fs_uuid,
117 int version,
118 int sunit,
119 int fmt)
120 {
121 xfs_buf_t *buf;
122 int len;
123
124 if (!device || !fs_uuid)
125 return -EINVAL;
126
127 /* first zero the log */
128 libxfs_device_zero(device, start, length);
129
130 /* then write a log record header */
131 len = ((version == 2) && sunit) ? BTOBB(sunit) : 2;
132 len = MAX(len, 2);
133 buf = libxfs_getbuf(device, start, len);
134 libxfs_log_header(XFS_BUF_PTR(buf),
135 fs_uuid, version, sunit, fmt, next, buf);
136 libxfs_writebufr(buf);
137 libxfs_putbuf(buf);
138 return 0;
139 }
140
141 int
142 libxfs_log_header(
143 xfs_caddr_t caddr,
144 uuid_t *fs_uuid,
145 int version,
146 int sunit,
147 int fmt,
148 libxfs_get_block_t *nextfunc,
149 void *private)
150 {
151 xlog_rec_header_t *head = (xlog_rec_header_t *)caddr;
152 xfs_caddr_t p = caddr;
153 uint cycle_lsn;
154 int i, len;
155
156 len = ((version == 2) && sunit) ? BTOBB(sunit) : 1;
157
158 /* note that oh_tid actually contains the cycle number
159 * and the tid is stored in h_cycle_data[0] - that's the
160 * way things end up on disk.
161 */
162 memset(p, 0, BBSIZE);
163 INT_SET(head->h_magicno, ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM);
164 INT_SET(head->h_cycle, ARCH_CONVERT, 1);
165 INT_SET(head->h_version, ARCH_CONVERT, version);
166 if (len != 1)
167 INT_SET(head->h_len, ARCH_CONVERT, sunit - BBSIZE);
168 else
169 INT_SET(head->h_len, ARCH_CONVERT, 20);
170 INT_SET(head->h_chksum, ARCH_CONVERT, 0);
171 INT_SET(head->h_prev_block, ARCH_CONVERT, -1);
172 INT_SET(head->h_num_logops, ARCH_CONVERT, 1);
173 INT_SET(head->h_cycle_data[0], ARCH_CONVERT, 0xb0c0d0d0);
174 INT_SET(head->h_fmt, ARCH_CONVERT, fmt);
175 INT_SET(head->h_size, ARCH_CONVERT, XLOG_HEADER_CYCLE_SIZE);
176
177 ASSIGN_ANY_LSN_DISK(head->h_lsn, 1, 0);
178 ASSIGN_ANY_LSN_DISK(head->h_tail_lsn, 1, 0);
179
180 memcpy(&head->h_fs_uuid, fs_uuid, sizeof(uuid_t));
181
182 len = MAX(len, 2);
183 p = nextfunc(p, BBSIZE, private);
184 unmount_record(p);
185
186 cycle_lsn = CYCLE_LSN_DISK(head->h_lsn);
187 for (i = 2; i < len; i++) {
188 p = nextfunc(p, BBSIZE, private);
189 memset(p, 0, BBSIZE);
190 *(uint *)p = cycle_lsn;
191 }
192
193 return BBTOB(len);
194 }
195
196 xfs_buf_t *
197 libxfs_getsb(xfs_mount_t *mp, int flags)
198 {
199 return libxfs_readbuf(mp->m_dev, XFS_SB_DADDR,
200 XFS_FSS_TO_BB(mp, 1), flags);
201 }
202
203
204 /*
205 * Simple I/O (buffer cache) interface
206 */
207
208 xfs_zone_t *xfs_buf_zone;
209
210 typedef struct {
211 dev_t device;
212 xfs_daddr_t blkno;
213 unsigned int count;
214 } xfs_bufkey_t;
215
216 static unsigned int
217 libxfs_bhash(cache_key_t key, unsigned int hashsize)
218 {
219 return ((unsigned int)((xfs_bufkey_t *)key)->blkno) % hashsize;
220 }
221
222 static int
223 libxfs_bcompare(struct cache_node *node, cache_key_t key)
224 {
225 xfs_buf_t *bp = (xfs_buf_t *)node;
226 xfs_bufkey_t *bkey = (xfs_bufkey_t *)key;
227
228 #ifdef IO_BCOMPARE_CHECK
229 if (bp->b_dev == bkey->device &&
230 bp->b_blkno == bkey->blkno &&
231 bp->b_bcount != bkey->count)
232 fprintf(stderr, "Badness in key lookup (length)\n"
233 "bp=(bno %llu, len %u bb) key=(bno %llu, len %u bbs)\n",
234 (unsigned long long)bp->b_blkno, (int)bp->b_bcount,
235 (unsigned long long)bkey->blkno, (int)bkey->count);
236 #endif
237
238 return (bp->b_dev == bkey->device &&
239 bp->b_blkno == bkey->blkno &&
240 bp->b_bcount == bkey->count);
241 }
242
243 void
244 libxfs_bprint(xfs_buf_t *bp)
245 {
246 fprintf(stderr, "Buffer 0x%p blkno=%llu bytes=%u flags=0x%x count=%u\n",
247 bp, (unsigned long long)bp->b_blkno, (unsigned)bp->b_bcount,
248 bp->b_flags, bp->b_node.cn_count);
249 }
250
251 xfs_buf_t *
252 libxfs_getbuf(dev_t device, xfs_daddr_t blkno, int len)
253 {
254 xfs_buf_t *bp;
255 xfs_bufkey_t key;
256 unsigned int bytes = BBTOB(len);
257
258 key.device = device;
259 key.blkno = blkno;
260 key.count = bytes;
261
262 if (cache_node_get(libxfs_bcache, &key, (struct cache_node **)&bp)) {
263 #ifdef IO_DEBUG
264 fprintf(stderr, "%s: allocated buffer, key=%llu(%llu), %p\n",
265 __FUNCTION__, BBTOB(len), LIBXFS_BBTOOFF64(blkno), blkno, buf);
266 #endif
267 bp->b_flags = 0;
268 bp->b_blkno = blkno;
269 bp->b_bcount = bytes;
270 bp->b_dev = device;
271 if (!(bp->b_addr = libxfs_memalign(bytes))) {
272 fprintf(stderr,
273 _("%s: %s can't memalign %d bytes: %s\n"),
274 progname, __FUNCTION__, (int)bytes,
275 strerror(errno));
276 exit(1);
277 }
278 }
279 return bp;
280 }
281
282 void
283 libxfs_putbuf(xfs_buf_t *bp)
284 {
285 cache_node_put((struct cache_node *)bp);
286 }
287
288 void
289 libxfs_purgebuf(xfs_buf_t *bp)
290 {
291 xfs_bufkey_t key;
292
293 key.device = bp->b_dev;
294 key.blkno = bp->b_blkno;
295 key.count = bp->b_bcount;
296
297 cache_node_purge(libxfs_bcache, &key, (struct cache_node *)bp);
298 }
299
300 static struct cache_node *
301 libxfs_balloc(void)
302 {
303 return libxfs_zone_zalloc(xfs_buf_zone);
304 }
305
306 int
307 libxfs_readbufr(dev_t dev, xfs_daddr_t blkno, xfs_buf_t *bp, int len, int flags)
308 {
309 int fd = libxfs_device_to_fd(dev);
310 int bytes = BBTOB(len);
311
312 ASSERT(BBTOB(len) <= bp->b_bcount);
313
314 if (pread64(fd, bp->b_addr, bytes, LIBXFS_BBTOOFF64(blkno)) < 0) {
315 fprintf(stderr, _("%s: read failed: %s\n"),
316 progname, strerror(errno));
317 if (flags & LIBXFS_EXIT_ON_FAILURE)
318 exit(1);
319 return errno;
320 }
321 #ifdef IO_DEBUG
322 fprintf(stderr, "readbufr read %ubytes, blkno=%llu(%llu), %p\n",
323 bytes, LIBXFS_BBTOOFF64(blkno), blkno, bp);
324 #endif
325 if (bp->b_dev == dev &&
326 bp->b_blkno == blkno &&
327 bp->b_bcount == bytes)
328 bp->b_flags |= LIBXFS_B_UPTODATE;
329 return 0;
330 }
331
332 xfs_buf_t *
333 libxfs_readbuf(dev_t dev, xfs_daddr_t blkno, int len, int flags)
334 {
335 xfs_buf_t *bp;
336 int error;
337
338 bp = libxfs_getbuf(dev, blkno, len);
339 if (!(bp->b_flags & (LIBXFS_B_UPTODATE|LIBXFS_B_DIRTY))) {
340 error = libxfs_readbufr(dev, blkno, bp, len, flags);
341 if (error) {
342 libxfs_putbuf(bp);
343 return NULL;
344 }
345 }
346 return bp;
347 }
348
349 int
350 libxfs_writebufr(xfs_buf_t *bp)
351 {
352 int sts;
353 int fd = libxfs_device_to_fd(bp->b_dev);
354
355 sts = pwrite64(fd, bp->b_addr, bp->b_bcount, LIBXFS_BBTOOFF64(bp->b_blkno));
356 if (sts < 0) {
357 fprintf(stderr, _("%s: pwrite64 failed: %s\n"),
358 progname, strerror(errno));
359 if (bp->b_flags & LIBXFS_B_EXIT)
360 exit(1);
361 return errno;
362 }
363 else if (sts != bp->b_bcount) {
364 fprintf(stderr, _("%s: error - wrote only %d of %d bytes\n"),
365 progname, sts, bp->b_bcount);
366 if (bp->b_flags & LIBXFS_B_EXIT)
367 exit(1);
368 return EIO;
369 }
370 #ifdef IO_DEBUG
371 fprintf(stderr, "writebufr wrote %ubytes, blkno=%llu(%llu), %p\n",
372 bp->b_bcount, LIBXFS_BBTOOFF64(bp->b_blkno), bp->b_blkno, bp);
373 #endif
374 bp->b_flags |= LIBXFS_B_UPTODATE;
375 bp->b_flags &= ~(LIBXFS_B_DIRTY | LIBXFS_B_EXIT);
376 return 0;
377 }
378
379 int
380 libxfs_writebuf_int(xfs_buf_t *bp, int flags)
381 {
382 bp->b_flags |= (LIBXFS_B_DIRTY | flags);
383 return 0;
384 }
385
386 int
387 libxfs_writebuf(xfs_buf_t *bp, int flags)
388 {
389 bp->b_flags |= (LIBXFS_B_DIRTY | flags);
390 libxfs_putbuf(bp);
391 return 0;
392 }
393
394 void
395 libxfs_iomove(xfs_buf_t *bp, uint boff, int len, void *data, int flags)
396 {
397 #ifdef IO_DEBUG
398 if (boff + len > bp->b_bcount) {
399 fprintf(stderr, "Badness, iomove out of range!\n"
400 "bp=(bno %llu, bytes %u) range=(boff %u, bytes %u)\n",
401 bp->b_blkno, bp->b_bcount, boff, len);
402 abort();
403 }
404 #endif
405 switch (flags) {
406 case LIBXFS_BZERO:
407 memset(bp->b_addr + boff, 0, len);
408 break;
409 case LIBXFS_BREAD:
410 memcpy(data, bp->b_addr + boff, len);
411 break;
412 case LIBXFS_BWRITE:
413 memcpy(bp->b_addr + boff, data, len);
414 break;
415 }
416 }
417
418 static void
419 libxfs_bflush(struct cache_node *node)
420 {
421 xfs_buf_t *bp = (xfs_buf_t *)node;
422
423 if ((bp != NULL) && (bp->b_flags & LIBXFS_B_DIRTY))
424 libxfs_writebufr(bp);
425 }
426
427 static void
428 libxfs_brelse(struct cache_node *node)
429 {
430 xfs_buf_t *bp = (xfs_buf_t *)node;
431 xfs_buf_log_item_t *bip;
432 extern xfs_zone_t *xfs_buf_item_zone;
433
434 if (bp != NULL) {
435 if (bp->b_flags & LIBXFS_B_DIRTY)
436 libxfs_writebufr(bp);
437 bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
438 if (bip)
439 libxfs_zone_free(xfs_buf_item_zone, bip);
440 free(bp->b_addr);
441 bp->b_addr = NULL;
442 bp->b_flags = 0;
443 free(bp);
444 bp = NULL;
445 }
446 }
447
448 void
449 libxfs_bcache_purge(void)
450 {
451 cache_purge(libxfs_bcache);
452 }
453
454 void
455 libxfs_bcache_flush(void)
456 {
457 cache_flush(libxfs_bcache);
458 }
459
460 struct cache_operations libxfs_bcache_operations = {
461 /* .hash */ libxfs_bhash,
462 /* .alloc */ libxfs_balloc,
463 /* .flush */ libxfs_bflush,
464 /* .relse */ libxfs_brelse,
465 /* .compare */ libxfs_bcompare,
466 /* .bulkrelse */ NULL /* TODO: lio_listio64 interface? */
467 };
468
469
470 /*
471 * Simple memory interface
472 */
473
474 xfs_zone_t *
475 libxfs_zone_init(int size, char *name)
476 {
477 xfs_zone_t *ptr;
478
479 if ((ptr = malloc(sizeof(xfs_zone_t))) == NULL) {
480 fprintf(stderr, _("%s: zone init failed (%s, %d bytes): %s\n"),
481 progname, name, (int)sizeof(xfs_zone_t), strerror(errno));
482 exit(1);
483 }
484 ptr->zone_unitsize = size;
485 ptr->zone_name = name;
486 #ifdef MEM_DEBUG
487 ptr->allocated = 0;
488 fprintf(stderr, "new zone %p for \"%s\", size=%d\n", ptr, name, size);
489 #endif
490 return ptr;
491 }
492
493 void *
494 libxfs_zone_zalloc(xfs_zone_t *z)
495 {
496 void *ptr;
497
498 if ((ptr = calloc(z->zone_unitsize, 1)) == NULL) {
499 fprintf(stderr, _("%s: zone calloc failed (%s, %d bytes): %s\n"),
500 progname, z->zone_name, z->zone_unitsize,
501 strerror(errno));
502 exit(1);
503 }
504 #ifdef MEM_DEBUG
505 z->allocated++;
506 fprintf(stderr, "## zone alloc'd item %p from %s (%d bytes) (%d active)\n",
507 ptr, z->zone_name, z->zone_unitsize,
508 z->allocated);
509 #endif
510 return ptr;
511 }
512
513 void
514 libxfs_zone_free(xfs_zone_t *z, void *ptr)
515 {
516 #ifdef MEM_DEBUG
517 z->allocated--;
518 fprintf(stderr, "## zone freed item %p from %s (%d bytes) (%d active)\n",
519 ptr, z->zone_name, z->zone_unitsize,
520 z->allocated);
521 #endif
522 if (ptr != NULL) {
523 free(ptr);
524 ptr = NULL;
525 }
526 }
527
528 void *
529 libxfs_malloc(size_t size)
530 {
531 void *ptr;
532
533 if ((ptr = calloc(1, size)) == NULL) {
534 fprintf(stderr, _("%s: calloc failed (%d bytes): %s\n"),
535 progname, (int)size, strerror(errno));
536 exit(1);
537 }
538 #ifdef MEM_DEBUG
539 fprintf(stderr, "## calloc'd item %p size %d bytes\n", ptr, size);
540 #endif
541 return ptr;
542 }
543
544 void
545 libxfs_free(void *ptr)
546 {
547 #ifdef MEM_DEBUG
548 fprintf(stderr, "## freed item %p\n", ptr);
549 #endif
550 if (ptr != NULL) {
551 free(ptr);
552 ptr = NULL;
553 }
554 }
555
556 void *
557 libxfs_realloc(void *ptr, size_t size)
558 {
559 #ifdef MEM_DEBUG
560 void *optr=ptr;
561 #endif
562 if ((ptr = realloc(ptr, size)) == NULL) {
563 fprintf(stderr, _("%s: realloc failed (%d bytes): %s\n"),
564 progname, (int)size, strerror(errno));
565 exit(1);
566 }
567 #ifdef MEM_DEBUG
568 fprintf(stderr, "## realloc'd item %p now %p size %d bytes\n",
569 optr, ptr, size);
570 #endif
571 return ptr;
572 }
573
574
575 /*
576 * Inode cache interfaces
577 */
578
579 extern xfs_zone_t *xfs_ili_zone;
580 extern xfs_zone_t *xfs_inode_zone;
581
582 static unsigned int
583 libxfs_ihash(cache_key_t key, unsigned int hashsize)
584 {
585 return ((unsigned int)*(xfs_ino_t *)key) % hashsize;
586 }
587
588 static int
589 libxfs_icompare(struct cache_node *node, cache_key_t key)
590 {
591 xfs_inode_t *ip = (xfs_inode_t *)node;
592
593 return (ip->i_ino == *(xfs_ino_t *)key);
594 }
595
596 int
597 libxfs_iget(xfs_mount_t *mp, xfs_trans_t *tp, xfs_ino_t ino, uint lock_flags,
598 xfs_inode_t **ipp, xfs_daddr_t bno)
599 {
600 xfs_inode_t *ip;
601 int error = 0;
602
603 if (cache_node_get(libxfs_icache, &ino, (struct cache_node **)&ip)) {
604 #ifdef INO_DEBUG
605 fprintf(stderr, "%s: allocated inode, ino=%llu(%llu), %p\n",
606 __FUNCTION__, (unsigned long long)ino, bno, ip);
607 #endif
608 if ((error = libxfs_iread(mp, tp, ino, ip, bno))) {
609 cache_node_purge(libxfs_icache, &ino,
610 (struct cache_node *)ip);
611 ip = NULL;
612 }
613 }
614 *ipp = ip;
615 return error;
616 }
617
618 void
619 libxfs_iput(xfs_inode_t *ip, uint lock_flags)
620 {
621 cache_node_put((struct cache_node *)ip);
622 }
623
624 static struct cache_node *
625 libxfs_ialloc(void)
626 {
627 return libxfs_zone_zalloc(xfs_inode_zone);
628 }
629
630 static void
631 libxfs_idestroy(xfs_inode_t *ip)
632 {
633 switch (ip->i_d.di_mode & S_IFMT) {
634 case S_IFREG:
635 case S_IFDIR:
636 case S_IFLNK:
637 libxfs_idestroy_fork(ip, XFS_DATA_FORK);
638 break;
639 }
640 if (ip->i_afp)
641 libxfs_idestroy_fork(ip, XFS_ATTR_FORK);
642 }
643
644 static void
645 libxfs_irelse(struct cache_node *node)
646 {
647 xfs_inode_t *ip = (xfs_inode_t *)node;
648
649 if (ip != NULL) {
650 if (ip->i_itemp)
651 libxfs_zone_free(xfs_ili_zone, ip->i_itemp);
652 ip->i_itemp = NULL;
653 libxfs_idestroy(ip);
654 libxfs_zone_free(xfs_inode_zone, ip);
655 ip = NULL;
656 }
657 }
658
659 void
660 libxfs_icache_purge(void)
661 {
662 cache_purge(libxfs_icache);
663 }
664
665 struct cache_operations libxfs_icache_operations = {
666 /* .hash */ libxfs_ihash,
667 /* .alloc */ libxfs_ialloc,
668 /* .flush */ NULL,
669 /* .relse */ libxfs_irelse,
670 /* .compare */ libxfs_icompare,
671 /* .bulkrelse */ NULL
672 };