From: Nathan Scott Date: Thu, 18 May 2006 15:52:04 +0000 (+0000) Subject: Implement buffer and inode caching in libxfs, groundwork for a parallel version of... X-Git-Tag: v2.8.0~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f1b058f9473a5b0cc8bbf65d59c9fc686148ca43;p=thirdparty%2Fxfsprogs-dev.git Implement buffer and inode caching in libxfs, groundwork for a parallel version of xfs_repair. Merge of master-melb:xfs-cmds:25967a by kenmcd. --- diff --git a/include/libxfs.h b/include/libxfs.h index 24d017302..e430d00b7 100644 --- a/include/libxfs.h +++ b/include/libxfs.h @@ -23,6 +23,10 @@ #include +#include "pthread.h" +#include +#include + #include #include #include @@ -97,6 +101,7 @@ typedef struct { extern char *progname; extern int libxfs_init (libxfs_init_t *); +extern void libxfs_destroy (void); extern int libxfs_device_to_fd (dev_t); extern dev_t libxfs_device_open (char *, int, int, int); extern void libxfs_device_zero (dev_t, xfs_daddr_t, uint); @@ -183,12 +188,16 @@ typedef struct xfs_mount { #define LIBXFS_MOUNT_32BITINOOPT 0x0008 #define LIBXFS_MOUNT_COMPAT_ATTR 0x0010 +#define LIBXFS_IHASHSIZE(sbp) (1<<16) /* tweak based on icount? */ +#define LIBXFS_BHASHSIZE(sbp) (1<<16) /* ditto, on blocks used? */ + extern xfs_mount_t *libxfs_mount (xfs_mount_t *, xfs_sb_t *, dev_t, dev_t, dev_t, int); extern void libxfs_mount_common (xfs_mount_t *, xfs_sb_t *); extern xfs_agnumber_t libxfs_initialize_perag (xfs_mount_t *, xfs_agnumber_t); extern void libxfs_umount (xfs_mount_t *); extern int libxfs_rtmount_init (xfs_mount_t *); +extern void libxfs_rtmount_destroy (xfs_mount_t *); extern void libxfs_alloc_compute_maxlevels (xfs_mount_t *); extern void libxfs_bmap_compute_maxlevels (xfs_mount_t *, int); extern void libxfs_ialloc_compute_maxlevels (xfs_mount_t *); @@ -199,15 +208,24 @@ extern void libxfs_trans_init (xfs_mount_t *); * Simple I/O interface */ typedef struct xfs_buf { - xfs_daddr_t b_blkno; - unsigned b_bcount; - dev_t b_dev; - void *b_fsprivate; - void *b_fsprivate2; - void *b_fsprivate3; - char *b_addr; - /* b_addr must be the last field */ + struct cache_node b_node; + unsigned int b_flags; + xfs_daddr_t b_blkno; + unsigned b_bcount; + dev_t b_dev; + void *b_fsprivate; + void *b_fsprivate2; + void *b_fsprivate3; + char *b_addr; } xfs_buf_t; + +enum xfs_buf_flags_t { /* b_flags bits */ + LIBXFS_B_EXIT = 0x0001, /* ==LIBXFS_EXIT_ON_FAILURE */ + LIBXFS_B_DIRTY = 0x0002, /* buffer has been modified */ + LIBXFS_B_STALE = 0x0004, /* buffer marked as invalid */ + LIBXFS_B_UPTODATE = 0x0008, /* buffer is sync'd to disk */ +}; + #define XFS_BUF_PTR(bp) ((bp)->b_addr) #define xfs_buf_offset(bp, offset) (XFS_BUF_PTR(bp) + (offset)) #define XFS_BUF_ADDR(bp) ((bp)->b_blkno) @@ -226,13 +244,20 @@ typedef struct xfs_buf { #define XFS_BUF_FSPRIVATE3(bp,type) ((type)(bp)->b_fsprivate3) #define XFS_BUF_SET_FSPRIVATE3(bp,val) (bp)->b_fsprivate3 = (void *)(val) -extern xfs_buf_t *libxfs_getbuf (dev_t, xfs_daddr_t, int); -extern xfs_buf_t *libxfs_readbuf (dev_t, xfs_daddr_t, int, int); extern xfs_buf_t *libxfs_getsb (xfs_mount_t *, int); +extern xfs_buf_t *libxfs_readbuf (dev_t, xfs_daddr_t, int, int); extern int libxfs_readbufr (dev_t, xfs_daddr_t, xfs_buf_t *, int, int); extern int libxfs_writebuf (xfs_buf_t *, int); +extern int libxfs_writebufr (xfs_buf_t *); extern int libxfs_writebuf_int (xfs_buf_t *, int); + +/* Buffer Cache Interfaces */ +extern struct cache *libxfs_bcache; +extern struct cache_operations libxfs_bcache_operations; +extern void libxfs_bcache_purge (void); +extern xfs_buf_t *libxfs_getbuf (dev_t, xfs_daddr_t, int); extern void libxfs_putbuf (xfs_buf_t *); +extern void libxfs_purgebuf (xfs_buf_t *); #define LIBXFS_BREAD 0x1 #define LIBXFS_BWRITE 0x2 @@ -289,6 +314,7 @@ extern int libxfs_trans_reserve (xfs_trans_t *, uint,uint,uint,uint,uint); extern int libxfs_trans_commit (xfs_trans_t *, uint, xfs_lsn_t *); extern void libxfs_trans_cancel (xfs_trans_t *, int); extern void libxfs_mod_sb (xfs_trans_t *, __int64_t); +extern xfs_buf_t *libxfs_trans_getsb (xfs_trans_t *, xfs_mount_t *, int); extern int libxfs_trans_iget (xfs_mount_t *, xfs_trans_t *, xfs_ino_t, uint, uint, struct xfs_inode **); @@ -330,8 +356,8 @@ extern void *libxfs_realloc (void *, size_t); /* * Inode interface */ -struct xfs_inode_log_item; typedef struct xfs_inode { + struct cache_node i_node; xfs_mount_t *i_mount; /* fs mount struct ptr */ xfs_ino_t i_ino; /* inode number (agno/agino) */ xfs_daddr_t i_blkno; /* blkno of inode buffer */ @@ -340,8 +366,8 @@ typedef struct xfs_inode { ushort i_boffset; /* off of inode in buffer */ xfs_ifork_t *i_afp; /* attribute fork pointer */ xfs_ifork_t i_df; /* data fork */ - struct xfs_trans *i_transp; /* ptr to owning transaction */ - struct xfs_inode_log_item *i_itemp; /* logging information */ + xfs_trans_t *i_transp; /* ptr to owning transaction */ + xfs_inode_log_item_t *i_itemp; /* logging information */ unsigned int i_delayed_blks; /* count of delay alloc blks */ xfs_dinode_core_t i_d; /* most of ondisk inode */ } xfs_inode_t; @@ -363,12 +389,18 @@ extern void libxfs_trans_inode_alloc_buf (xfs_trans_t *, xfs_buf_t *); extern void libxfs_idata_realloc (xfs_inode_t *, int, int); extern void libxfs_idestroy_fork (xfs_inode_t *, int); -extern int libxfs_iread (xfs_mount_t *, xfs_trans_t *, xfs_ino_t, - xfs_inode_t **, xfs_daddr_t); +extern int libxfs_iformat (xfs_inode_t *, xfs_dinode_t *); extern void libxfs_ichgtime (xfs_inode_t *, int); extern int libxfs_iflush_int (xfs_inode_t *, xfs_buf_t *); extern int libxfs_itobp (xfs_mount_t *, xfs_trans_t *, xfs_inode_t *, xfs_dinode_t **, xfs_buf_t **, xfs_daddr_t); +extern int libxfs_iread (xfs_mount_t *, xfs_trans_t *, xfs_ino_t, + xfs_inode_t *, xfs_daddr_t); + +/* Inode Cache Interfaces */ +extern struct cache *libxfs_icache; +extern struct cache_operations libxfs_icache_operations; +extern void libxfs_icache_purge (void); extern int libxfs_iget (xfs_mount_t *, xfs_trans_t *, xfs_ino_t, uint, xfs_inode_t **, xfs_daddr_t); extern void libxfs_iput (xfs_inode_t *, uint); diff --git a/include/libxlog.h b/include/libxlog.h index fcdbadcd9..cef47cd5b 100644 --- a/include/libxlog.h +++ b/include/libxlog.h @@ -79,7 +79,7 @@ extern void xlog_warn(char *fmt,...); extern void xlog_exit(char *fmt,...); extern void xlog_panic(char *fmt,...); -#define xlog_get_bp(log,bbs) libxfs_getbuf(x.logdev, 0, (bbs)) +#define xlog_get_bp(log,bbs) libxfs_getbuf(x.logdev, (xfs_daddr_t)-1, (bbs)) #define xlog_put_bp(bp) libxfs_putbuf(bp) #define xlog_bread(log,blkno,bbs,bp) \ (libxfs_readbufr(x.logdev, \ diff --git a/libxfs/init.c b/libxfs/init.c index 0ec541563..b5ae26edc 100644 --- a/libxfs/init.c +++ b/libxfs/init.c @@ -25,6 +25,14 @@ char *progname = "libxfs"; /* default, changed by each tool */ +struct cache *libxfs_icache; /* global inode cache */ +int libxfs_icache_size; /* #buckets in icache */ + +struct cache *libxfs_bcache; /* global buffer cache */ +int libxfs_bcache_size; /* #buckets in bcache */ + +static void manage_zones(int); /* setup global zones */ + /* * dev_map - map open devices to fd. */ @@ -380,6 +388,13 @@ voldone: } if (needcd) chdir(curdir); + if (!libxfs_icache_size) + libxfs_icache_size = LIBXFS_IHASHSIZE(sbp); + libxfs_icache = cache_init(libxfs_icache_size,&libxfs_icache_operations); + if (!libxfs_bcache_size) + libxfs_bcache_size = LIBXFS_BHASHSIZE(sbp); + libxfs_bcache = cache_init(libxfs_bcache_size,&libxfs_bcache_operations); + manage_zones(0); rval = 1; done: if (dpath[0]) @@ -406,6 +421,7 @@ done: static void manage_zones(int release) { + extern xfs_zone_t *xfs_buf_zone; extern xfs_zone_t *xfs_ili_zone; extern xfs_zone_t *xfs_inode_zone; extern xfs_zone_t *xfs_ifork_zone; @@ -417,6 +433,7 @@ manage_zones(int release) extern void xfs_dir_startup(); if (release) { /* free zone allocation */ + libxfs_free(xfs_buf_zone); libxfs_free(xfs_inode_zone); libxfs_free(xfs_ifork_zone); libxfs_free(xfs_dabuf_zone); @@ -427,6 +444,7 @@ manage_zones(int release) return; } /* otherwise initialise zone allocation */ + xfs_buf_zone = libxfs_zone_init(sizeof(xfs_buf_t), "xfs_buffer"); xfs_inode_zone = libxfs_zone_init(sizeof(xfs_inode_t), "xfs_inode"); xfs_ifork_zone = libxfs_zone_init(sizeof(xfs_ifork_t), "xfs_ifork"); xfs_dabuf_zone = libxfs_zone_init(sizeof(xfs_dabuf_t), "xfs_dabuf"); @@ -456,7 +474,7 @@ rtmount_inodes(xfs_mount_t *mp) sbp = &mp->m_sb; if (sbp->sb_rbmino == NULLFSINO) return 0; - error = libxfs_iread(mp, NULL, sbp->sb_rbmino, &mp->m_rbmip, 0); + error = libxfs_iget(mp, NULL, sbp->sb_rbmino, 0, &mp->m_rbmip, 0); if (error) { fprintf(stderr, _("%s: cannot read realtime bitmap inode (%d)\n"), @@ -465,8 +483,9 @@ rtmount_inodes(xfs_mount_t *mp) } ASSERT(mp->m_rbmip != NULL); ASSERT(sbp->sb_rsumino != NULLFSINO); - error = libxfs_iread(mp, NULL, sbp->sb_rsumino, &mp->m_rsumip, 0); + error = libxfs_iget(mp, NULL, sbp->sb_rsumino, 0, &mp->m_rsumip, 0); if (error) { + libxfs_iput(mp->m_rbmip, 0); fprintf(stderr, _("%s: cannot read realtime summary inode (%d)\n"), progname, error); @@ -556,7 +575,6 @@ libxfs_mount( mp->m_flags = (LIBXFS_MOUNT_32BITINODES|LIBXFS_MOUNT_32BITINOOPT); mp->m_sb = *sb; sbp = &(mp->m_sb); - manage_zones(0); libxfs_mount_common(mp, sb); @@ -675,7 +693,7 @@ libxfs_mount( * mkfs calls mount before the root inode is allocated. */ if ((flags & LIBXFS_MOUNT_ROOTINOS) && sbp->sb_rootino != NULLFSINO) { - error = libxfs_iread(mp, NULL, sbp->sb_rootino, + error = libxfs_iget(mp, NULL, sbp->sb_rootino, 0, &mp->m_rootip, 0); if (error) { fprintf(stderr, _("%s: cannot read root inode (%d)\n"), @@ -685,18 +703,33 @@ libxfs_mount( } ASSERT(mp->m_rootip != NULL); } - if ((flags & LIBXFS_MOUNT_ROOTINOS) && rtmount_inodes(mp)) + if ((flags & LIBXFS_MOUNT_ROOTINOS) && rtmount_inodes(mp)) { + libxfs_iput(mp->m_rootip, 0); return NULL; + } return mp; } +void +libxfs_rtmount_destroy(xfs_mount_t *mp) +{ + if (mp->m_rsumip) + libxfs_iput(mp->m_rsumip, 0); + if (mp->m_rbmip) + libxfs_iput(mp->m_rbmip, 0); + mp->m_rsumip = mp->m_rbmip = NULL; +} + /* * Release any resource obtained during a mount. */ void libxfs_umount(xfs_mount_t *mp) { - manage_zones(1); + libxfs_rtmount_destroy(mp); + libxfs_icache_purge(); + libxfs_bcache_purge(); + if (mp->m_perag) { int agno; for (agno = 0; agno < mp->m_maxagi; agno++) { @@ -706,3 +739,14 @@ libxfs_umount(xfs_mount_t *mp) free(mp->m_perag); } } + +/* + * Release any global resources used by libxfs. + */ +void +libxfs_destroy(void) +{ + manage_zones(1); + cache_destroy(libxfs_icache); + cache_destroy(libxfs_bcache); +} diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c index 2b26ccbdf..501efff1b 100644 --- a/libxfs/rdwr.c +++ b/libxfs/rdwr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. + * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or @@ -24,6 +24,16 @@ #define BDSTRAT_SIZE (256 * 1024) #define min(x, y) ((x) < (y) ? (x) : (y)) +static inline void * +libxfs_memalign(size_t size) +{ + static size_t pagealign; + + if (!pagealign) + pagealign = getpagesize(); + return memalign(pagealign, size); +} + void libxfs_device_zero(dev_t dev, xfs_daddr_t start, uint len) { @@ -33,7 +43,7 @@ libxfs_device_zero(dev_t dev, xfs_daddr_t start, uint len) int fd; zsize = min(BDSTRAT_SIZE, BBTOB(len)); - if ((z = memalign(getpagesize(), zsize)) == NULL) { + if ((z = libxfs_memalign(zsize)) == NULL) { fprintf(stderr, _("%s: %s can't memalign %d bytes: %s\n"), progname, __FUNCTION__, (int)zsize, strerror(errno)); @@ -121,13 +131,10 @@ libxfs_log_clear( len = ((version == 2) && sunit) ? BTOBB(sunit) : 2; len = MAX(len, 2); buf = libxfs_getbuf(device, start, len); - if (!buf) - return -1; libxfs_log_header(XFS_BUF_PTR(buf), fs_uuid, version, sunit, fmt, next, buf); - if (libxfs_writebuf(buf, 0)) - return -1; - + libxfs_writebufr(buf); + libxfs_putbuf(buf); return 0; } @@ -186,46 +193,125 @@ libxfs_log_header( return BBTOB(len); } +xfs_buf_t * +libxfs_getsb(xfs_mount_t *mp, int flags) +{ + return libxfs_readbuf(mp->m_dev, XFS_SB_DADDR, + XFS_FSS_TO_BB(mp, 1), flags); +} + /* - * Simple I/O interface + * Simple I/O (buffer cache) interface */ +xfs_zone_t *xfs_buf_zone; + +typedef struct { + dev_t device; + xfs_daddr_t blkno; + unsigned int count; +} xfs_bufkey_t; + +static unsigned int +libxfs_bhash(cache_key_t key, unsigned int hashsize) +{ + return ((unsigned int)((xfs_bufkey_t *)key)->blkno) % hashsize; +} + +static int +libxfs_bcompare(struct cache_node *node, cache_key_t key) +{ + xfs_buf_t *bp = (xfs_buf_t *)node; + xfs_bufkey_t *bkey = (xfs_bufkey_t *)key; + +#ifdef IO_BCOMPARE_CHECK + if (bp->b_dev == bkey->device && + bp->b_blkno == bkey->blkno && + bp->b_bcount != bkey->count) + fprintf(stderr, "Badness in key lookup (length)\n" + "bp=(bno %llu, len %u bb) key=(bno %llu, len %u bbs)\n", + (unsigned long long)bp->b_blkno, (int)bp->b_bcount, + (unsigned long long)bkey->blkno, (int)bkey->count); +#endif + + return (bp->b_dev == bkey->device && + bp->b_blkno == bkey->blkno && + bp->b_bcount == bkey->count); +} + +void +libxfs_bprint(xfs_buf_t *bp) +{ + fprintf(stderr, "Buffer 0x%p blkno=%llu bytes=%u flags=0x%x count=%u\n", + bp, (unsigned long long)bp->b_blkno, (unsigned)bp->b_bcount, + bp->b_flags, bp->b_node.cn_count); +} + xfs_buf_t * libxfs_getbuf(dev_t device, xfs_daddr_t blkno, int len) { - xfs_buf_t *buf; - size_t total; + xfs_buf_t *bp; + xfs_bufkey_t key; + unsigned int bytes = BBTOB(len); - total = sizeof(xfs_buf_t) + BBTOB(len); - if ((buf = calloc(total, 1)) == NULL) { - fprintf(stderr, _("%s: buf calloc failed (%ld bytes): %s\n"), - progname, (long)total, strerror(errno)); - exit(1); - } - /* by default, we allocate buffer directly after the header */ - buf->b_blkno = blkno; - buf->b_bcount = BBTOB(len); - buf->b_dev = device; - buf->b_addr = (char *)(&buf->b_addr + 1); /* must be last field */ + key.device = device; + key.blkno = blkno; + key.count = bytes; + + if (cache_node_get(libxfs_bcache, &key, (struct cache_node **)&bp)) { #ifdef IO_DEBUG - fprintf(stderr, "getbuf allocated %ubytes, blkno=%llu(%llu), %p\n", - BBTOB(len), BBTOOFF64(blkno), blkno, buf); + fprintf(stderr, "%s: allocated buffer, key=%llu(%llu), %p\n", + __FUNCTION__, BBTOB(len), BBTOOFF64(blkno), blkno, buf); #endif + bp->b_flags = 0; + bp->b_blkno = blkno; + bp->b_bcount = bytes; + bp->b_dev = device; + if (!(bp->b_addr = libxfs_memalign(bytes))) { + fprintf(stderr, + _("%s: %s can't memalign %d bytes: %s\n"), + progname, __FUNCTION__, (int)bytes, + strerror(errno)); + exit(1); + } + } + return bp; +} + +void +libxfs_putbuf(xfs_buf_t *bp) +{ + cache_node_put((struct cache_node *)bp); +} + +void +libxfs_purgebuf(xfs_buf_t *bp) +{ + xfs_bufkey_t key; + + key.device = bp->b_dev; + key.blkno = bp->b_blkno; + key.count = bp->b_bcount; + + cache_node_purge(libxfs_bcache, &key, (struct cache_node *)bp); +} - return(buf); +static struct cache_node * +libxfs_balloc(void) +{ + return libxfs_zone_zalloc(xfs_buf_zone); } int -libxfs_readbufr(dev_t dev, xfs_daddr_t blkno, xfs_buf_t *buf, int len, int flags) +libxfs_readbufr(dev_t dev, xfs_daddr_t blkno, xfs_buf_t *bp, int len, int flags) { int fd = libxfs_device_to_fd(dev); + int bytes = BBTOB(len); - buf->b_dev = dev; - buf->b_blkno = blkno; - ASSERT(BBTOB(len) <= buf->b_bcount); + ASSERT(BBTOB(len) <= bp->b_bcount); - if (pread64(fd, buf->b_addr, BBTOB(len), BBTOOFF64(blkno)) < 0) { + if (pread64(fd, bp->b_addr, bytes, BBTOOFF64(blkno)) < 0) { fprintf(stderr, _("%s: read failed: %s\n"), progname, strerror(errno)); if (flags & LIBXFS_EXIT_ON_FAILURE) @@ -234,108 +320,135 @@ libxfs_readbufr(dev_t dev, xfs_daddr_t blkno, xfs_buf_t *buf, int len, int flags } #ifdef IO_DEBUG fprintf(stderr, "readbufr read %ubytes, blkno=%llu(%llu), %p\n", - BBTOB(len), BBTOOFF64(blkno), blkno, buf); + bytes, BBTOOFF64(blkno), blkno, bp); #endif + if (bp->b_dev == dev && + bp->b_blkno == blkno && + bp->b_bcount == bytes) + bp->b_flags |= LIBXFS_B_UPTODATE; return 0; } xfs_buf_t * libxfs_readbuf(dev_t dev, xfs_daddr_t blkno, int len, int flags) { - xfs_buf_t *buf; + xfs_buf_t *bp; int error; - buf = libxfs_getbuf(dev, blkno, len); - error = libxfs_readbufr(dev, blkno, buf, len, flags); - if (error) { - libxfs_putbuf(buf); - return NULL; + bp = libxfs_getbuf(dev, blkno, len); + if (!(bp->b_flags & (LIBXFS_B_UPTODATE|LIBXFS_B_DIRTY))) { + error = libxfs_readbufr(dev, blkno, bp, len, flags); + if (error) { + libxfs_putbuf(bp); + return NULL; + } } - return buf; -} - -xfs_buf_t * -libxfs_getsb(xfs_mount_t *mp, int flags) -{ - return libxfs_readbuf(mp->m_dev, XFS_SB_DADDR, - XFS_FSB_TO_BB(mp, 1), flags); + return bp; } int -libxfs_writebuf_int(xfs_buf_t *buf, int flags) +libxfs_writebufr(xfs_buf_t *bp) { int sts; - int fd = libxfs_device_to_fd(buf->b_dev); + int fd = libxfs_device_to_fd(bp->b_dev); -#ifdef IO_DEBUG - fprintf(stderr, "writing %ubytes at blkno=%llu(%llu), %p\n", - buf->b_bcount, BBTOOFF64(buf->b_blkno), buf->b_blkno, buf); -#endif - sts = pwrite64(fd, buf->b_addr, buf->b_bcount, BBTOOFF64(buf->b_blkno)); + sts = pwrite64(fd, bp->b_addr, bp->b_bcount, BBTOOFF64(bp->b_blkno)); if (sts < 0) { fprintf(stderr, _("%s: pwrite64 failed: %s\n"), progname, strerror(errno)); - if (flags & LIBXFS_EXIT_ON_FAILURE) + if (bp->b_flags & LIBXFS_B_EXIT) exit(1); return errno; } - else if (sts != buf->b_bcount) { + else if (sts != bp->b_bcount) { fprintf(stderr, _("%s: error - wrote only %d of %d bytes\n"), - progname, sts, buf->b_bcount); - if (flags & LIBXFS_EXIT_ON_FAILURE) + progname, sts, bp->b_bcount); + if (bp->b_flags & LIBXFS_B_EXIT) exit(1); return EIO; } +#ifdef IO_DEBUG + fprintf(stderr, "writebufr wrote %ubytes, blkno=%llu(%llu), %p\n", + bp->b_bcount, BBTOOFF64(bp->b_blkno), bp->b_blkno, bp); +#endif + bp->b_flags |= LIBXFS_B_UPTODATE; + bp->b_flags &= ~(LIBXFS_B_DIRTY | LIBXFS_B_EXIT); return 0; } int -libxfs_writebuf(xfs_buf_t *buf, int flags) +libxfs_writebuf_int(xfs_buf_t *bp, int flags) { - int error = libxfs_writebuf_int(buf, flags); - libxfs_putbuf(buf); - return error; + bp->b_flags |= (LIBXFS_B_DIRTY | flags); + return 0; +} + +int +libxfs_writebuf(xfs_buf_t *bp, int flags) +{ + bp->b_flags |= (LIBXFS_B_DIRTY | flags); + libxfs_putbuf(bp); + return 0; } void -libxfs_iomove(xfs_buf_t *buf, uint boff, int len, void *data, int flags) +libxfs_iomove(xfs_buf_t *bp, uint boff, int len, void *data, int flags) { - if (boff + len > buf->b_bcount) +#ifdef IO_DEBUG + if (boff + len > bp->b_bcount) { + fprintf(stderr, "Badness, iomove out of range!\n" + "bp=(bno %llu, bytes %u) range=(boff %u, bytes %u)\n", + bp->b_blkno, bp->b_bcount, boff, len); abort(); - + } +#endif switch (flags) { case LIBXFS_BZERO: - memset(buf->b_addr + boff, 0, len); + memset(bp->b_addr + boff, 0, len); break; case LIBXFS_BREAD: - memcpy(data, buf->b_addr + boff, len); + memcpy(data, bp->b_addr + boff, len); break; case LIBXFS_BWRITE: - memcpy(buf->b_addr + boff, data, len); + memcpy(bp->b_addr + boff, data, len); break; } } -void -libxfs_putbuf(xfs_buf_t *buf) +static void +libxfs_brelse(struct cache_node *node) { - if (buf != NULL) { - xfs_buf_log_item_t *bip; - extern xfs_zone_t *xfs_buf_item_zone; - - bip = XFS_BUF_FSPRIVATE(buf, xfs_buf_log_item_t *); - + xfs_buf_t *bp = (xfs_buf_t *)node; + xfs_buf_log_item_t *bip; + extern xfs_zone_t *xfs_buf_item_zone; + + if (bp != NULL) { + if (bp->b_flags & LIBXFS_B_DIRTY) + libxfs_writebufr(bp); + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); if (bip) libxfs_zone_free(xfs_buf_item_zone, bip); -#ifdef IO_DEBUG - fprintf(stderr, "putbuf released %ubytes, %p\n", - buf->b_bcount, buf); -#endif - free(buf); - buf = NULL; + free(bp->b_addr); + bp->b_addr = NULL; + bp->b_flags = 0; + free(bp); + bp = NULL; } } +void +libxfs_bcache_purge(void) +{ + cache_purge(libxfs_bcache); +} + +struct cache_operations libxfs_bcache_operations = { + /* .hash */ libxfs_bhash, + /* .alloc */ libxfs_balloc, + /* .relse */ libxfs_brelse, + /* .compare */ libxfs_bcompare, +}; + /* * Simple memory interface @@ -406,8 +519,7 @@ libxfs_malloc(size_t size) exit(1); } #ifdef MEM_DEBUG - fprintf(stderr, "## calloc'd item %p size %d bytes\n", - ptr, size); + fprintf(stderr, "## calloc'd item %p size %d bytes\n", ptr, size); #endif return ptr; } @@ -416,8 +528,7 @@ void libxfs_free(void *ptr) { #ifdef MEM_DEBUG - fprintf(stderr, "## freed item %p\n", - ptr); + fprintf(stderr, "## freed item %p\n", ptr); #endif if (ptr != NULL) { free(ptr); @@ -444,21 +555,62 @@ libxfs_realloc(void *ptr, size_t size) } +/* + * Inode cache interfaces + */ + +extern xfs_zone_t *xfs_ili_zone; +extern xfs_zone_t *xfs_inode_zone; + +static unsigned int +libxfs_ihash(cache_key_t key, unsigned int hashsize) +{ + return ((unsigned int)*(xfs_ino_t *)key) % hashsize; +} + +static int +libxfs_icompare(struct cache_node *node, cache_key_t key) +{ + xfs_inode_t *ip = (xfs_inode_t *)node; + + return (ip->i_ino == *(xfs_ino_t *)key); +} + int libxfs_iget(xfs_mount_t *mp, xfs_trans_t *tp, xfs_ino_t ino, uint lock_flags, xfs_inode_t **ipp, xfs_daddr_t bno) { xfs_inode_t *ip; - int error; + int error = 0; - error = libxfs_iread(mp, tp, ino, &ip, bno); - if (error) - return error; + if (cache_node_get(libxfs_icache, &ino, (struct cache_node **)&ip)) { +#ifdef INO_DEBUG + fprintf(stderr, "%s: allocated inode, ino=%llu(%llu), %p\n", + __FUNCTION__, (unsigned long long)ino, bno, ip); +#endif + if ((error = libxfs_iread(mp, tp, ino, ip, bno))) { + cache_node_purge(libxfs_icache, &ino, + (struct cache_node *)ip); + ip = NULL; + } + } *ipp = ip; - return 0; + return error; } void +libxfs_iput(xfs_inode_t *ip, uint lock_flags) +{ + cache_node_put((struct cache_node *)ip); +} + +static struct cache_node * +libxfs_ialloc(void) +{ + return libxfs_zone_zalloc(xfs_inode_zone); +} + +static void libxfs_idestroy(xfs_inode_t *ip) { switch (ip->i_d.di_mode & S_IFMT) { @@ -472,15 +624,12 @@ libxfs_idestroy(xfs_inode_t *ip) libxfs_idestroy_fork(ip, XFS_ATTR_FORK); } -void -libxfs_iput(xfs_inode_t *ip, uint lock_flags) +static void +libxfs_irelse(struct cache_node *node) { - extern xfs_zone_t *xfs_ili_zone; - extern xfs_zone_t *xfs_inode_zone; + xfs_inode_t *ip = (xfs_inode_t *)node; if (ip != NULL) { - - /* free attached inode log item */ if (ip->i_itemp) libxfs_zone_free(xfs_ili_zone, ip->i_itemp); ip->i_itemp = NULL; @@ -490,22 +639,15 @@ libxfs_iput(xfs_inode_t *ip, uint lock_flags) } } -/* - * libxfs_mod_sb can be used to copy arbitrary changes to the - * in-core superblock into the superblock buffer to be logged. - * - * In user-space, we simply convert to big-endian, and write the - * the whole superblock - the in-core changes have all been made - * already. - */ void -libxfs_mod_sb(xfs_trans_t *tp, __int64_t fields) +libxfs_icache_purge(void) { - xfs_buf_t *bp; - xfs_mount_t *mp; - - mp = tp->t_mountp; - bp = libxfs_getbuf(mp->m_dev, XFS_SB_DADDR, 1); - libxfs_xlate_sb(XFS_BUF_PTR(bp), &mp->m_sb, -1, XFS_SB_ALL_BITS); - libxfs_writebuf(bp, LIBXFS_EXIT_ON_FAILURE); + cache_purge(libxfs_icache); } + +struct cache_operations libxfs_icache_operations = { + /* .hash */ libxfs_ihash, + /* .alloc */ libxfs_ialloc, + /* .relse */ libxfs_irelse, + /* .compare */ libxfs_icompare, +}; diff --git a/libxfs/trans.c b/libxfs/trans.c index c72497877..33c24ac81 100644 --- a/libxfs/trans.c +++ b/libxfs/trans.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. + * Copyright (c) 2000-2001,2005-2006 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or @@ -113,9 +113,9 @@ libxfs_trans_iget( xfs_inode_log_item_t *iip; if (tp == NULL) - return libxfs_iread(mp, tp, ino, ipp, 0); + return libxfs_iget(mp, tp, ino, lock_flags, ipp, 0); - error = libxfs_iread(mp, tp, ino, &ip, 0); + error = libxfs_iget(mp, tp, ino, lock_flags, &ip, 0); if (error) return error; ASSERT(ip != NULL); @@ -310,14 +310,14 @@ libxfs_trans_brelse( bip->bli_recur--; return; } - /* If dirty, can't release till transaction committed */ - if (lidp->lid_flags & XFS_LID_DIRTY) { + /* If dirty/stale, can't release till transaction committed */ + if (bip->bli_flags & XFS_BLI_STALE) + return; + if (lidp->lid_flags & XFS_LID_DIRTY) return; - } xfs_trans_free_item(tp, lidp); - if (bip->bli_flags & XFS_BLI_HOLD) { + if (bip->bli_flags & XFS_BLI_HOLD) bip->bli_flags &= ~XFS_BLI_HOLD; - } XFS_BUF_SET_FSPRIVATE2(bp, NULL); libxfs_putbuf(bp); } @@ -339,7 +339,12 @@ libxfs_trans_binval( bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)bip); ASSERT(lidp != NULL); - bip->bli_flags &= ~(XFS_BLI_DIRTY); + if (bip->bli_flags & XFS_BLI_STALE) + return; + XFS_BUF_UNDELAYWRITE(bp); + XFS_BUF_STALE(bp); + bip->bli_flags |= XFS_BLI_STALE; + bip->bli_flags &= ~XFS_BLI_DIRTY; bip->bli_format.blf_flags &= ~XFS_BLI_INODE_BUF; bip->bli_format.blf_flags |= XFS_BLI_CANCEL; lidp->lid_flags |= XFS_LID_DIRTY; @@ -426,6 +431,49 @@ libxfs_trans_get_buf( return bp; } +xfs_buf_t * +libxfs_trans_getsb( + xfs_trans_t *tp, + xfs_mount_t *mp, + int flags) +{ + xfs_buf_t *bp; + xfs_buf_log_item_t *bip; + xfs_buftarg_t bdev; + int len; + + if (tp == NULL) + return libxfs_getsb(mp, flags); + + bdev.dev = mp->m_dev; + len = XFS_FSS_TO_BB(mp, 1); + if (tp->t_items.lic_next == NULL) + bp = xfs_trans_buf_item_match(tp, &bdev, XFS_SB_DADDR, len); + else + bp = xfs_trans_buf_item_match_all(tp, &bdev, XFS_SB_DADDR, len); + if (bp != NULL) { + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(bip != NULL); + bip->bli_recur++; + return bp; + } + + bp = libxfs_getsb(mp, flags); +#ifdef XACT_DEBUG + fprintf(stderr, "trans_get_sb buffer %p, transaction %p\n", bp, tp); +#endif + + xfs_buf_item_init(bp, mp); + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); + bip->bli_recur = 0; + xfs_trans_add_item(tp, (xfs_log_item_t *)bip); + + /* initialize b_fsprivate2 so we can find it incore */ + XFS_BUF_SET_FSPRIVATE2(bp, tp); + return bp; +} + int libxfs_trans_read_buf( xfs_mount_t *mp, @@ -433,19 +481,16 @@ libxfs_trans_read_buf( dev_t dev, xfs_daddr_t blkno, int len, - uint f, + uint flags, xfs_buf_t **bpp) { xfs_buf_t *bp; xfs_buf_log_item_t *bip; - int error; xfs_buftarg_t bdev; if (tp == NULL) { - bp = libxfs_getbuf(mp->m_dev, blkno, len); - error = libxfs_readbufr(dev, blkno, bp, len, 0); - *bpp = bp; - return error; + *bpp = libxfs_readbuf(dev, blkno, len, flags); + return 0; } bdev.dev = dev; @@ -462,12 +507,7 @@ libxfs_trans_read_buf( return 0; } - bp = libxfs_getbuf(mp->m_dev, blkno, len); - error = libxfs_readbufr(dev, blkno, bp, len, 0); - if (error) { - *bpp = NULL; - return error; - } + bp = libxfs_readbuf(dev, blkno, len, flags); #ifdef XACT_DEBUG fprintf(stderr, "trans_read_buf buffer %p, transaction %p\n", bp, tp); #endif @@ -572,7 +612,7 @@ inode_item_done( ip->i_transp = NULL; /* disassociate from transaction */ XFS_BUF_SET_FSPRIVATE(bp, NULL); /* remove log item */ XFS_BUF_SET_FSPRIVATE2(bp, NULL); /* remove xact ptr */ - libxfs_writebuf_int(bp, 0); + libxfs_writebuf(bp, 0); #ifdef XACT_DEBUG fprintf(stderr, "flushing dirty inode %llu, buffer %p (hold=%u)\n", ip->i_ino, bp, hold); @@ -582,8 +622,7 @@ inode_item_done( return; } else { - /*libxfs_iput(iip->ili_inode, 0); - nathans TODO? */ - libxfs_putbuf(bp); + libxfs_iput(iip->ili_inode, 0); } ili_done: @@ -608,12 +647,13 @@ buf_item_done( XFS_BUF_SET_FSPRIVATE2(bp, NULL); /* remove xact ptr */ hold = (bip->bli_flags & XFS_BLI_HOLD); - if (bip->bli_flags & XFS_BLI_DIRTY) { + if (bip->bli_flags & (XFS_BLI_DIRTY|XFS_BLI_STALE)) { #ifdef XACT_DEBUG - fprintf(stderr, "flushing dirty buffer %p (hold=%d)\n", + fprintf(stderr, "flushing/staling buffer %p (hold=%d)\n", bp, hold); #endif - libxfs_writebuf_int(bp, 0); + if (bip->bli_flags & XFS_BLI_DIRTY) + libxfs_writebuf_int(bp, 0); if (hold) bip->bli_flags &= ~XFS_BLI_HOLD; else diff --git a/libxfs/util.c b/libxfs/util.c index 8d55b8799..bd932be87 100644 --- a/libxfs/util.c +++ b/libxfs/util.c @@ -50,6 +50,61 @@ libxfs_ichgtime(xfs_inode_t *ip, int flags) } } +/* + * Given a mount structure and an inode number, return a pointer + * to a newly allocated in-core inode coresponding to the given + * inode number. + * + * Initialize the inode's attributes and extent pointers if it + * already has them (it will not if the inode has no links). + */ +int +libxfs_iread( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_ino_t ino, + xfs_inode_t *ip, + xfs_daddr_t bno) +{ + xfs_buf_t *bp; + xfs_dinode_t *dip; + int error; + + ip->i_ino = ino; + ip->i_mount = mp; + if ((error = xfs_itobp(mp, tp, ip, &dip, &bp, bno))) + return error; + if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC) { + xfs_trans_brelse(tp, bp); + return EINVAL; + } + if (dip->di_core.di_mode) { + xfs_xlate_dinode_core((xfs_caddr_t)&dip->di_core, + &(ip->i_d), 1); + if ((error = xfs_iformat(ip, dip))) { + xfs_trans_brelse(tp, bp); + return error; + } + } else { + ip->i_d.di_magic = INT_GET(dip->di_core.di_magic, ARCH_CONVERT); + ip->i_d.di_version = INT_GET(dip->di_core.di_version, ARCH_CONVERT); + ip->i_d.di_gen = INT_GET(dip->di_core.di_gen, ARCH_CONVERT); + ip->i_d.di_flushiter = INT_GET(dip->di_core.di_flushiter, ARCH_CONVERT); + ip->i_d.di_mode = 0; + ip->i_df.if_ext_max = + XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); + } + if (ip->i_d.di_version == XFS_DINODE_VERSION_1) { + ip->i_d.di_nlink = ip->i_d.di_onlink; + ip->i_d.di_onlink = 0; + ip->i_d.di_projid = 0; + } + ip->i_delayed_blks = 0; + XFS_BUF_SET_REF(bp, XFS_INO_REF); + xfs_trans_brelse(tp, bp); + return 0; +} + /* * Allocate an inode on disk and return a copy of it's in-core version. * Set mode, nlink, and rdev appropriately within the inode. diff --git a/libxfs/xfs.h b/libxfs/xfs.h index ed87c7a56..d9b7106eb 100644 --- a/libxfs/xfs.h +++ b/libxfs/xfs.h @@ -88,10 +88,11 @@ #define xfs_initialize_perag libxfs_initialize_perag #define xfs_rtmount_init libxfs_rtmount_init #define xfs_alloc_fix_freelist libxfs_alloc_fix_freelist -#define xfs_iread libxfs_iread #define xfs_idata_realloc libxfs_idata_realloc #define xfs_idestroy_fork libxfs_idestroy_fork +#define xfs_iread libxfs_iread #define xfs_itobp libxfs_itobp +#define xfs_iformat libxfs_iformat #define xfs_ichgtime libxfs_ichgtime #define xfs_bmapi libxfs_bmapi #define xfs_bmap_finish libxfs_bmap_finish @@ -112,8 +113,9 @@ #define xfs_trans_alloc libxfs_trans_alloc #define xfs_trans_commit libxfs_trans_commit #define xfs_trans_cancel libxfs_trans_cancel -#define xfs_trans_mod_sb libxfs_trans_mod_sb #define xfs_trans_reserve libxfs_trans_reserve +#define xfs_trans_getsb libxfs_trans_getsb +#define xfs_trans_mod_sb libxfs_trans_mod_sb #define xfs_trans_get_buf libxfs_trans_get_buf #define xfs_trans_log_buf libxfs_trans_log_buf #define xfs_trans_read_buf libxfs_trans_read_buf @@ -153,11 +155,11 @@ #define XFS_BUF_LOCK 0 #define XFS_BUF_MAPPED 0 #define XFS_BUF_TRYLOCK 0 -#define XFS_BUF_ISDONE(bp) 0 #define XFS_BUF_GETERROR(bp) 0 -#define XFS_BUF_DONE(bp) ((void) 0) -#define XFS_BUF_STALE(bp) ((void) 0) -#define XFS_BUF_UNDELAYWRITE(bp) ((void) 0) +#define XFS_BUF_DONE(bp) ((bp)->b_flags |= LIBXFS_B_UPTODATE) +#define XFS_BUF_ISDONE(bp) ((bp)->b_flags & LIBXFS_B_UPTODATE) +#define XFS_BUF_STALE(bp) ((bp)->b_flags |= LIBXFS_B_STALE) +#define XFS_BUF_UNDELAYWRITE(bp) ((bp)->b_flags &= ~LIBXFS_B_DIRTY) #define XFS_BUF_SET_REF(a,b) ((void) 0) #define XFS_BUF_SET_VTYPE(a,b) ((void) 0) #define XFS_BUF_SET_VTYPE_REF(a,b,c) ((void) 0) @@ -420,6 +422,8 @@ static inline int xfs_btree_readahead (xfs_btree_cur_t *cur, int lev, int lr) /* xfs_inode.c */ int xfs_ialloc (xfs_trans_t *, xfs_inode_t *, mode_t, nlink_t, xfs_dev_t, cred_t *, xfs_prid_t, int, xfs_buf_t **, boolean_t *, xfs_inode_t **); +int xfs_iread (xfs_mount_t *, xfs_trans_t *, xfs_ino_t, xfs_inode_t *, + xfs_daddr_t); int xfs_iread_extents (xfs_trans_t *, xfs_inode_t *, int); int xfs_imap (xfs_mount_t *, xfs_trans_t *, xfs_ino_t, xfs_imap_t *, uint); int xfs_iextents_copy (xfs_inode_t *, xfs_bmbt_rec_t *, int); diff --git a/libxfs/xfs_inode.c b/libxfs/xfs_inode.c index a45861286..844b9baaa 100644 --- a/libxfs/xfs_inode.c +++ b/libxfs/xfs_inode.c @@ -605,172 +605,6 @@ xfs_xlate_dinode_core( INT_XLATE(buf_core->di_gen, mem_core->di_gen, dir, arch); } -/* - * Given a mount structure and an inode number, return a pointer - * to a newly allocated in-core inode coresponding to the given - * inode number. - * - * Initialize the inode's attributes and extent pointers if it - * already has them (it will not if the inode has no links). - */ -int -xfs_iread( - xfs_mount_t *mp, - xfs_trans_t *tp, - xfs_ino_t ino, - xfs_inode_t **ipp, - xfs_daddr_t bno) -{ - xfs_buf_t *bp; - xfs_dinode_t *dip; - xfs_inode_t *ip; - int error; - - ASSERT(xfs_inode_zone != NULL); - - ip = kmem_zone_zalloc(xfs_inode_zone, KM_SLEEP); - ip->i_ino = ino; - ip->i_mount = mp; - - /* - * Get pointer's to the on-disk inode and the buffer containing it. - * If the inode number refers to a block outside the file system - * then xfs_itobp() will return NULL. In this case we should - * return NULL as well. Set i_blkno to 0 so that xfs_itobp() will - * know that this is a new incore inode. - */ - error = xfs_itobp(mp, tp, ip, &dip, &bp, bno); - - if (error != 0) { - kmem_zone_free(xfs_inode_zone, ip); - return error; - } - - /* - * Initialize inode's trace buffers. - * Do this before xfs_iformat in case it adds entries. - */ -#ifdef XFS_BMAP_TRACE - ip->i_xtrace = ktrace_alloc(XFS_BMAP_KTRACE_SIZE, KM_SLEEP); -#endif -#ifdef XFS_BMBT_TRACE - ip->i_btrace = ktrace_alloc(XFS_BMBT_KTRACE_SIZE, KM_SLEEP); -#endif -#ifdef XFS_RW_TRACE - ip->i_rwtrace = ktrace_alloc(XFS_RW_KTRACE_SIZE, KM_SLEEP); -#endif -#ifdef XFS_ILOCK_TRACE - ip->i_lock_trace = ktrace_alloc(XFS_ILOCK_KTRACE_SIZE, KM_SLEEP); -#endif -#ifdef XFS_DIR2_TRACE - ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, KM_SLEEP); -#endif - - /* - * If we got something that isn't an inode it means someone - * (nfs or dmi) has a stale handle. - */ - if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC) { - kmem_zone_free(xfs_inode_zone, ip); - xfs_trans_brelse(tp, bp); -#ifdef DEBUG - xfs_fs_cmn_err(CE_ALERT, mp, "xfs_iread: " - "dip->di_core.di_magic (0x%x) != " - "XFS_DINODE_MAGIC (0x%x)", - INT_GET(dip->di_core.di_magic, ARCH_CONVERT), - XFS_DINODE_MAGIC); -#endif /* DEBUG */ - return XFS_ERROR(EINVAL); - } - - /* - * If the on-disk inode is already linked to a directory - * entry, copy all of the inode into the in-core inode. - * xfs_iformat() handles copying in the inode format - * specific information. - * Otherwise, just get the truly permanent information. - */ - if (dip->di_core.di_mode) { - xfs_xlate_dinode_core((xfs_caddr_t)&dip->di_core, - &(ip->i_d), 1); - error = xfs_iformat(ip, dip); - if (error) { - kmem_zone_free(xfs_inode_zone, ip); - xfs_trans_brelse(tp, bp); -#ifdef DEBUG - xfs_fs_cmn_err(CE_ALERT, mp, "xfs_iread: " - "xfs_iformat() returned error %d", - error); -#endif /* DEBUG */ - return error; - } - } else { - ip->i_d.di_magic = INT_GET(dip->di_core.di_magic, ARCH_CONVERT); - ip->i_d.di_version = INT_GET(dip->di_core.di_version, ARCH_CONVERT); - ip->i_d.di_gen = INT_GET(dip->di_core.di_gen, ARCH_CONVERT); - ip->i_d.di_flushiter = INT_GET(dip->di_core.di_flushiter, ARCH_CONVERT); - /* - * Make sure to pull in the mode here as well in - * case the inode is released without being used. - * This ensures that xfs_inactive() will see that - * the inode is already free and not try to mess - * with the uninitialized part of it. - */ - ip->i_d.di_mode = 0; - /* - * Initialize the per-fork minima and maxima for a new - * inode here. xfs_iformat will do it for old inodes. - */ - ip->i_df.if_ext_max = - XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); - } - - INIT_LIST_HEAD(&ip->i_reclaim); - - /* - * The inode format changed when we moved the link count and - * made it 32 bits long. If this is an old format inode, - * convert it in memory to look like a new one. If it gets - * flushed to disk we will convert back before flushing or - * logging it. We zero out the new projid field and the old link - * count field. We'll handle clearing the pad field (the remains - * of the old uuid field) when we actually convert the inode to - * the new format. We don't change the version number so that we - * can distinguish this from a real new format inode. - */ - if (ip->i_d.di_version == XFS_DINODE_VERSION_1) { - ip->i_d.di_nlink = ip->i_d.di_onlink; - ip->i_d.di_onlink = 0; - ip->i_d.di_projid = 0; - } - - ip->i_delayed_blks = 0; - - /* - * Mark the buffer containing the inode as something to keep - * around for a while. This helps to keep recently accessed - * meta-data in-core longer. - */ - XFS_BUF_SET_REF(bp, XFS_INO_REF); - - /* - * Use xfs_trans_brelse() to release the buffer containing the - * on-disk inode, because it was acquired with xfs_trans_read_buf() - * in xfs_itobp() above. If tp is NULL, this is just a normal - * brelse(). If we're within a transaction, then xfs_trans_brelse() - * will only release the buffer if it is not dirty within the - * transaction. It will be OK to release the buffer in this case, - * because inodes on disk are never destroyed and we will be - * locking the new in-core inode before putting it in the hash - * table where other processes can find it. Thus we don't have - * to worry about the inode being changed just because we released - * the buffer. - */ - xfs_trans_brelse(tp, bp); - *ipp = ip; - return 0; -} - /* * Read in extents from a btree-format inode. * Allocate and fill in if_extents. Real work is done in xfs_bmap.c. diff --git a/libxfs/xfs_mount.c b/libxfs/xfs_mount.c index 6cd170abd..583293158 100644 --- a/libxfs/xfs_mount.c +++ b/libxfs/xfs_mount.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. + * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or @@ -212,6 +212,46 @@ xfs_xlatesb( } } +/* + * xfs_mod_sb() can be used to copy arbitrary changes to the + * in-core superblock into the superblock buffer to be logged. + * It does not provide the higher level of locking that is + * needed to protect the in-core superblock from concurrent + * access. + */ +void +xfs_mod_sb(xfs_trans_t *tp, __int64_t fields) +{ + xfs_buf_t *bp; + int first; + int last; + xfs_mount_t *mp; + xfs_sb_t *sbp; + xfs_sb_field_t f; + + ASSERT(fields); + if (!fields) + return; + mp = tp->t_mountp; + bp = xfs_trans_getsb(tp, mp, 0); + sbp = XFS_BUF_TO_SBP(bp); + first = sizeof(xfs_sb_t); + last = 0; + + /* translate/copy */ + xfs_xlatesb(XFS_BUF_PTR(bp), &(mp->m_sb), -1, fields); + + /* find modified range */ + f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields); + ASSERT((1LL << f) & XFS_SB_MOD_BITS); + first = xfs_sb_info[f].offset; + f = (xfs_sb_field_t)xfs_highbit64((__uint64_t)fields); + ASSERT((1LL << f) & XFS_SB_MOD_BITS); + last = xfs_sb_info[f + 1].offset - 1; + + xfs_trans_log_buf(tp, bp, first, last); +} + xfs_agnumber_t xfs_initialize_perag(xfs_mount_t *mp, xfs_agnumber_t agcount) { diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index 6b4594e03..03da415e3 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -2030,6 +2030,7 @@ an AG size that is one stripe unit smaller, for example %llu.\n"), buf = libxfs_getbuf(xi.ddev, 0, BTOBB(WHACK_SIZE)); bzero(XFS_BUF_PTR(buf), WHACK_SIZE); libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE); + libxfs_purgebuf(buf); /* OK, now write the superblock */ buf = libxfs_getbuf(xi.ddev, XFS_SB_DADDR, XFS_FSS_TO_BB(mp, 1)); @@ -2331,6 +2332,14 @@ an AG size that is one stripe unit smaller, for example %llu.\n"), } } + /* + * Dump all inodes and buffers before marking us all done. + * Need to drop references to inodes we still hold, first. + */ + libxfs_rtmount_destroy(mp); + libxfs_icache_purge(); + libxfs_bcache_purge(); + /* * Mark the filesystem ok. */ diff --git a/repair/phase6.c b/repair/phase6.c index b3a421e93..d92f9599c 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -719,8 +719,6 @@ mk_orphanage(xfs_mount_t *mp) int error; xfs_bmap_free_t flist; const int mode = 0755; - const int uid = 0; - const int gid = 0; int nres; tp = libxfs_trans_alloc(mp, 0); @@ -741,14 +739,10 @@ mk_orphanage(xfs_mount_t *mp) error = libxfs_inode_alloc(&tp, pip, mode|S_IFDIR, 1, 0, &zerocr, &zerofsx, &ip); - if (error) { do_error(_("%s inode allocation failed %d\n"), ORPHANAGE, error); } - - ip->i_d.di_uid = uid; - ip->i_d.di_gid = gid; ip->i_d.di_nlink++; /* account for . */ /* diff --git a/repair/scan.c b/repair/scan.c index ee0eac553..80bbfc2a6 100644 --- a/repair/scan.c +++ b/repair/scan.c @@ -42,6 +42,7 @@ static xfs_agino_t agifreecount; void set_mp(xfs_mount_t *mpp) { + libxfs_bcache_purge(); mp = mpp; } @@ -1171,7 +1172,7 @@ scan_ag( agicount = agifreecount = 0; sbbuf = libxfs_readbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_SB_DADDR), - 1, 0); + XFS_FSS_TO_BB(mp, 1), 0); if (!sbbuf) { do_error(_("can't get root superblock for ag %d\n"), agno); return; diff --git a/repair/xfs_repair.c b/repair/xfs_repair.c index 8693b47d6..0acb2a0d3 100644 --- a/repair/xfs_repair.c +++ b/repair/xfs_repair.c @@ -500,6 +500,10 @@ main(int argc, char **argv) phase4(mp); + /* XXX: nathans - something in phase4 ain't playing by */ + /* the buffer cache rules.. why doesn't IRIX hit this? */ + libxfs_bcache_purge(); + if (no_modify) printf(_("No modify flag set, skipping phase 5\n")); else @@ -577,6 +581,12 @@ _("Warning: project quota information would be cleared.\n" return(0); } + /* + * Done, flush all cached buffers and inodes. + */ + libxfs_icache_purge(); + libxfs_bcache_purge(); + /* * Clear the quota flags if they're on. */