Annotation of src/sys/ufs/ffs/ffs_wapbl.c, Revision 1.1.2.1
1.1.2.1 ! simonb 1: /* $NetBSD: ffs_wapbl.c,v 1.22 2007/10/09 05:12:53 simonb Exp $ */
! 2:
! 3: /*-
! 4: * Copyright (c) 2003,2006,2008 The NetBSD Foundation, Inc.
! 5: * All rights reserved.
! 6: *
! 7: * This code is derived from software contributed to The NetBSD Foundation
! 8: * by Wasabi Systems, Inc.
! 9: *
! 10: * Redistribution and use in source and binary forms, with or without
! 11: * modification, are permitted provided that the following conditions
! 12: * are met:
! 13: * 1. Redistributions of source code must retain the above copyright
! 14: * notice, this list of conditions and the following disclaimer.
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in the
! 17: * documentation and/or other materials provided with the distribution.
! 18: * 3. All advertising materials mentioning features or use of this software
! 19: * must display the following acknowledgement:
! 20: * This product includes software developed by the NetBSD
! 21: * Foundation, Inc. and its contributors.
! 22: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 23: * contributors may be used to endorse or promote products derived
! 24: * from this software without specific prior written permission.
! 25: *
! 26: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 27: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 36: * POSSIBILITY OF SUCH DAMAGE.
! 37: */
! 38:
! 39: #include <sys/cdefs.h>
! 40: __KERNEL_RCSID(0, "$NetBSD: ffs_wapbl.c,v 1.22 2007/10/09 05:12:53 simonb Exp $");
! 41:
! 42: #if defined(_KERNEL_OPT)
! 43: #include "opt_ffs.h"
! 44: #endif
! 45:
! 46: #include <sys/param.h>
! 47: #include <sys/systm.h>
! 48: #include <sys/kernel.h>
! 49: #include <sys/vnode.h>
! 50: #include <sys/mount.h>
! 51: #include <sys/file.h>
! 52: #include <sys/disk.h>
! 53: #include <sys/disklabel.h>
! 54: #include <sys/ioctl.h>
! 55: #include <sys/errno.h>
! 56: #include <sys/kauth.h>
! 57: #include <sys/wapbl.h>
! 58:
! 59: #include <ufs/ufs/quota.h>
! 60: #include <ufs/ufs/ufsmount.h>
! 61: #include <ufs/ufs/inode.h>
! 62: #include <ufs/ufs/ufs_wapbl.h>
! 63:
! 64: #include <ufs/ffs/fs.h>
! 65: #include <ufs/ffs/ffs_extern.h>
! 66:
! 67: static int ffs_wapbl_log_position(struct mount *, struct fs *, struct vnode *,
! 68: daddr_t *, size_t *, size_t *);
! 69:
! 70: /* This function is invoked after a log is replayed to
! 71: * disk to perform logical cleanup actions as described by
! 72: * the log
! 73: */
! 74: void
! 75: ffs_wapbl_replay_finish(struct mount *mp)
! 76: {
! 77: struct wapbl_replay *wr = mp->mnt_wapbl_replay;
! 78: int i;
! 79: int error;
! 80:
! 81: if (!wr)
! 82: return;
! 83:
! 84: KDASSERT((mp->mnt_flag & MNT_RDONLY) == 0);
! 85:
! 86: for (i=0;i<wr->wr_inodescnt;i++) {
! 87: struct vnode *vp;
! 88: struct inode *ip;
! 89: error = VFS_VGET(mp, wr->wr_inodes[i].wr_inumber, &vp);
! 90: if (error) {
! 91: printf("ffs_wapbl_replay_finish: "
! 92: "unable to cleanup inode %" PRIu32 "\n",
! 93: wr->wr_inodes[i].wr_inumber);
! 94: continue;
! 95: }
! 96: ip = VTOI(vp);
! 97: KDASSERT(wr->wr_inodes[i].wr_inumber == ip->i_number);
! 98: printf("ffs_wapbl_replay_finish: "
! 99: "cleaning inode %" PRIu64 " size=%" PRIu64 " mode=%o nlink=%d\n",
! 100: ip->i_number, ip->i_size, ip->i_mode, ip->i_nlink);
! 101: KASSERT(ip->i_nlink == 0);
! 102:
! 103: /*
! 104: * The journal may have left partially allocated inodes in mode
! 105: * zero. This may occur if a crash occurs betweeen the node
! 106: * allocation in ffs_nodeallocg and when the node is properly
! 107: * initialized in ufs_makeinode. If so, just dallocate them.
! 108: */
! 109: if (ip->i_mode == 0) {
! 110: UFS_WAPBL_BEGIN(mp);
! 111: ffs_vfree(vp, ip->i_number, wr->wr_inodes[i].wr_imode);
! 112: UFS_WAPBL_END(mp);
! 113: }
! 114: vput(vp);
! 115: }
! 116: mp->mnt_wapbl_replay = 0;
! 117: wapbl_replay_free(wr);
! 118: }
! 119:
! 120: /* Callback for wapbl */
! 121: void
! 122: ffs_wapbl_sync_metadata(struct mount *mp, daddr_t *deallocblks,
! 123: int *dealloclens, int dealloccnt)
! 124: {
! 125: struct ufsmount *ump = VFSTOUFS(mp);
! 126: struct fs *fs = ump->um_fs;
! 127: int i, error;
! 128:
! 129: #ifdef WAPBL_DEBUG_INODES
! 130: ufs_wapbl_verify_inodes(mp, "ffs_wapbl_sync_metadata");
! 131: #endif
! 132:
! 133: for (i = 0; i< dealloccnt; i++) {
! 134: /*
! 135: * blkfree errors are unreported, might silently fail
! 136: * if it cannot read the cylinder group block
! 137: */
! 138: ffs_blkfree(fs, ump->um_devvp,
! 139: dbtofsb(fs, deallocblks[i]), dealloclens[i], -1);
! 140: }
! 141:
! 142: fs->fs_fmod = 0;
! 143: fs->fs_time = time_second;
! 144: error = ffs_cgupdate(ump, 0);
! 145: KASSERT(error == 0);
! 146: }
! 147:
! 148: void
! 149: ffs_wapbl_abort_sync_metadata(struct mount *mp, daddr_t *deallocblks,
! 150: int *dealloclens, int dealloccnt)
! 151: {
! 152: struct ufsmount *ump = VFSTOUFS(mp);
! 153: struct fs *fs = ump->um_fs;
! 154: int i;
! 155:
! 156: /*
! 157: * I suppose we could dig around for an in use inode, but
! 158: * its not really used by ffs_blkalloc, so we just fake
! 159: * the couple of fields that it touches.
! 160: */
! 161: struct inode in;
! 162: in.i_fs = fs;
! 163: in.i_devvp = ump->um_devvp;
! 164: in.i_dev = ump->um_dev;
! 165: in.i_number = -1;
! 166: in.i_uid = 0;
! 167: for (i = 0; i < dealloccnt; i++) {
! 168: /*
! 169: * Since the above blkfree may have failed, this blkalloc might
! 170: * fail as well, so don't check its error. Note that if the
! 171: * blkfree succeeded above, then this shouldn't fail because
! 172: * the buffer will be locked in the current transaction.
! 173: */
! 174: ffs_blkalloc(&in, dbtofsb(fs, deallocblks[i]),
! 175: dealloclens[i]);
! 176: }
! 177: }
! 178:
! 179:
! 180: static int
! 181: ffs_wapbl_log_position(struct mount *mp, struct fs *fs, struct vnode *devvp,
! 182: daddr_t* startp, size_t* countp, size_t* blksizep)
! 183: {
! 184: int error;
! 185: struct partinfo dpart;
! 186: daddr_t logstart = fsbtodb(fs, fs->fs_size);
! 187: daddr_t logend ;
! 188: size_t blksize;
! 189:
! 190: /* Use space after filesystem on partition for log */
! 191:
! 192: error = VOP_IOCTL(devvp, DIOCGPART, &dpart, FREAD, FSCRED);
! 193: if (!error) {
! 194: logend = dpart.part->p_size;
! 195: blksize = dpart.disklab->d_secsize;
! 196: } else {
! 197: struct dkwedge_info dkw;
! 198: error = VOP_IOCTL(devvp, DIOCGWEDGEINFO, &dkw, FREAD, FSCRED);
! 199: if (error)
! 200: return error;
! 201:
! 202: blksize = DEV_BSIZE;
! 203: logend = dkw.dkw_size;
! 204: }
! 205:
! 206: KDASSERT(blksize != 0);
! 207: KDASSERT(logstart <= logend);
! 208:
! 209: *startp = logstart;
! 210: *countp = (logend - logstart);
! 211: *blksizep = blksize;
! 212:
! 213: return 0;
! 214: }
! 215:
! 216: int
! 217: ffs_wapbl_start(struct mount *mp)
! 218: {
! 219: struct ufsmount *ump = VFSTOUFS(mp);
! 220: struct fs *fs = ump->um_fs;
! 221: struct vnode *devvp = ump->um_devvp;
! 222: daddr_t off;
! 223: size_t count;
! 224: size_t blksize;
! 225: int error;
! 226:
! 227: if (mp->mnt_wapbl == 0) {
! 228: if (mp->mnt_flag & MNT_LOG) {
! 229: KDASSERT(fs->fs_ronly == 0);
! 230:
! 231: error = ffs_wapbl_log_position(mp, fs, devvp, &off,
! 232: &count, &blksize);
! 233: if (error)
! 234: return error;
! 235:
! 236: error = wapbl_start(&mp->mnt_wapbl, mp, devvp, off,
! 237: count, blksize, mp->mnt_wapbl_replay,
! 238: ffs_wapbl_sync_metadata,
! 239: ffs_wapbl_abort_sync_metadata);
! 240: if (error)
! 241: return error;
! 242:
! 243: mp->mnt_wapbl_op = &wapbl_ops;
! 244:
! 245: #ifdef WAPBL_DEBUG
! 246: printf("%s: enabling logging\n", fs->fs_fsmnt);
! 247: #endif
! 248:
! 249: if ((fs->fs_flags & FS_DOWAPBL) == 0) {
! 250: UFS_WAPBL_BEGIN(mp);
! 251: fs->fs_flags |= FS_DOWAPBL;
! 252: error = ffs_sbupdate(ump, MNT_WAIT);
! 253: KASSERT(error == 0);
! 254: UFS_WAPBL_END(mp);
! 255: error = wapbl_flush(mp->mnt_wapbl, 1);
! 256: if (error) {
! 257: ffs_wapbl_stop(mp, MNT_FORCE);
! 258: return error;
! 259: }
! 260: }
! 261: } else if (fs->fs_flags & FS_DOWAPBL) {
! 262: fs->fs_fmod = 1;
! 263: fs->fs_flags &= ~FS_DOWAPBL;
! 264: }
! 265: }
! 266:
! 267: /*
! 268: * It is recommended that you finish replay with logging enabled.
! 269: * However, even if logging is not enabled, the remaining log
! 270: * replay should be safely recoverable with an fsck, so perform
! 271: * it anyway.
! 272: */
! 273: if ((fs->fs_ronly == 0) && mp->mnt_wapbl_replay) {
! 274: int saveflag = mp->mnt_flag & MNT_RDONLY;
! 275: /*
! 276: * Make sure MNT_RDONLY is not set so that the inode
! 277: * cleanup in ufs_inactive will actually do its work.
! 278: */
! 279: mp->mnt_flag &= ~MNT_RDONLY;
! 280: ffs_wapbl_replay_finish(mp);
! 281: mp->mnt_flag |= saveflag;
! 282: KASSERT(fs->fs_ronly == 0);
! 283: }
! 284:
! 285: return 0;
! 286: }
! 287:
! 288: int
! 289: ffs_wapbl_stop(struct mount *mp, int force)
! 290: {
! 291: struct ufsmount *ump = VFSTOUFS(mp);
! 292: struct fs *fs = ump->um_fs;
! 293: int error;
! 294:
! 295: if (mp->mnt_wapbl) {
! 296: KDASSERT(fs->fs_ronly == 0);
! 297:
! 298: /*
! 299: * Make sure turning off FS_DOWAPBL is only removed
! 300: * as the only change in the final flush since otherwise
! 301: * a transaction may reorder writes.
! 302: */
! 303: error = wapbl_flush(mp->mnt_wapbl, 1);
! 304: if (error && !force)
! 305: return error;
! 306: if (error && force)
! 307: goto forceout;
! 308: error = UFS_WAPBL_BEGIN(mp);
! 309: if (error && !force)
! 310: return error;
! 311: if (error && force)
! 312: goto forceout;
! 313: KASSERT(fs->fs_flags & FS_DOWAPBL);
! 314: fs->fs_flags &= ~FS_DOWAPBL;
! 315: error = ffs_sbupdate(ump, MNT_WAIT);
! 316: KASSERT(error == 0);
! 317: UFS_WAPBL_END(mp);
! 318: forceout:
! 319: error = wapbl_stop(mp->mnt_wapbl, force);
! 320: if (error) {
! 321: KASSERT(!force);
! 322: fs->fs_flags |= FS_DOWAPBL;
! 323: return error;
! 324: }
! 325: fs->fs_flags &= ~FS_DOWAPBL; /* Repeat in case of forced error */
! 326: mp->mnt_wapbl = 0;
! 327:
! 328: #ifdef WAPBL_DEBUG
! 329: printf("%s: disabled logging\n", fs->fs_fsmnt);
! 330: #endif
! 331: }
! 332:
! 333: return 0;
! 334: }
! 335:
! 336: int
! 337: ffs_wapbl_replay_start(struct mount *mp, struct fs *fs, struct vnode *devvp)
! 338: {
! 339: int error;
! 340: daddr_t off;
! 341: size_t count;
! 342: size_t blksize;
! 343:
! 344: error = ffs_wapbl_log_position(mp, fs, devvp, &off, &count, &blksize);
! 345: if (error)
! 346: return error;
! 347:
! 348: /* Use space after filesystem on partition for log */
! 349: error = wapbl_replay_start(&mp->mnt_wapbl_replay, devvp, off,
! 350: count, blksize);
! 351: if (error)
! 352: return error;
! 353:
! 354: mp->mnt_wapbl_op = &wapbl_ops;
! 355:
! 356: return 0;
! 357: }
CVSweb <webmaster@jp.NetBSD.org>