Annotation of src/sys/ufs/ffs/ffs_snapshot.c, Revision 1.43.2.2
1.43.2.2! ad 1: /* $NetBSD: ffs_snapshot.c,v 1.43.2.1 2007/03/13 17:51:20 ad Exp $ */
1.18 thorpej 2:
1.1 hannken 3: /*
4: * Copyright 2000 Marshall Kirk McKusick. All Rights Reserved.
5: *
6: * Further information about snapshots can be obtained from:
7: *
8: * Marshall Kirk McKusick http://www.mckusick.com/softdep/
9: * 1614 Oxford Street mckusick@mckusick.com
10: * Berkeley, CA 94709-1608 +1-510-843-9542
11: * USA
12: *
13: * Redistribution and use in source and binary forms, with or without
14: * modification, are permitted provided that the following conditions
15: * are met:
16: *
17: * 1. Redistributions of source code must retain the above copyright
18: * notice, this list of conditions and the following disclaimer.
19: * 2. Redistributions in binary form must reproduce the above copyright
20: * notice, this list of conditions and the following disclaimer in the
21: * documentation and/or other materials provided with the distribution.
22: *
23: * THIS SOFTWARE IS PROVIDED BY MARSHALL KIRK MCKUSICK ``AS IS'' AND ANY
24: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26: * DISCLAIMED. IN NO EVENT SHALL MARSHALL KIRK MCKUSICK BE LIABLE FOR
27: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: *
35: * @(#)ffs_snapshot.c 8.11 (McKusick) 7/23/00
36: *
37: * from FreeBSD: ffs_snapshot.c,v 1.79 2004/02/13 02:02:06 kuriyama Exp
38: */
39:
40: #include <sys/cdefs.h>
1.43.2.2! ad 41: __KERNEL_RCSID(0, "$NetBSD: ffs_snapshot.c,v 1.43.2.1 2007/03/13 17:51:20 ad Exp $");
1.8 hannken 42:
43: #if defined(_KERNEL_OPT)
44: #include "opt_ffs.h"
1.38 hannken 45: #include "opt_quota.h"
1.8 hannken 46: #endif
1.1 hannken 47:
48: #include <sys/param.h>
49: #include <sys/kernel.h>
50: #include <sys/systm.h>
51: #include <sys/conf.h>
52: #include <sys/buf.h>
53: #include <sys/proc.h>
54: #include <sys/namei.h>
55: #include <sys/sched.h>
56: #include <sys/stat.h>
57: #include <sys/malloc.h>
58: #include <sys/mount.h>
59: #include <sys/resource.h>
60: #include <sys/resourcevar.h>
61: #include <sys/vnode.h>
1.29 elad 62: #include <sys/kauth.h>
1.40 hannken 63: #include <sys/fstrans.h>
1.1 hannken 64:
65: #include <miscfs/specfs/specdev.h>
66:
67: #include <ufs/ufs/quota.h>
68: #include <ufs/ufs/ufsmount.h>
69: #include <ufs/ufs/inode.h>
70: #include <ufs/ufs/ufs_extern.h>
71: #include <ufs/ufs/ufs_bswap.h>
72:
73: #include <ufs/ffs/fs.h>
74: #include <ufs/ffs/ffs_extern.h>
75:
76: /* FreeBSD -> NetBSD conversion */
1.31 ad 77: #define KERNCRED lwp0.l_cred
1.1 hannken 78: #define ufs1_daddr_t int32_t
79: #define ufs2_daddr_t int64_t
80: #define ufs_lbn_t daddr_t
81: #define VI_MTX(v) (&(v)->v_interlock)
1.43.2.1 ad 82: #define VI_LOCK(v) mutex_enter(&(v)->v_interlock)
83: #define VI_UNLOCK(v) mutex_exit(&(v)->v_interlock)
84: #define MNT_ILOCK(v) mutex_enter(&mntvnode_lock)
85: #define MNT_IUNLOCK(v) mutex_exit(&mntvnode_lock)
1.1 hannken 86:
1.10 hannken 87: #if !defined(FFS_NO_SNAPSHOT)
1.43 christos 88: static int cgaccount(int, struct vnode *, void *, int);
1.1 hannken 89: static int expunge_ufs1(struct vnode *, struct inode *, struct fs *,
90: int (*)(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *, struct fs *,
91: ufs_lbn_t, int), int);
92: static int indiracct_ufs1(struct vnode *, struct vnode *, int,
93: ufs1_daddr_t, ufs_lbn_t, ufs_lbn_t, ufs_lbn_t, ufs_lbn_t, struct fs *,
94: int (*)(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *, struct fs *,
95: ufs_lbn_t, int), int);
96: static int fullacct_ufs1(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *,
97: struct fs *, ufs_lbn_t, int);
98: static int snapacct_ufs1(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *,
99: struct fs *, ufs_lbn_t, int);
100: static int mapacct_ufs1(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *,
101: struct fs *, ufs_lbn_t, int);
102: static int expunge_ufs2(struct vnode *, struct inode *, struct fs *,
103: int (*)(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, struct fs *,
104: ufs_lbn_t, int), int);
105: static int indiracct_ufs2(struct vnode *, struct vnode *, int,
106: ufs2_daddr_t, ufs_lbn_t, ufs_lbn_t, ufs_lbn_t, ufs_lbn_t, struct fs *,
107: int (*)(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, struct fs *,
108: ufs_lbn_t, int), int);
109: static int fullacct_ufs2(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *,
110: struct fs *, ufs_lbn_t, int);
111: static int snapacct_ufs2(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *,
112: struct fs *, ufs_lbn_t, int);
113: static int mapacct_ufs2(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *,
114: struct fs *, ufs_lbn_t, int);
1.43 christos 115: static int readvnblk(struct vnode *, void *, ufs2_daddr_t);
1.10 hannken 116: #endif /* !defined(FFS_NO_SNAPSHOT) */
117:
1.1 hannken 118: static int ffs_copyonwrite(void *, struct buf *);
1.43 christos 119: static int readfsblk(struct vnode *, void *, ufs2_daddr_t);
120: static int writevnblk(struct vnode *, void *, ufs2_daddr_t);
1.4 hannken 121: static inline int cow_enter(void);
122: static inline void cow_leave(int);
1.1 hannken 123: static inline ufs2_daddr_t db_get(struct inode *, int);
124: static inline void db_assign(struct inode *, int, ufs2_daddr_t);
1.43 christos 125: static inline ufs2_daddr_t idb_get(struct inode *, void *, int);
126: static inline void idb_assign(struct inode *, void *, int, ufs2_daddr_t);
1.1 hannken 127:
128: #ifdef DEBUG
129: static int snapdebug = 0;
130: #endif
131:
132: /*
133: * Create a snapshot file and initialize it for the filesystem.
1.4 hannken 134: * Vnode is locked on entry and return.
1.1 hannken 135: */
136: int
1.36 christos 137: ffs_snapshot(struct mount *mp, struct vnode *vp,
138: struct timespec *ctime)
1.1 hannken 139: {
1.10 hannken 140: #if defined(FFS_NO_SNAPSHOT)
141: return EOPNOTSUPP;
142: }
143: #else /* defined(FFS_NO_SNAPSHOT) */
1.1 hannken 144: ufs2_daddr_t numblks, blkno, *blkp, snaplistsize = 0, *snapblklist;
145: int error, ns, cg, snaploc;
1.15 hannken 146: int i, s, size, len, loc;
1.1 hannken 147: int flag = mp->mnt_flag;
148: struct timeval starttime;
149: #ifdef DEBUG
150: struct timeval endtime;
151: #endif
152: struct timespec ts;
153: long redo = 0;
154: int32_t *lp;
155: void *space;
1.43 christos 156: void *sbbuf = NULL;
1.1 hannken 157: struct ufsmount *ump = VFSTOUFS(mp);
158: struct fs *copy_fs = NULL, *fs = ump->um_fs;
1.23 christos 159: struct lwp *l = curlwp;
1.1 hannken 160: struct inode *ip, *xp;
1.15 hannken 161: struct buf *bp, *ibp, *nbp;
1.1 hannken 162: struct vattr vat;
1.35 reinoud 163: struct vnode *xvp, *nvp, *devvp;
1.1 hannken 164:
165: ns = UFS_FSNEEDSWAP(fs);
166: /*
167: * Need to serialize access to snapshot code per filesystem.
168: */
169: /*
170: * If the vnode already is a snapshot, return.
171: */
172: if (VTOI(vp)->i_flags & SF_SNAPSHOT) {
173: if (ctime) {
174: ctime->tv_sec = DIP(VTOI(vp), mtime);
175: ctime->tv_nsec = DIP(VTOI(vp), mtimensec);
176: }
177: return 0;
178: }
179: /*
1.9 hannken 180: * Check mount, exclusive reference and owner.
1.1 hannken 181: */
1.4 hannken 182: if (vp->v_mount != mp)
1.1 hannken 183: return EXDEV;
1.4 hannken 184: if (vp->v_usecount != 1 || vp->v_writecount != 0)
1.1 hannken 185: return EBUSY;
1.31 ad 186: if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
1.39 elad 187: NULL) != 0 &&
1.31 ad 188: VTOI(vp)->i_uid != kauth_cred_geteuid(l->l_cred))
1.9 hannken 189: return EACCES;
190:
1.38 hannken 191: #ifdef QUOTA
192: if ((error = getinoquota(VTOI(vp))) != 0)
193: return error;
194: #endif
1.1 hannken 195: if (vp->v_size != 0) {
1.23 christos 196: error = ffs_truncate(vp, 0, 0, NOCRED, l);
1.4 hannken 197: if (error)
1.1 hannken 198: return error;
199: }
200: /*
201: * Assign a snapshot slot in the superblock.
202: */
203: for (snaploc = 0; snaploc < FSMAXSNAP; snaploc++)
204: if (fs->fs_snapinum[snaploc] == 0)
205: break;
206: if (snaploc == FSMAXSNAP)
207: return (ENOSPC);
208: ip = VTOI(vp);
209: devvp = ip->i_devvp;
210: /*
1.16 hannken 211: * Write an empty list of preallocated blocks to the end of
212: * the snapshot to set size to at least that of the filesystem.
1.1 hannken 213: */
214: numblks = howmany(fs->fs_size, fs->fs_frag);
1.16 hannken 215: blkno = 1;
216: blkno = ufs_rw64(blkno, ns);
1.1 hannken 217: error = vn_rdwr(UIO_WRITE, vp,
1.43 christos 218: (void *)&blkno, sizeof(blkno), lblktosize(fs, (off_t)numblks),
1.31 ad 219: UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, l->l_cred, NULL, NULL);
1.1 hannken 220: if (error)
221: goto out;
222: /*
223: * Preallocate critical data structures so that we can copy
224: * them in without further allocation after we suspend all
225: * operations on the filesystem. We would like to just release
226: * the allocated buffers without writing them since they will
227: * be filled in below once we are ready to go, but this upsets
228: * the soft update code, so we go ahead and write the new buffers.
229: *
230: * Allocate all indirect blocks and mark all of them as not
231: * needing to be copied.
232: */
233: for (blkno = NDADDR; blkno < numblks; blkno += NINDIR(fs)) {
1.22 yamt 234: error = ffs_balloc(vp, lblktosize(fs, (off_t)blkno),
1.31 ad 235: fs->fs_bsize, l->l_cred, B_METAONLY, &ibp);
1.1 hannken 236: if (error)
237: goto out;
1.15 hannken 238: bawrite(ibp);
1.1 hannken 239: }
240: /*
241: * Allocate copies for the superblock and its summary information.
242: */
1.22 yamt 243: error = ffs_balloc(vp, fs->fs_sblockloc, fs->fs_sbsize, KERNCRED,
1.15 hannken 244: 0, &nbp);
245: if (error)
246: goto out;
247: bawrite(nbp);
1.1 hannken 248: blkno = fragstoblks(fs, fs->fs_csaddr);
1.15 hannken 249: len = howmany(fs->fs_cssize, fs->fs_bsize);
250: for (loc = 0; loc < len; loc++) {
1.22 yamt 251: error = ffs_balloc(vp, lblktosize(fs, (off_t)(blkno + loc)),
1.15 hannken 252: fs->fs_bsize, KERNCRED, 0, &nbp);
253: if (error)
1.1 hannken 254: goto out;
1.15 hannken 255: bawrite(nbp);
256: }
1.1 hannken 257: /*
258: * Copy all the cylinder group maps. Although the
259: * filesystem is still active, we hope that only a few
260: * cylinder groups will change between now and when we
261: * suspend operations. Thus, we will be able to quickly
262: * touch up the few cylinder groups that changed during
263: * the suspension period.
264: */
265: len = howmany(fs->fs_ncg, NBBY);
1.25 christos 266: fs->fs_active = malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
1.1 hannken 267: for (cg = 0; cg < fs->fs_ncg; cg++) {
1.22 yamt 268: if ((error = ffs_balloc(vp, lfragtosize(fs, cgtod(fs, cg)),
1.15 hannken 269: fs->fs_bsize, KERNCRED, 0, &nbp)) != 0)
1.1 hannken 270: goto out;
1.15 hannken 271: error = cgaccount(cg, vp, nbp->b_data, 1);
272: bawrite(nbp);
273: if (error)
1.1 hannken 274: goto out;
275: }
276: /*
277: * Change inode to snapshot type file.
278: */
279: ip->i_flags |= SF_SNAPSHOT;
280: DIP_ASSIGN(ip, flags, ip->i_flags);
281: ip->i_flag |= IN_CHANGE | IN_UPDATE;
282: /*
283: * Ensure that the snapshot is completely on disk.
284: * Since we have marked it as a snapshot it is safe to
285: * unlock it as no process will be allowed to write to it.
286: */
1.23 christos 287: if ((error = VOP_FSYNC(vp, KERNCRED, FSYNC_WAIT, 0, 0, l)) != 0)
1.1 hannken 288: goto out;
289: VOP_UNLOCK(vp, 0);
290: /*
291: * All allocations are done, so we can now snapshot the system.
292: *
293: * Suspend operation on filesystem.
294: */
1.40 hannken 295: if ((error = vfs_suspend(vp->v_mount, 0)) != 0) {
1.1 hannken 296: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
297: goto out;
298: }
299: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.30 kardel 300: getmicrotime(&starttime);
1.1 hannken 301: /*
302: * First, copy all the cylinder group maps that have changed.
303: */
304: for (cg = 0; cg < fs->fs_ncg; cg++) {
305: if (ACTIVECG_ISSET(fs, cg))
306: continue;
307: redo++;
1.22 yamt 308: if ((error = ffs_balloc(vp, lfragtosize(fs, cgtod(fs, cg)),
1.15 hannken 309: fs->fs_bsize, KERNCRED, 0, &nbp)) != 0)
1.1 hannken 310: goto out1;
1.15 hannken 311: error = cgaccount(cg, vp, nbp->b_data, 2);
312: bawrite(nbp);
313: if (error)
1.1 hannken 314: goto out1;
315: }
316: /*
317: * Grab a copy of the superblock and its summary information.
318: * We delay writing it until the suspension is released below.
319: */
1.16 hannken 320: sbbuf = malloc(fs->fs_bsize, M_UFSMNT, M_WAITOK);
1.1 hannken 321: loc = blkoff(fs, fs->fs_sblockloc);
322: if (loc > 0)
1.43 christos 323: memset(sbbuf, 0, loc);
324: copy_fs = (struct fs *)((char *)sbbuf + loc);
1.1 hannken 325: bcopy(fs, copy_fs, fs->fs_sbsize);
326: size = fs->fs_bsize < SBLOCKSIZE ? fs->fs_bsize : SBLOCKSIZE;
327: if (fs->fs_sbsize < size)
1.43 christos 328: memset((char *)sbbuf + loc + fs->fs_sbsize, 0,
329: size - fs->fs_sbsize);
1.1 hannken 330: size = blkroundup(fs, fs->fs_cssize);
331: if (fs->fs_contigsumsize > 0)
332: size += fs->fs_ncg * sizeof(int32_t);
333: space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
334: copy_fs->fs_csp = space;
335: bcopy(fs->fs_csp, copy_fs->fs_csp, fs->fs_cssize);
1.12 yamt 336: space = (char *)space + fs->fs_cssize;
1.1 hannken 337: loc = howmany(fs->fs_cssize, fs->fs_fsize);
338: i = fs->fs_frag - loc % fs->fs_frag;
339: len = (i == fs->fs_frag) ? 0 : i * fs->fs_fsize;
340: if (len > 0) {
341: if ((error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + loc),
342: len, KERNCRED, &bp)) != 0) {
343: brelse(bp);
344: free(copy_fs->fs_csp, M_UFSMNT);
345: goto out1;
346: }
347: bcopy(bp->b_data, space, (u_int)len);
1.12 yamt 348: space = (char *)space + len;
1.1 hannken 349: bp->b_flags |= B_INVAL | B_NOCACHE;
350: brelse(bp);
351: }
352: if (fs->fs_contigsumsize > 0) {
353: copy_fs->fs_maxcluster = lp = space;
354: for (i = 0; i < fs->fs_ncg; i++)
355: *lp++ = fs->fs_contigsumsize;
356: }
357: /*
358: * We must check for active files that have been unlinked
359: * (e.g., with a zero link count). We have to expunge all
360: * trace of these files from the snapshot so that they are
361: * not reclaimed prematurely by fsck or unnecessarily dumped.
362: * We turn off the MNTK_SUSPENDED flag to avoid a panic from
363: * spec_strategy about writing on a suspended filesystem.
364: * Note that we skip unlinked snapshot files as they will
365: * be handled separately below.
366: *
367: * We also calculate the needed size for the snapshot list.
368: */
369: snaplistsize = fs->fs_ncg + howmany(fs->fs_cssize, fs->fs_bsize) +
370: FSMAXSNAP + 1 /* superblock */ + 1 /* last block */ + 1 /* size */;
371: MNT_ILOCK(mp);
372: loop:
1.35 reinoud 373: /*
374: * NOTE: not using the TAILQ_FOREACH here since in this loop vgone()
375: * and vclean() can be called indirectly
376: */
377: for (xvp = TAILQ_FIRST(&mp->mnt_vnodelist); xvp; xvp = nvp) {
1.1 hannken 378: /*
379: * Make sure this vnode wasn't reclaimed in getnewvnode().
380: * Start over if it has (it won't be on the list anymore).
381: */
382: if (xvp->v_mount != mp)
383: goto loop;
384: VI_LOCK(xvp);
1.35 reinoud 385: nvp = TAILQ_NEXT(xvp, v_mntvnodes);
1.1 hannken 386: MNT_IUNLOCK(mp);
387: if ((xvp->v_flag & VXLOCK) ||
388: xvp->v_usecount == 0 || xvp->v_type == VNON ||
389: (VTOI(xvp)->i_flags & SF_SNAPSHOT)) {
390: VI_UNLOCK(xvp);
391: MNT_ILOCK(mp);
392: continue;
393: }
1.40 hannken 394: VI_UNLOCK(xvp);
1.1 hannken 395: #ifdef DEBUG
396: if (snapdebug)
397: vprint("ffs_snapshot: busy vnode", xvp);
398: #endif
1.31 ad 399: if (VOP_GETATTR(xvp, &vat, l->l_cred, l) == 0 &&
1.1 hannken 400: vat.va_nlink > 0) {
401: MNT_ILOCK(mp);
402: continue;
403: }
404: xp = VTOI(xvp);
405: if (ffs_checkfreefile(copy_fs, vp, xp->i_number)) {
406: MNT_ILOCK(mp);
407: continue;
408: }
409: /*
410: * If there is a fragment, clear it here.
411: */
412: blkno = 0;
413: loc = howmany(xp->i_size, fs->fs_bsize) - 1;
414: if (loc < NDADDR) {
415: len = fragroundup(fs, blkoff(fs, xp->i_size));
1.5 hannken 416: if (len > 0 && len < fs->fs_bsize) {
1.1 hannken 417: ffs_blkfree(copy_fs, vp, db_get(xp, loc),
418: len, xp->i_number);
419: blkno = db_get(xp, loc);
420: db_assign(xp, loc, 0);
421: }
422: }
423: snaplistsize += 1;
424: if (xp->i_ump->um_fstype == UFS1)
425: error = expunge_ufs1(vp, xp, copy_fs, fullacct_ufs1,
426: BLK_NOCOPY);
427: else
428: error = expunge_ufs2(vp, xp, copy_fs, fullacct_ufs2,
429: BLK_NOCOPY);
430: if (blkno)
431: db_assign(xp, loc, blkno);
1.6 hannken 432: if (!error)
433: error = ffs_freefile(copy_fs, vp, xp->i_number,
434: xp->i_mode);
1.1 hannken 435: if (error) {
436: free(copy_fs->fs_csp, M_UFSMNT);
437: goto out1;
438: }
439: MNT_ILOCK(mp);
440: }
441: MNT_IUNLOCK(mp);
442: /*
443: * If there already exist snapshots on this filesystem, grab a
444: * reference to their shared lock. If this is the first snapshot
445: * on this filesystem, we need to allocate a lock for the snapshots
446: * to share. In either case, acquire the snapshot lock and give
447: * up our original private lock.
448: */
449: VI_LOCK(devvp);
450: if ((xp = TAILQ_FIRST(&ump->um_snapshots)) != NULL) {
451: struct lock *lkp;
452:
453: lkp = ITOV(xp)->v_vnlock;
454: VI_UNLOCK(devvp);
455: VI_LOCK(vp);
456: vp->v_vnlock = lkp;
457: } else {
458: struct lock *lkp;
459:
460: VI_UNLOCK(devvp);
461: MALLOC(lkp, struct lock *, sizeof(struct lock), M_UFSMNT,
462: M_WAITOK);
463: lockinit(lkp, PVFS, "snaplk", 0, LK_CANRECURSE);
464: VI_LOCK(vp);
465: vp->v_vnlock = lkp;
466: }
467: vn_lock(vp, LK_INTERLOCK | LK_EXCLUSIVE | LK_RETRY);
468: transferlockers(&vp->v_lock, vp->v_vnlock);
469: lockmgr(&vp->v_lock, LK_RELEASE, NULL);
470: /*
471: * If this is the first snapshot on this filesystem, then we need
472: * to allocate the space for the list of preallocated snapshot blocks.
473: * This list will be refined below, but this preliminary one will
474: * keep us out of deadlock until the full one is ready.
475: */
476: if (xp == NULL) {
1.25 christos 477: snapblklist = malloc(
1.1 hannken 478: snaplistsize * sizeof(ufs2_daddr_t), M_UFSMNT, M_WAITOK);
479: blkp = &snapblklist[1];
1.15 hannken 480: *blkp++ = lblkno(fs, fs->fs_sblockloc);
1.1 hannken 481: blkno = fragstoblks(fs, fs->fs_csaddr);
482: for (cg = 0; cg < fs->fs_ncg; cg++) {
1.15 hannken 483: if (fragstoblks(fs, cgtod(fs, cg)) > blkno)
1.1 hannken 484: break;
1.15 hannken 485: *blkp++ = fragstoblks(fs, cgtod(fs, cg));
1.1 hannken 486: }
487: len = howmany(fs->fs_cssize, fs->fs_bsize);
488: for (loc = 0; loc < len; loc++)
1.15 hannken 489: *blkp++ = blkno + loc;
1.1 hannken 490: for (; cg < fs->fs_ncg; cg++)
1.15 hannken 491: *blkp++ = fragstoblks(fs, cgtod(fs, cg));
492: snapblklist[0] = blkp - snapblklist;
1.1 hannken 493: VI_LOCK(devvp);
494: if (ump->um_snapblklist != NULL)
495: panic("ffs_snapshot: non-empty list");
496: ump->um_snapblklist = snapblklist;
497: VI_UNLOCK(devvp);
498: }
499: /*
500: * Record snapshot inode. Since this is the newest snapshot,
501: * it must be placed at the end of the list.
502: */
503: VI_LOCK(devvp);
504: fs->fs_snapinum[snaploc] = ip->i_number;
505: if (ip->i_nextsnap.tqe_prev != 0)
1.19 christos 506: panic("ffs_snapshot: %llu already on list",
507: (unsigned long long)ip->i_number);
1.1 hannken 508: TAILQ_INSERT_TAIL(&ump->um_snapshots, ip, i_nextsnap);
509: VI_UNLOCK(devvp);
510: if (xp == NULL)
511: vn_cow_establish(devvp, ffs_copyonwrite, devvp);
512: vp->v_flag |= VSYSTEM;
513: out1:
514: /*
515: * Resume operation on filesystem.
516: */
1.40 hannken 517: vfs_resume(vp->v_mount);
1.1 hannken 518: /*
519: * Set the mtime to the time the snapshot has been taken.
520: */
1.21 yamt 521: TIMEVAL_TO_TIMESPEC(&starttime, &ts);
1.1 hannken 522: if (ctime)
523: *ctime = ts;
524: DIP_ASSIGN(ip, mtime, ts.tv_sec);
525: DIP_ASSIGN(ip, mtimensec, ts.tv_nsec);
526: ip->i_flag |= IN_CHANGE | IN_UPDATE;
527:
528: #ifdef DEBUG
529: if (starttime.tv_sec > 0) {
1.30 kardel 530: getmicrotime(&endtime);
1.1 hannken 531: timersub(&endtime, &starttime, &endtime);
532: printf("%s: suspended %ld.%03ld sec, redo %ld of %d\n",
533: vp->v_mount->mnt_stat.f_mntonname, (long)endtime.tv_sec,
534: endtime.tv_usec / 1000, redo, fs->fs_ncg);
535: }
536: #endif
537: if (error)
538: goto out;
539: /*
540: * Copy allocation information from all the snapshots in
541: * this snapshot and then expunge them from its view.
542: */
543: TAILQ_FOREACH(xp, &ump->um_snapshots, i_nextsnap) {
544: if (xp == ip)
545: break;
546: if (xp->i_ump->um_fstype == UFS1)
547: error = expunge_ufs1(vp, xp, fs, snapacct_ufs1,
548: BLK_SNAP);
549: else
550: error = expunge_ufs2(vp, xp, fs, snapacct_ufs2,
551: BLK_SNAP);
552: if (error) {
553: fs->fs_snapinum[snaploc] = 0;
554: goto done;
555: }
556: }
557: /*
558: * Allocate space for the full list of preallocated snapshot blocks.
559: */
1.25 christos 560: snapblklist = malloc(snaplistsize * sizeof(ufs2_daddr_t),
1.1 hannken 561: M_UFSMNT, M_WAITOK);
562: ip->i_snapblklist = &snapblklist[1];
563: /*
564: * Expunge the blocks used by the snapshots from the set of
565: * blocks marked as used in the snapshot bitmaps. Also, collect
566: * the list of allocated blocks in i_snapblklist.
567: */
568: if (ip->i_ump->um_fstype == UFS1)
569: error = expunge_ufs1(vp, ip, copy_fs, mapacct_ufs1, BLK_SNAP);
570: else
571: error = expunge_ufs2(vp, ip, copy_fs, mapacct_ufs2, BLK_SNAP);
572: if (error) {
573: fs->fs_snapinum[snaploc] = 0;
574: FREE(snapblklist, M_UFSMNT);
575: goto done;
576: }
577: if (snaplistsize < ip->i_snapblklist - snapblklist)
578: panic("ffs_snapshot: list too small");
579: snaplistsize = ip->i_snapblklist - snapblklist;
1.15 hannken 580: snapblklist[0] = snaplistsize;
581: ip->i_snapblklist = &snapblklist[0];
1.1 hannken 582: /*
583: * Write out the list of allocated blocks to the end of the snapshot.
584: */
1.15 hannken 585: for (i = 0; i < snaplistsize; i++)
586: snapblklist[i] = ufs_rw64(snapblklist[i], ns);
1.43 christos 587: error = vn_rdwr(UIO_WRITE, vp, (void *)snapblklist,
1.16 hannken 588: snaplistsize*sizeof(ufs2_daddr_t), lblktosize(fs, (off_t)numblks),
1.31 ad 589: UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, l->l_cred, NULL, NULL);
1.15 hannken 590: for (i = 0; i < snaplistsize; i++)
591: snapblklist[i] = ufs_rw64(snapblklist[i], ns);
1.1 hannken 592: if (error) {
593: fs->fs_snapinum[snaploc] = 0;
594: FREE(snapblklist, M_UFSMNT);
595: goto done;
596: }
597: /*
598: * Write the superblock and its summary information
599: * to the snapshot.
600: */
601: blkno = fragstoblks(fs, fs->fs_csaddr);
602: len = howmany(fs->fs_cssize, fs->fs_bsize);
603: space = copy_fs->fs_csp;
1.8 hannken 604: #ifdef FFS_EI
1.1 hannken 605: if (ns) {
606: ffs_sb_swap(copy_fs, copy_fs);
607: ffs_csum_swap(space, space, fs->fs_cssize);
608: }
1.8 hannken 609: #endif
1.1 hannken 610: for (loc = 0; loc < len; loc++) {
1.15 hannken 611: error = bread(vp, blkno + loc, fs->fs_bsize, KERNCRED, &nbp);
612: if (error) {
613: brelse(nbp);
1.1 hannken 614: fs->fs_snapinum[snaploc] = 0;
615: FREE(snapblklist, M_UFSMNT);
616: goto done;
617: }
1.15 hannken 618: bcopy(space, nbp->b_data, fs->fs_bsize);
1.1 hannken 619: space = (char *)space + fs->fs_bsize;
1.15 hannken 620: bawrite(nbp);
1.1 hannken 621: }
622: /*
623: * As this is the newest list, it is the most inclusive, so
1.15 hannken 624: * should replace the previous list. If this is the first snapshot
625: * free the preliminary list.
1.1 hannken 626: */
627: VI_LOCK(devvp);
628: space = ump->um_snapblklist;
629: ump->um_snapblklist = snapblklist;
630: VI_UNLOCK(devvp);
1.15 hannken 631: if (TAILQ_FIRST(&ump->um_snapshots) == ip)
1.1 hannken 632: FREE(space, M_UFSMNT);
633: done:
634: free(copy_fs->fs_csp, M_UFSMNT);
1.15 hannken 635: if (!error) {
636: error = bread(vp, lblkno(fs, fs->fs_sblockloc), fs->fs_bsize,
637: KERNCRED, &nbp);
638: if (error) {
639: brelse(nbp);
640: fs->fs_snapinum[snaploc] = 0;
641: }
1.16 hannken 642: bcopy(sbbuf, nbp->b_data, fs->fs_bsize);
1.15 hannken 643: bawrite(nbp);
644: }
1.1 hannken 645: out:
1.4 hannken 646: /*
1.15 hannken 647: * Invalidate and free all pages on the snapshot vnode.
648: * All metadata has been written through the buffer cache.
649: * Clean all dirty buffers now to avoid UBC inconsistencies.
1.4 hannken 650: */
651: if (!error) {
1.43.2.1 ad 652: mutex_enter(&vp->v_interlock);
1.4 hannken 653: error = VOP_PUTPAGES(vp, 0, 0,
654: PGO_ALLPAGES|PGO_CLEANIT|PGO_SYNCIO|PGO_FREE);
655: }
1.15 hannken 656: if (!error) {
657: s = splbio();
658: for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
659: nbp = LIST_NEXT(bp, b_vnbufs);
1.43.2.1 ad 660: mutex_enter(&bp->b_interlock);
1.15 hannken 661: splx(s);
662: if ((bp->b_flags & (B_DELWRI|B_BUSY)) != B_DELWRI)
663: panic("ffs_snapshot: not dirty or busy, bp %p",
664: bp);
665: bp->b_flags |= B_BUSY|B_VFLUSH;
666: if (LIST_FIRST(&bp->b_dep) == NULL)
667: bp->b_flags |= B_NOCACHE;
1.43.2.1 ad 668: mutex_exit(&bp->b_interlock);
1.15 hannken 669: bwrite(bp);
670: s = splbio();
671: }
1.43.2.1 ad 672: mutex_enter(&global_v_numoutput_lock);
1.43.2.2! ad 673: while (vp->v_numoutput)
! 674: cv_wait(&vp->v_outputcv, &global_v_numoutput_lock);
1.43.2.1 ad 675: mutex_exit(&global_v_numoutput_lock);
1.15 hannken 676: splx(s);
677: }
1.16 hannken 678: if (sbbuf)
679: free(sbbuf, M_UFSMNT);
1.1 hannken 680: if (fs->fs_active != 0) {
681: FREE(fs->fs_active, M_DEVBUF);
682: fs->fs_active = 0;
683: }
684: mp->mnt_flag = flag;
685: if (error)
1.23 christos 686: (void) ffs_truncate(vp, (off_t)0, 0, NOCRED, l);
1.1 hannken 687: else
688: vref(vp);
689: return (error);
690: }
691:
692: /*
693: * Copy a cylinder group map. All the unallocated blocks are marked
694: * BLK_NOCOPY so that the snapshot knows that it need not copy them
695: * if they are later written. If passno is one, then this is a first
696: * pass, so only setting needs to be done. If passno is 2, then this
697: * is a revision to a previous pass which must be undone as the
698: * replacement pass is done.
699: */
700: static int
1.43 christos 701: cgaccount(int cg, struct vnode *vp, void *data, int passno)
1.1 hannken 702: {
703: struct buf *bp, *ibp;
704: struct inode *ip;
705: struct cg *cgp;
706: struct fs *fs;
707: ufs2_daddr_t base, numblks;
708: int error, len, loc, ns, indiroff;
709:
710: ip = VTOI(vp);
711: fs = ip->i_fs;
712: ns = UFS_FSNEEDSWAP(fs);
713: error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
714: (int)fs->fs_cgsize, KERNCRED, &bp);
715: if (error) {
716: brelse(bp);
717: return (error);
718: }
719: cgp = (struct cg *)bp->b_data;
720: if (!cg_chkmagic(cgp, ns)) {
721: brelse(bp);
722: return (EIO);
723: }
724: ACTIVECG_SET(fs, cg);
725:
726: bcopy(bp->b_data, data, fs->fs_cgsize);
727: brelse(bp);
728: if (fs->fs_cgsize < fs->fs_bsize)
1.43 christos 729: memset((char *)data + fs->fs_cgsize, 0,
1.1 hannken 730: fs->fs_bsize - fs->fs_cgsize);
731: numblks = howmany(fs->fs_size, fs->fs_frag);
732: len = howmany(fs->fs_fpg, fs->fs_frag);
733: base = cg * fs->fs_fpg / fs->fs_frag;
734: if (base + len >= numblks)
735: len = numblks - base - 1;
736: loc = 0;
737: if (base < NDADDR) {
738: for ( ; loc < NDADDR; loc++) {
739: if (ffs_isblock(fs, cg_blksfree(cgp, ns), loc))
740: db_assign(ip, loc, BLK_NOCOPY);
741: else if (db_get(ip, loc) == BLK_NOCOPY) {
742: if (passno == 2)
743: db_assign(ip, loc, 0);
744: else if (passno == 1)
745: panic("ffs_snapshot: lost direct block");
746: }
747: }
748: }
1.22 yamt 749: if ((error = ffs_balloc(vp, lblktosize(fs, (off_t)(base + loc)),
1.11 perry 750: fs->fs_bsize, KERNCRED, B_METAONLY, &ibp)) != 0)
1.1 hannken 751: return (error);
752: indiroff = (base + loc - NDADDR) % NINDIR(fs);
753: for ( ; loc < len; loc++, indiroff++) {
754: if (indiroff >= NINDIR(fs)) {
1.15 hannken 755: bawrite(ibp);
1.22 yamt 756: if ((error = ffs_balloc(vp,
1.1 hannken 757: lblktosize(fs, (off_t)(base + loc)),
758: fs->fs_bsize, KERNCRED, B_METAONLY, &ibp)) != 0)
759: return (error);
760: indiroff = 0;
761: }
762: if (ffs_isblock(fs, cg_blksfree(cgp, ns), loc))
763: idb_assign(ip, ibp->b_data, indiroff, BLK_NOCOPY);
764: else if (idb_get(ip, ibp->b_data, indiroff) == BLK_NOCOPY) {
765: if (passno == 2)
766: idb_assign(ip, ibp->b_data, indiroff, 0);
767: else if (passno == 1)
768: panic("ffs_snapshot: lost indirect block");
769: }
770: }
1.15 hannken 771: bdwrite(ibp);
1.1 hannken 772: return (0);
773: }
774:
775: /*
776: * Before expunging a snapshot inode, note all the
777: * blocks that it claims with BLK_SNAP so that fsck will
778: * be able to account for those blocks properly and so
779: * that this snapshot knows that it need not copy them
780: * if the other snapshot holding them is freed. This code
781: * is reproduced once each for UFS1 and UFS2.
782: */
783: static int
1.18 thorpej 784: expunge_ufs1(struct vnode *snapvp, struct inode *cancelip, struct fs *fs,
785: int (*acctfunc)(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *,
786: struct fs *, ufs_lbn_t, int),
787: int expungetype)
1.1 hannken 788: {
1.4 hannken 789: int i, s, error, ns, indiroff;
1.1 hannken 790: ufs_lbn_t lbn, rlbn;
791: ufs2_daddr_t len, blkno, numblks, blksperindir;
792: struct ufs1_dinode *dip;
793: struct buf *bp;
1.43 christos 794: void *bf;
1.1 hannken 795:
796: ns = UFS_FSNEEDSWAP(fs);
797: /*
798: * Prepare to expunge the inode. If its inode block has not
799: * yet been copied, then allocate and fill the copy.
800: */
801: lbn = fragstoblks(fs, ino_to_fsba(fs, cancelip->i_number));
802: blkno = 0;
803: if (lbn < NDADDR) {
804: blkno = db_get(VTOI(snapvp), lbn);
805: } else {
1.4 hannken 806: s = cow_enter();
1.22 yamt 807: error = ffs_balloc(snapvp, lblktosize(fs, (off_t)lbn),
1.1 hannken 808: fs->fs_bsize, KERNCRED, B_METAONLY, &bp);
1.4 hannken 809: cow_leave(s);
1.1 hannken 810: if (error)
811: return (error);
812: indiroff = (lbn - NDADDR) % NINDIR(fs);
813: blkno = idb_get(VTOI(snapvp), bp->b_data, indiroff);
814: brelse(bp);
815: }
1.17 christos 816: bf = malloc(fs->fs_bsize, M_UFSMNT, M_WAITOK);
1.1 hannken 817: if (blkno != 0)
1.17 christos 818: error = readvnblk(snapvp, bf, lbn);
1.1 hannken 819: else
1.17 christos 820: error = readfsblk(snapvp, bf, lbn);
1.1 hannken 821: if (error) {
1.17 christos 822: free(bf, M_UFSMNT);
1.1 hannken 823: return error;
824: }
825: /*
826: * Set a snapshot inode to be a zero length file, regular files
827: * to be completely unallocated.
828: */
1.17 christos 829: dip = (struct ufs1_dinode *)bf + ino_to_fsbo(fs, cancelip->i_number);
1.1 hannken 830: if (expungetype == BLK_NOCOPY)
831: dip->di_mode = 0;
832: dip->di_size = 0;
833: dip->di_blocks = 0;
834: dip->di_flags =
835: ufs_rw32(ufs_rw32(dip->di_flags, ns) & ~SF_SNAPSHOT, ns);
836: bzero(&dip->di_db[0], (NDADDR + NIADDR) * sizeof(ufs1_daddr_t));
1.17 christos 837: error = writevnblk(snapvp, bf, lbn);
838: free(bf, M_UFSMNT);
1.1 hannken 839: if (error)
840: return error;
841: /*
842: * Now go through and expunge all the blocks in the file
843: * using the function requested.
844: */
845: numblks = howmany(cancelip->i_size, fs->fs_bsize);
846: if ((error = (*acctfunc)(snapvp, &cancelip->i_ffs1_db[0],
847: &cancelip->i_ffs1_db[NDADDR], fs, 0, expungetype)))
848: return (error);
849: if ((error = (*acctfunc)(snapvp, &cancelip->i_ffs1_ib[0],
850: &cancelip->i_ffs1_ib[NIADDR], fs, -1, expungetype)))
851: return (error);
852: blksperindir = 1;
853: lbn = -NDADDR;
854: len = numblks - NDADDR;
855: rlbn = NDADDR;
856: for (i = 0; len > 0 && i < NIADDR; i++) {
857: error = indiracct_ufs1(snapvp, ITOV(cancelip), i,
858: ufs_rw32(cancelip->i_ffs1_ib[i], ns), lbn, rlbn, len,
859: blksperindir, fs, acctfunc, expungetype);
860: if (error)
861: return (error);
862: blksperindir *= NINDIR(fs);
863: lbn -= blksperindir + 1;
864: len -= blksperindir;
865: rlbn += blksperindir;
866: }
867: return (0);
868: }
869:
870: /*
871: * Descend an indirect block chain for vnode cancelvp accounting for all
872: * its indirect blocks in snapvp.
1.11 perry 873: */
1.1 hannken 874: static int
1.18 thorpej 875: indiracct_ufs1(struct vnode *snapvp, struct vnode *cancelvp, int level,
876: ufs1_daddr_t blkno, ufs_lbn_t lbn, ufs_lbn_t rlbn, ufs_lbn_t remblks,
877: ufs_lbn_t blksperindir, struct fs *fs,
878: int (*acctfunc)(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *,
879: struct fs *, ufs_lbn_t, int),
880: int expungetype)
1.1 hannken 881: {
882: int error, ns, num, i;
883: ufs_lbn_t subblksperindir;
884: struct indir indirs[NIADDR + 2];
885: ufs1_daddr_t last, *bap;
886: struct buf *bp;
887:
888: ns = UFS_FSNEEDSWAP(fs);
889:
890: if (blkno == 0) {
891: if (expungetype == BLK_NOCOPY)
892: return (0);
893: panic("indiracct_ufs1: missing indir");
894: }
895: if ((error = ufs_getlbns(cancelvp, rlbn, indirs, &num)) != 0)
896: return (error);
897: if (lbn != indirs[num - 1 - level].in_lbn || num < 2)
898: panic("indiracct_ufs1: botched params");
899: /*
900: * We have to expand bread here since it will deadlock looking
901: * up the block number for any blocks that are not in the cache.
902: */
903: bp = getblk(cancelvp, lbn, fs->fs_bsize, 0, 0);
904: bp->b_blkno = fsbtodb(fs, blkno);
905: if ((bp->b_flags & (B_DONE | B_DELWRI)) == 0 &&
906: (error = readfsblk(bp->b_vp, bp->b_data, fragstoblks(fs, blkno)))) {
907: brelse(bp);
908: return (error);
909: }
910: /*
911: * Account for the block pointers in this indirect block.
912: */
913: last = howmany(remblks, blksperindir);
914: if (last > NINDIR(fs))
915: last = NINDIR(fs);
1.25 christos 916: bap = malloc(fs->fs_bsize, M_DEVBUF, M_WAITOK);
1.43 christos 917: bcopy(bp->b_data, (void *)bap, fs->fs_bsize);
1.1 hannken 918: brelse(bp);
919: error = (*acctfunc)(snapvp, &bap[0], &bap[last], fs,
920: level == 0 ? rlbn : -1, expungetype);
921: if (error || level == 0)
922: goto out;
923: /*
924: * Account for the block pointers in each of the indirect blocks
925: * in the levels below us.
926: */
927: subblksperindir = blksperindir / NINDIR(fs);
928: for (lbn++, level--, i = 0; i < last; i++) {
929: error = indiracct_ufs1(snapvp, cancelvp, level,
930: ufs_rw32(bap[i], ns), lbn, rlbn, remblks, subblksperindir,
931: fs, acctfunc, expungetype);
932: if (error)
933: goto out;
934: rlbn += blksperindir;
935: lbn -= blksperindir;
936: remblks -= blksperindir;
937: }
938: out:
939: FREE(bap, M_DEVBUF);
940: return (error);
941: }
942:
943: /*
944: * Do both snap accounting and map accounting.
945: */
946: static int
1.18 thorpej 947: fullacct_ufs1(struct vnode *vp, ufs1_daddr_t *oldblkp, ufs1_daddr_t *lastblkp,
948: struct fs *fs, ufs_lbn_t lblkno,
949: int exptype /* BLK_SNAP or BLK_NOCOPY */)
1.1 hannken 950: {
951: int error;
952:
953: if ((error = snapacct_ufs1(vp, oldblkp, lastblkp, fs, lblkno, exptype)))
954: return (error);
955: return (mapacct_ufs1(vp, oldblkp, lastblkp, fs, lblkno, exptype));
956: }
957:
958: /*
959: * Identify a set of blocks allocated in a snapshot inode.
960: */
961: static int
1.18 thorpej 962: snapacct_ufs1(struct vnode *vp, ufs1_daddr_t *oldblkp, ufs1_daddr_t *lastblkp,
1.36 christos 963: struct fs *fs, ufs_lbn_t lblkno,
1.18 thorpej 964: int expungetype /* BLK_SNAP or BLK_NOCOPY */)
1.1 hannken 965: {
966: struct inode *ip = VTOI(vp);
967: ufs1_daddr_t blkno, *blkp;
968: ufs_lbn_t lbn;
969: struct buf *ibp;
970: int error, ns;
971:
972: ns = UFS_FSNEEDSWAP(fs);
973:
974: for ( ; oldblkp < lastblkp; oldblkp++) {
975: blkno = ufs_rw32(*oldblkp, ns);
976: if (blkno == 0 || blkno == BLK_NOCOPY || blkno == BLK_SNAP)
977: continue;
978: lbn = fragstoblks(fs, blkno);
979: if (lbn < NDADDR) {
980: blkp = &ip->i_ffs1_db[lbn];
981: ip->i_flag |= IN_CHANGE | IN_UPDATE;
982: } else {
1.22 yamt 983: error = ffs_balloc(vp, lblktosize(fs, (off_t)lbn),
1.1 hannken 984: fs->fs_bsize, KERNCRED, B_METAONLY, &ibp);
985: if (error)
986: return (error);
987: blkp = &((ufs1_daddr_t *)(ibp->b_data))
988: [(lbn - NDADDR) % NINDIR(fs)];
989: }
990: /*
991: * If we are expunging a snapshot vnode and we
992: * find a block marked BLK_NOCOPY, then it is
993: * one that has been allocated to this snapshot after
994: * we took our current snapshot and can be ignored.
995: */
996: blkno = ufs_rw32(*blkp, ns);
997: if (expungetype == BLK_SNAP && blkno == BLK_NOCOPY) {
998: if (lbn >= NDADDR)
999: brelse(ibp);
1000: } else {
1001: if (blkno != 0)
1002: panic("snapacct_ufs1: bad block");
1003: *blkp = ufs_rw32(expungetype, ns);
1004: if (lbn >= NDADDR)
1.15 hannken 1005: bdwrite(ibp);
1.1 hannken 1006: }
1007: }
1008: return (0);
1009: }
1010:
1011: /*
1012: * Account for a set of blocks allocated in a snapshot inode.
1013: */
1014: static int
1.18 thorpej 1015: mapacct_ufs1(struct vnode *vp, ufs1_daddr_t *oldblkp, ufs1_daddr_t *lastblkp,
1016: struct fs *fs, ufs_lbn_t lblkno, int expungetype)
1.1 hannken 1017: {
1018: ufs1_daddr_t blkno;
1019: struct inode *ip;
1020: ino_t inum;
1021: int acctit, ns;
1022:
1023: ns = UFS_FSNEEDSWAP(fs);
1024: ip = VTOI(vp);
1025: inum = ip->i_number;
1026: if (lblkno == -1)
1027: acctit = 0;
1028: else
1029: acctit = 1;
1030: for ( ; oldblkp < lastblkp; oldblkp++, lblkno++) {
1031: blkno = ufs_rw32(*oldblkp, ns);
1032: if (blkno == 0 || blkno == BLK_NOCOPY)
1033: continue;
1034: if (acctit && expungetype == BLK_SNAP && blkno != BLK_SNAP)
1.15 hannken 1035: *ip->i_snapblklist++ = lblkno;
1.1 hannken 1036: if (blkno == BLK_SNAP)
1037: blkno = blkstofrags(fs, lblkno);
1038: ffs_blkfree(fs, vp, blkno, fs->fs_bsize, inum);
1039: }
1040: return (0);
1041: }
1042:
1043: /*
1044: * Before expunging a snapshot inode, note all the
1045: * blocks that it claims with BLK_SNAP so that fsck will
1046: * be able to account for those blocks properly and so
1047: * that this snapshot knows that it need not copy them
1048: * if the other snapshot holding them is freed. This code
1049: * is reproduced once each for UFS1 and UFS2.
1050: */
1051: static int
1.18 thorpej 1052: expunge_ufs2(struct vnode *snapvp, struct inode *cancelip, struct fs *fs,
1053: int (*acctfunc)(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *,
1054: struct fs *, ufs_lbn_t, int),
1055: int expungetype)
1.1 hannken 1056: {
1.4 hannken 1057: int i, s, error, ns, indiroff;
1.1 hannken 1058: ufs_lbn_t lbn, rlbn;
1059: ufs2_daddr_t len, blkno, numblks, blksperindir;
1060: struct ufs2_dinode *dip;
1061: struct buf *bp;
1.43 christos 1062: void *bf;
1.1 hannken 1063:
1064: ns = UFS_FSNEEDSWAP(fs);
1065: /*
1066: * Prepare to expunge the inode. If its inode block has not
1067: * yet been copied, then allocate and fill the copy.
1068: */
1069: lbn = fragstoblks(fs, ino_to_fsba(fs, cancelip->i_number));
1070: blkno = 0;
1071: if (lbn < NDADDR) {
1072: blkno = db_get(VTOI(snapvp), lbn);
1073: } else {
1.4 hannken 1074: s = cow_enter();
1.22 yamt 1075: error = ffs_balloc(snapvp, lblktosize(fs, (off_t)lbn),
1.1 hannken 1076: fs->fs_bsize, KERNCRED, B_METAONLY, &bp);
1.4 hannken 1077: cow_leave(s);
1.1 hannken 1078: if (error)
1079: return (error);
1080: indiroff = (lbn - NDADDR) % NINDIR(fs);
1081: blkno = idb_get(VTOI(snapvp), bp->b_data, indiroff);
1082: brelse(bp);
1083: }
1.17 christos 1084: bf = malloc(fs->fs_bsize, M_UFSMNT, M_WAITOK);
1.1 hannken 1085: if (blkno != 0)
1.17 christos 1086: error = readvnblk(snapvp, bf, lbn);
1.1 hannken 1087: else
1.17 christos 1088: error = readfsblk(snapvp, bf, lbn);
1.1 hannken 1089: if (error) {
1.17 christos 1090: free(bf, M_UFSMNT);
1.1 hannken 1091: return error;
1092: }
1093: /*
1094: * Set a snapshot inode to be a zero length file, regular files
1095: * to be completely unallocated.
1096: */
1.17 christos 1097: dip = (struct ufs2_dinode *)bf + ino_to_fsbo(fs, cancelip->i_number);
1.1 hannken 1098: if (expungetype == BLK_NOCOPY)
1099: dip->di_mode = 0;
1100: dip->di_size = 0;
1101: dip->di_blocks = 0;
1102: dip->di_flags =
1103: ufs_rw32(ufs_rw32(dip->di_flags, ns) & ~SF_SNAPSHOT, ns);
1104: bzero(&dip->di_db[0], (NDADDR + NIADDR) * sizeof(ufs2_daddr_t));
1.17 christos 1105: error = writevnblk(snapvp, bf, lbn);
1106: free(bf, M_UFSMNT);
1.1 hannken 1107: if (error)
1108: return error;
1109: /*
1110: * Now go through and expunge all the blocks in the file
1111: * using the function requested.
1112: */
1113: numblks = howmany(cancelip->i_size, fs->fs_bsize);
1114: if ((error = (*acctfunc)(snapvp, &cancelip->i_ffs2_db[0],
1115: &cancelip->i_ffs2_db[NDADDR], fs, 0, expungetype)))
1116: return (error);
1117: if ((error = (*acctfunc)(snapvp, &cancelip->i_ffs2_ib[0],
1118: &cancelip->i_ffs2_ib[NIADDR], fs, -1, expungetype)))
1119: return (error);
1120: blksperindir = 1;
1121: lbn = -NDADDR;
1122: len = numblks - NDADDR;
1123: rlbn = NDADDR;
1124: for (i = 0; len > 0 && i < NIADDR; i++) {
1125: error = indiracct_ufs2(snapvp, ITOV(cancelip), i,
1126: ufs_rw64(cancelip->i_ffs2_ib[i], ns), lbn, rlbn, len,
1127: blksperindir, fs, acctfunc, expungetype);
1128: if (error)
1129: return (error);
1130: blksperindir *= NINDIR(fs);
1131: lbn -= blksperindir + 1;
1132: len -= blksperindir;
1133: rlbn += blksperindir;
1134: }
1135: return (0);
1136: }
1137:
1138: /*
1139: * Descend an indirect block chain for vnode cancelvp accounting for all
1140: * its indirect blocks in snapvp.
1.11 perry 1141: */
1.1 hannken 1142: static int
1.18 thorpej 1143: indiracct_ufs2(struct vnode *snapvp, struct vnode *cancelvp, int level,
1144: ufs2_daddr_t blkno, ufs_lbn_t lbn, ufs_lbn_t rlbn, ufs_lbn_t remblks,
1145: ufs_lbn_t blksperindir, struct fs *fs,
1146: int (*acctfunc)(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *,
1147: struct fs *, ufs_lbn_t, int),
1148: int expungetype)
1.1 hannken 1149: {
1150: int error, ns, num, i;
1151: ufs_lbn_t subblksperindir;
1152: struct indir indirs[NIADDR + 2];
1153: ufs2_daddr_t last, *bap;
1154: struct buf *bp;
1155:
1156: ns = UFS_FSNEEDSWAP(fs);
1157:
1158: if (blkno == 0) {
1159: if (expungetype == BLK_NOCOPY)
1160: return (0);
1161: panic("indiracct_ufs2: missing indir");
1162: }
1163: if ((error = ufs_getlbns(cancelvp, rlbn, indirs, &num)) != 0)
1164: return (error);
1165: if (lbn != indirs[num - 1 - level].in_lbn || num < 2)
1166: panic("indiracct_ufs2: botched params");
1167: /*
1168: * We have to expand bread here since it will deadlock looking
1169: * up the block number for any blocks that are not in the cache.
1170: */
1171: bp = getblk(cancelvp, lbn, fs->fs_bsize, 0, 0);
1172: bp->b_blkno = fsbtodb(fs, blkno);
1173: if ((bp->b_flags & (B_DONE | B_DELWRI)) == 0 &&
1174: (error = readfsblk(bp->b_vp, bp->b_data, fragstoblks(fs, blkno)))) {
1175: brelse(bp);
1176: return (error);
1177: }
1178: /*
1179: * Account for the block pointers in this indirect block.
1180: */
1181: last = howmany(remblks, blksperindir);
1182: if (last > NINDIR(fs))
1183: last = NINDIR(fs);
1.25 christos 1184: bap = malloc(fs->fs_bsize, M_DEVBUF, M_WAITOK);
1.43 christos 1185: bcopy(bp->b_data, (void *)bap, fs->fs_bsize);
1.1 hannken 1186: brelse(bp);
1187: error = (*acctfunc)(snapvp, &bap[0], &bap[last], fs,
1188: level == 0 ? rlbn : -1, expungetype);
1189: if (error || level == 0)
1190: goto out;
1191: /*
1192: * Account for the block pointers in each of the indirect blocks
1193: * in the levels below us.
1194: */
1195: subblksperindir = blksperindir / NINDIR(fs);
1196: for (lbn++, level--, i = 0; i < last; i++) {
1197: error = indiracct_ufs2(snapvp, cancelvp, level,
1198: ufs_rw64(bap[i], ns), lbn, rlbn, remblks, subblksperindir,
1199: fs, acctfunc, expungetype);
1200: if (error)
1201: goto out;
1202: rlbn += blksperindir;
1203: lbn -= blksperindir;
1204: remblks -= blksperindir;
1205: }
1206: out:
1207: FREE(bap, M_DEVBUF);
1208: return (error);
1209: }
1210:
1211: /*
1212: * Do both snap accounting and map accounting.
1213: */
1214: static int
1.18 thorpej 1215: fullacct_ufs2(struct vnode *vp, ufs2_daddr_t *oldblkp, ufs2_daddr_t *lastblkp,
1216: struct fs *fs, ufs_lbn_t lblkno,
1217: int exptype /* BLK_SNAP or BLK_NOCOPY */)
1.1 hannken 1218: {
1219: int error;
1220:
1221: if ((error = snapacct_ufs2(vp, oldblkp, lastblkp, fs, lblkno, exptype)))
1222: return (error);
1223: return (mapacct_ufs2(vp, oldblkp, lastblkp, fs, lblkno, exptype));
1224: }
1225:
1226: /*
1227: * Identify a set of blocks allocated in a snapshot inode.
1228: */
1229: static int
1.18 thorpej 1230: snapacct_ufs2(struct vnode *vp, ufs2_daddr_t *oldblkp, ufs2_daddr_t *lastblkp,
1.36 christos 1231: struct fs *fs, ufs_lbn_t lblkno,
1.18 thorpej 1232: int expungetype /* BLK_SNAP or BLK_NOCOPY */)
1.1 hannken 1233: {
1234: struct inode *ip = VTOI(vp);
1235: ufs2_daddr_t blkno, *blkp;
1236: ufs_lbn_t lbn;
1237: struct buf *ibp;
1238: int error, ns;
1239:
1240: ns = UFS_FSNEEDSWAP(fs);
1241:
1242: for ( ; oldblkp < lastblkp; oldblkp++) {
1243: blkno = ufs_rw64(*oldblkp, ns);
1244: if (blkno == 0 || blkno == BLK_NOCOPY || blkno == BLK_SNAP)
1245: continue;
1246: lbn = fragstoblks(fs, blkno);
1247: if (lbn < NDADDR) {
1248: blkp = &ip->i_ffs2_db[lbn];
1249: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1250: } else {
1.22 yamt 1251: error = ffs_balloc(vp, lblktosize(fs, (off_t)lbn),
1.1 hannken 1252: fs->fs_bsize, KERNCRED, B_METAONLY, &ibp);
1253: if (error)
1254: return (error);
1255: blkp = &((ufs2_daddr_t *)(ibp->b_data))
1256: [(lbn - NDADDR) % NINDIR(fs)];
1257: }
1258: /*
1259: * If we are expunging a snapshot vnode and we
1260: * find a block marked BLK_NOCOPY, then it is
1261: * one that has been allocated to this snapshot after
1262: * we took our current snapshot and can be ignored.
1263: */
1264: blkno = ufs_rw64(*blkp, ns);
1265: if (expungetype == BLK_SNAP && blkno == BLK_NOCOPY) {
1266: if (lbn >= NDADDR)
1267: brelse(ibp);
1268: } else {
1269: if (blkno != 0)
1270: panic("snapacct_ufs2: bad block");
1271: *blkp = ufs_rw64(expungetype, ns);
1272: if (lbn >= NDADDR)
1.15 hannken 1273: bdwrite(ibp);
1.1 hannken 1274: }
1275: }
1276: return (0);
1277: }
1278:
1279: /*
1280: * Account for a set of blocks allocated in a snapshot inode.
1281: */
1282: static int
1.18 thorpej 1283: mapacct_ufs2(struct vnode *vp, ufs2_daddr_t *oldblkp, ufs2_daddr_t *lastblkp,
1284: struct fs *fs, ufs_lbn_t lblkno, int expungetype)
1.1 hannken 1285: {
1286: ufs2_daddr_t blkno;
1287: struct inode *ip;
1288: ino_t inum;
1289: int acctit, ns;
1290:
1291: ns = UFS_FSNEEDSWAP(fs);
1292: ip = VTOI(vp);
1293: inum = ip->i_number;
1294: if (lblkno == -1)
1295: acctit = 0;
1296: else
1297: acctit = 1;
1298: for ( ; oldblkp < lastblkp; oldblkp++, lblkno++) {
1299: blkno = ufs_rw64(*oldblkp, ns);
1300: if (blkno == 0 || blkno == BLK_NOCOPY)
1301: continue;
1302: if (acctit && expungetype == BLK_SNAP && blkno != BLK_SNAP)
1.15 hannken 1303: *ip->i_snapblklist++ = lblkno;
1.1 hannken 1304: if (blkno == BLK_SNAP)
1305: blkno = blkstofrags(fs, lblkno);
1306: ffs_blkfree(fs, vp, blkno, fs->fs_bsize, inum);
1307: }
1308: return (0);
1309: }
1.10 hannken 1310: #endif /* defined(FFS_NO_SNAPSHOT) */
1.1 hannken 1311:
1312: /*
1313: * Decrement extra reference on snapshot when last name is removed.
1314: * It will not be freed until the last open reference goes away.
1315: */
1316: void
1.18 thorpej 1317: ffs_snapgone(struct inode *ip)
1.1 hannken 1318: {
1319: struct ufsmount *ump = VFSTOUFS(ip->i_devvp->v_specmountpoint);
1320: struct inode *xp;
1321: struct fs *fs;
1322: int snaploc;
1323:
1324: /*
1325: * Find snapshot in incore list.
1326: */
1327: TAILQ_FOREACH(xp, &ump->um_snapshots, i_nextsnap)
1328: if (xp == ip)
1329: break;
1330: if (xp != NULL)
1331: vrele(ITOV(ip));
1332: #ifdef DEBUG
1333: else if (snapdebug)
1.19 christos 1334: printf("ffs_snapgone: lost snapshot vnode %llu\n",
1335: (unsigned long long)ip->i_number);
1.1 hannken 1336: #endif
1337: /*
1338: * Delete snapshot inode from superblock. Keep list dense.
1339: */
1340: fs = ip->i_fs;
1341: for (snaploc = 0; snaploc < FSMAXSNAP; snaploc++)
1342: if (fs->fs_snapinum[snaploc] == ip->i_number)
1343: break;
1344: if (snaploc < FSMAXSNAP) {
1345: for (snaploc++; snaploc < FSMAXSNAP; snaploc++) {
1346: if (fs->fs_snapinum[snaploc] == 0)
1347: break;
1348: fs->fs_snapinum[snaploc - 1] = fs->fs_snapinum[snaploc];
1349: }
1350: fs->fs_snapinum[snaploc - 1] = 0;
1351: }
1352: }
1353:
1354: /*
1355: * Prepare a snapshot file for being removed.
1356: */
1357: void
1.18 thorpej 1358: ffs_snapremove(struct vnode *vp)
1.1 hannken 1359: {
1.15 hannken 1360: struct inode *ip = VTOI(vp), *xp;
1.1 hannken 1361: struct vnode *devvp = ip->i_devvp;
1362: struct fs *fs = ip->i_fs;
1363: struct ufsmount *ump = VFSTOUFS(devvp->v_specmountpoint);
1364: struct lock *lkp;
1365: struct buf *ibp;
1.15 hannken 1366: ufs2_daddr_t numblks, blkno, dblk;
1.1 hannken 1367: int error, ns, loc, last;
1368:
1369: ns = UFS_FSNEEDSWAP(fs);
1370: /*
1371: * If active, delete from incore list (this snapshot may
1372: * already have been in the process of being deleted, so
1373: * would not have been active).
1374: *
1375: * Clear copy-on-write flag if last snapshot.
1376: */
1377: if (ip->i_nextsnap.tqe_prev != 0) {
1378: VI_LOCK(devvp);
1379: lockmgr(&vp->v_lock, LK_INTERLOCK | LK_EXCLUSIVE,
1380: VI_MTX(devvp));
1381: VI_LOCK(devvp);
1382: TAILQ_REMOVE(&ump->um_snapshots, ip, i_nextsnap);
1383: ip->i_nextsnap.tqe_prev = 0;
1384: lkp = vp->v_vnlock;
1385: vp->v_vnlock = &vp->v_lock;
1386: lockmgr(lkp, LK_RELEASE, NULL);
1387: if (TAILQ_FIRST(&ump->um_snapshots) != 0) {
1.15 hannken 1388: /* Roll back the list of preallocated blocks. */
1389: xp = TAILQ_LAST(&ump->um_snapshots, inodelst);
1390: ump->um_snapblklist = xp->i_snapblklist;
1.1 hannken 1391: VI_UNLOCK(devvp);
1392: } else {
1393: ump->um_snapblklist = 0;
1394: lockmgr(lkp, LK_DRAIN|LK_INTERLOCK, VI_MTX(devvp));
1395: lockmgr(lkp, LK_RELEASE, NULL);
1396: vn_cow_disestablish(devvp, ffs_copyonwrite, devvp);
1397: FREE(lkp, M_UFSMNT);
1398: }
1.15 hannken 1399: FREE(ip->i_snapblklist, M_UFSMNT);
1400: ip->i_snapblklist = NULL;
1.1 hannken 1401: }
1402: /*
1403: * Clear all BLK_NOCOPY fields. Pass any block claims to other
1404: * snapshots that want them (see ffs_snapblkfree below).
1405: */
1406: for (blkno = 1; blkno < NDADDR; blkno++) {
1407: dblk = db_get(ip, blkno);
1408: if (dblk == BLK_NOCOPY || dblk == BLK_SNAP)
1409: db_assign(ip, blkno, 0);
1410: else if ((dblk == blkstofrags(fs, blkno) &&
1411: ffs_snapblkfree(fs, ip->i_devvp, dblk, fs->fs_bsize,
1412: ip->i_number))) {
1413: DIP_ADD(ip, blocks, -btodb(fs->fs_bsize));
1414: db_assign(ip, blkno, 0);
1415: }
1416: }
1417: numblks = howmany(ip->i_size, fs->fs_bsize);
1418: for (blkno = NDADDR; blkno < numblks; blkno += NINDIR(fs)) {
1.22 yamt 1419: error = ffs_balloc(vp, lblktosize(fs, (off_t)blkno),
1.1 hannken 1420: fs->fs_bsize, KERNCRED, B_METAONLY, &ibp);
1421: if (error)
1422: continue;
1423: if (fs->fs_size - blkno > NINDIR(fs))
1424: last = NINDIR(fs);
1425: else
1426: last = fs->fs_size - blkno;
1427: for (loc = 0; loc < last; loc++) {
1428: dblk = idb_get(ip, ibp->b_data, loc);
1429: if (dblk == BLK_NOCOPY || dblk == BLK_SNAP)
1430: idb_assign(ip, ibp->b_data, loc, 0);
1431: else if (dblk == blkstofrags(fs, blkno) &&
1432: ffs_snapblkfree(fs, ip->i_devvp, dblk,
1433: fs->fs_bsize, ip->i_number)) {
1434: DIP_ADD(ip, blocks, -btodb(fs->fs_bsize));
1435: idb_assign(ip, ibp->b_data, loc, 0);
1436: }
1437: }
1.15 hannken 1438: bawrite(ibp);
1.1 hannken 1439: }
1440: /*
1441: * Clear snapshot flag and drop reference.
1442: */
1443: ip->i_flags &= ~SF_SNAPSHOT;
1444: DIP_ASSIGN(ip, flags, ip->i_flags);
1445: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1446: }
1447:
1448: /*
1449: * Notification that a block is being freed. Return zero if the free
1450: * should be allowed to proceed. Return non-zero if the snapshot file
1451: * wants to claim the block. The block will be claimed if it is an
1452: * uncopied part of one of the snapshots. It will be freed if it is
1453: * either a BLK_NOCOPY or has already been copied in all of the snapshots.
1454: * If a fragment is being freed, then all snapshots that care about
1455: * it must make a copy since a snapshot file can only claim full sized
1456: * blocks. Note that if more than one snapshot file maps the block,
1457: * we can pick one at random to claim it. Since none of the snapshots
1458: * can change, we are assurred that they will all see the same unmodified
1459: * image. When deleting a snapshot file (see ffs_snapremove above), we
1460: * must push any of these claimed blocks to one of the other snapshots
1461: * that maps it. These claimed blocks are easily identified as they will
1462: * have a block number equal to their logical block number within the
1463: * snapshot. A copied block can never have this property because they
1464: * must always have been allocated from a BLK_NOCOPY location.
1465: */
1466: int
1.18 thorpej 1467: ffs_snapblkfree(struct fs *fs, struct vnode *devvp, ufs2_daddr_t bno,
1.36 christos 1468: long size, ino_t inum)
1.1 hannken 1469: {
1470: struct ufsmount *ump = VFSTOUFS(devvp->v_specmountpoint);
1471: struct buf *ibp;
1472: struct inode *ip;
1473: struct vnode *vp = NULL, *saved_vp = NULL;
1.43 christos 1474: void *saved_data = NULL;
1.1 hannken 1475: ufs_lbn_t lbn;
1476: ufs2_daddr_t blkno;
1.4 hannken 1477: int s, indiroff = 0, snapshot_locked = 0, error = 0, claimedblk = 0;
1.1 hannken 1478:
1479: lbn = fragstoblks(fs, bno);
1480: retry:
1481: VI_LOCK(devvp);
1482: TAILQ_FOREACH(ip, &ump->um_snapshots, i_nextsnap) {
1483: vp = ITOV(ip);
1484: /*
1485: * Lookup block being written.
1486: */
1487: if (lbn < NDADDR) {
1488: blkno = db_get(ip, lbn);
1489: } else {
1490: if (snapshot_locked == 0 &&
1491: lockmgr(vp->v_vnlock,
1492: LK_INTERLOCK | LK_EXCLUSIVE | LK_SLEEPFAIL,
1493: VI_MTX(devvp)) != 0)
1494: goto retry;
1495: snapshot_locked = 1;
1.4 hannken 1496: s = cow_enter();
1.22 yamt 1497: error = ffs_balloc(vp, lblktosize(fs, (off_t)lbn),
1.1 hannken 1498: fs->fs_bsize, KERNCRED, B_METAONLY, &ibp);
1.4 hannken 1499: cow_leave(s);
1.1 hannken 1500: if (error)
1501: break;
1502: indiroff = (lbn - NDADDR) % NINDIR(fs);
1503: blkno = idb_get(ip, ibp->b_data, indiroff);
1504: }
1505: /*
1506: * Check to see if block needs to be copied.
1507: */
1508: if (blkno == 0) {
1509: /*
1510: * A block that we map is being freed. If it has not
1511: * been claimed yet, we will claim or copy it (below).
1512: */
1513: claimedblk = 1;
1514: } else if (blkno == BLK_SNAP) {
1515: /*
1516: * No previous snapshot claimed the block,
1517: * so it will be freed and become a BLK_NOCOPY
1518: * (don't care) for us.
1519: */
1520: if (claimedblk)
1521: panic("snapblkfree: inconsistent block type");
1522: if (snapshot_locked == 0 &&
1523: lockmgr(vp->v_vnlock,
1524: LK_INTERLOCK | LK_EXCLUSIVE | LK_NOWAIT,
1525: VI_MTX(devvp)) != 0) {
1.32 christos 1526: #if 0 /* CID-2949: dead code */
1.1 hannken 1527: if (lbn >= NDADDR)
1528: brelse(ibp);
1.32 christos 1529: #endif
1.1 hannken 1530: vn_lock(vp, LK_EXCLUSIVE | LK_SLEEPFAIL);
1531: goto retry;
1532: }
1533: snapshot_locked = 1;
1534: if (lbn < NDADDR) {
1535: db_assign(ip, lbn, BLK_NOCOPY);
1536: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1537: } else {
1538: idb_assign(ip, ibp->b_data, indiroff,
1539: BLK_NOCOPY);
1540: bwrite(ibp);
1541: }
1542: continue;
1543: } else /* BLK_NOCOPY or default */ {
1544: /*
1545: * If the snapshot has already copied the block
1546: * (default), or does not care about the block,
1547: * it is not needed.
1548: */
1.27 bouyer 1549: if (lbn >= NDADDR)
1.1 hannken 1550: brelse(ibp);
1551: continue;
1552: }
1553: /*
1554: * If this is a full size block, we will just grab it
1555: * and assign it to the snapshot inode. Otherwise we
1556: * will proceed to copy it. See explanation for this
1557: * routine as to why only a single snapshot needs to
1558: * claim this block.
1559: */
1560: if (snapshot_locked == 0 &&
1561: lockmgr(vp->v_vnlock,
1562: LK_INTERLOCK | LK_EXCLUSIVE | LK_NOWAIT,
1563: VI_MTX(devvp)) != 0) {
1564: vn_lock(vp, LK_EXCLUSIVE | LK_SLEEPFAIL);
1565: goto retry;
1566: }
1567: snapshot_locked = 1;
1568: if (size == fs->fs_bsize) {
1569: #ifdef DEBUG
1570: if (snapdebug)
1.19 christos 1571: printf("%s %llu lbn %" PRId64
1572: "from inum %llu\n",
1573: "Grabonremove: snapino",
1574: (unsigned long long)ip->i_number,
1575: lbn, (unsigned long long)inum);
1.1 hannken 1576: #endif
1577: if (lbn < NDADDR) {
1578: db_assign(ip, lbn, bno);
1579: } else {
1580: idb_assign(ip, ibp->b_data, indiroff, bno);
1581: bwrite(ibp);
1582: }
1583: DIP_ADD(ip, blocks, btodb(size));
1584: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1585: VOP_UNLOCK(vp, 0);
1586: return (1);
1587: }
1588: if (lbn >= NDADDR)
1589: brelse(ibp);
1590: #ifdef DEBUG
1591: if (snapdebug)
1.19 christos 1592: printf("%s%llu lbn %" PRId64 " %s %llu size %ld\n",
1593: "Copyonremove: snapino ",
1594: (unsigned long long)ip->i_number,
1595: lbn, "for inum", (unsigned long long)inum, size);
1.1 hannken 1596: #endif
1597: /*
1598: * If we have already read the old block contents, then
1599: * simply copy them to the new block. Note that we need
1600: * to synchronously write snapshots that have not been
1601: * unlinked, and hence will be visible after a crash,
1602: * to ensure their integrity.
1603: */
1604: if (saved_data) {
1605: error = writevnblk(vp, saved_data, lbn);
1606: if (error)
1607: break;
1608: continue;
1609: }
1610: /*
1611: * Otherwise, read the old block contents into the buffer.
1612: */
1613: saved_data = malloc(fs->fs_bsize, M_UFSMNT, M_WAITOK);
1614: saved_vp = vp;
1615: if ((error = readfsblk(vp, saved_data, lbn)) != 0) {
1616: free(saved_data, M_UFSMNT);
1617: saved_data = NULL;
1618: break;
1619: }
1620: }
1621: /*
1622: * Note that we need to synchronously write snapshots that
1623: * have not been unlinked, and hence will be visible after
1624: * a crash, to ensure their integrity.
1625: */
1626: if (saved_data) {
1627: error = writevnblk(saved_vp, saved_data, lbn);
1628: free(saved_data, M_UFSMNT);
1629: }
1630: /*
1631: * If we have been unable to allocate a block in which to do
1632: * the copy, then return non-zero so that the fragment will
1633: * not be freed. Although space will be lost, the snapshot
1634: * will stay consistent.
1635: */
1636: if (snapshot_locked)
1637: VOP_UNLOCK(vp, 0);
1638: else
1639: VI_UNLOCK(devvp);
1640: return (error);
1641: }
1642:
1643: /*
1644: * Associate snapshot files when mounting.
1645: */
1646: void
1.18 thorpej 1647: ffs_snapshot_mount(struct mount *mp)
1.1 hannken 1648: {
1649: struct ufsmount *ump = VFSTOUFS(mp);
1650: struct vnode *devvp = ump->um_devvp;
1651: struct fs *fs = ump->um_fs;
1.31 ad 1652: struct lwp *l = curlwp;
1.1 hannken 1653: struct vnode *vp;
1654: struct inode *ip, *xp;
1655: ufs2_daddr_t snaplistsize, *snapblklist;
1.15 hannken 1656: int i, error, ns, snaploc, loc;
1.1 hannken 1657:
1658: ns = UFS_FSNEEDSWAP(fs);
1659: /*
1.22 yamt 1660: * XXX The following needs to be set before ffs_truncate or
1.1 hannken 1661: * VOP_READ can be called.
1662: */
1663: mp->mnt_stat.f_iosize = fs->fs_bsize;
1664: /*
1665: * Process each snapshot listed in the superblock.
1666: */
1667: vp = NULL;
1668: for (snaploc = 0; snaploc < FSMAXSNAP; snaploc++) {
1669: if (fs->fs_snapinum[snaploc] == 0)
1670: break;
1671: if ((error = VFS_VGET(mp, fs->fs_snapinum[snaploc],
1672: &vp)) != 0) {
1673: printf("ffs_snapshot_mount: vget failed %d\n", error);
1674: continue;
1675: }
1676: ip = VTOI(vp);
1677: if ((ip->i_flags & SF_SNAPSHOT) == 0) {
1678: printf("ffs_snapshot_mount: non-snapshot inode %d\n",
1679: fs->fs_snapinum[snaploc]);
1680: vput(vp);
1681: vp = NULL;
1682: for (loc = snaploc + 1; loc < FSMAXSNAP; loc++) {
1683: if (fs->fs_snapinum[loc] == 0)
1684: break;
1685: fs->fs_snapinum[loc - 1] = fs->fs_snapinum[loc];
1686: }
1687: fs->fs_snapinum[loc - 1] = 0;
1688: snaploc--;
1689: continue;
1690: }
1.15 hannken 1691:
1692: /*
1693: * Read the block hints list. Use an empty list on
1694: * read errors.
1695: */
1696: error = vn_rdwr(UIO_READ, vp,
1.43 christos 1697: (void *)&snaplistsize, sizeof(snaplistsize),
1.15 hannken 1698: lblktosize(fs, howmany(fs->fs_size, fs->fs_frag)),
1699: UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT,
1.31 ad 1700: l->l_cred, NULL, NULL);
1.15 hannken 1701: if (error) {
1702: printf("ffs_snapshot_mount: read_1 failed %d\n", error);
1703: snaplistsize = 1;
1704: } else
1705: snaplistsize = ufs_rw64(snaplistsize, ns);
1.25 christos 1706: snapblklist = malloc(
1.15 hannken 1707: snaplistsize * sizeof(ufs2_daddr_t), M_UFSMNT, M_WAITOK);
1708: if (error)
1709: snapblklist[0] = 1;
1710: else {
1.43 christos 1711: error = vn_rdwr(UIO_READ, vp, (void *)snapblklist,
1.15 hannken 1712: snaplistsize * sizeof(ufs2_daddr_t),
1713: lblktosize(fs, howmany(fs->fs_size, fs->fs_frag)),
1714: UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT,
1.31 ad 1715: l->l_cred, NULL, NULL);
1.15 hannken 1716: for (i = 0; i < snaplistsize; i++)
1717: snapblklist[i] = ufs_rw64(snapblklist[i], ns);
1718: if (error) {
1719: printf("ffs_snapshot_mount: read_2 failed %d\n",
1720: error);
1721: snapblklist[0] = 1;
1722: }
1723: }
1724: ip->i_snapblklist = &snapblklist[0];
1725:
1.1 hannken 1726: /*
1727: * If there already exist snapshots on this filesystem, grab a
1728: * reference to their shared lock. If this is the first snapshot
1729: * on this filesystem, we need to allocate a lock for the
1730: * snapshots to share. In either case, acquire the snapshot
1731: * lock and give up our original private lock.
1732: */
1733: VI_LOCK(devvp);
1734: if ((xp = TAILQ_FIRST(&ump->um_snapshots)) != NULL) {
1735: struct lock *lkp;
1736:
1737: lkp = ITOV(xp)->v_vnlock;
1738: VI_UNLOCK(devvp);
1739: VI_LOCK(vp);
1740: vp->v_vnlock = lkp;
1741: } else {
1742: struct lock *lkp;
1743:
1744: VI_UNLOCK(devvp);
1745: MALLOC(lkp, struct lock *, sizeof(struct lock),
1746: M_UFSMNT, M_WAITOK);
1747: lockinit(lkp, PVFS, "snaplk", 0, LK_CANRECURSE);
1748: VI_LOCK(vp);
1749: vp->v_vnlock = lkp;
1750: }
1751: vn_lock(vp, LK_INTERLOCK | LK_EXCLUSIVE | LK_RETRY);
1752: transferlockers(&vp->v_lock, vp->v_vnlock);
1753: lockmgr(&vp->v_lock, LK_RELEASE, NULL);
1754: /*
1755: * Link it onto the active snapshot list.
1756: */
1757: VI_LOCK(devvp);
1758: if (ip->i_nextsnap.tqe_prev != 0)
1.19 christos 1759: panic("ffs_snapshot_mount: %llu already on list",
1760: (unsigned long long)ip->i_number);
1.1 hannken 1761: else
1762: TAILQ_INSERT_TAIL(&ump->um_snapshots, ip, i_nextsnap);
1763: vp->v_flag |= VSYSTEM;
1764: VI_UNLOCK(devvp);
1765: VOP_UNLOCK(vp, 0);
1766: }
1767: /*
1768: * No usable snapshots found.
1769: */
1770: if (vp == NULL)
1771: return;
1772: /*
1.15 hannken 1773: * Attach the block hints list. We always want to
1.1 hannken 1774: * use the list from the newest snapshot.
1.15 hannken 1775: */
1776: xp = TAILQ_LAST(&ump->um_snapshots, inodelst);
1.1 hannken 1777: VI_LOCK(devvp);
1.15 hannken 1778: ump->um_snapblklist = xp->i_snapblklist;
1.1 hannken 1779: VI_UNLOCK(devvp);
1780: vn_cow_establish(devvp, ffs_copyonwrite, devvp);
1781: }
1782:
1783: /*
1784: * Disassociate snapshot files when unmounting.
1785: */
1786: void
1.18 thorpej 1787: ffs_snapshot_unmount(struct mount *mp)
1.1 hannken 1788: {
1789: struct ufsmount *ump = VFSTOUFS(mp);
1790: struct vnode *devvp = ump->um_devvp;
1791: struct lock *lkp = NULL;
1792: struct inode *xp;
1793: struct vnode *vp;
1794:
1795: VI_LOCK(devvp);
1796: while ((xp = TAILQ_FIRST(&ump->um_snapshots)) != 0) {
1797: vp = ITOV(xp);
1798: lkp = vp->v_vnlock;
1799: vp->v_vnlock = &vp->v_lock;
1800: TAILQ_REMOVE(&ump->um_snapshots, xp, i_nextsnap);
1801: xp->i_nextsnap.tqe_prev = 0;
1.15 hannken 1802: if (xp->i_snapblklist == ump->um_snapblklist)
1803: ump->um_snapblklist = NULL;
1804: VI_UNLOCK(devvp);
1805: FREE(xp->i_snapblklist, M_UFSMNT);
1806: if (xp->i_ffs_effnlink > 0)
1.1 hannken 1807: vrele(vp);
1.15 hannken 1808: VI_LOCK(devvp);
1.1 hannken 1809: }
1810: VI_UNLOCK(devvp);
1811: if (lkp != NULL) {
1812: vn_cow_disestablish(devvp, ffs_copyonwrite, devvp);
1813: FREE(lkp, M_UFSMNT);
1814: }
1815: }
1816:
1817: /*
1818: * Check for need to copy block that is about to be written,
1819: * copying the block if necessary.
1820: */
1821: static int
1.18 thorpej 1822: ffs_copyonwrite(void *v, struct buf *bp)
1.1 hannken 1823: {
1824: struct buf *ibp;
1825: struct fs *fs;
1826: struct inode *ip;
1827: struct vnode *devvp = v, *vp = 0, *saved_vp = NULL;
1828: struct ufsmount *ump = VFSTOUFS(devvp->v_specmountpoint);
1.43 christos 1829: void *saved_data = NULL;
1.1 hannken 1830: ufs2_daddr_t lbn, blkno, *snapblklist;
1.4 hannken 1831: int lower, upper, mid, s, ns, indiroff, snapshot_locked = 0, error = 0;
1.1 hannken 1832:
1833: /*
1834: * Check for valid snapshots.
1835: */
1836: VI_LOCK(devvp);
1837: ip = TAILQ_FIRST(&ump->um_snapshots);
1838: if (ip == NULL) {
1839: VI_UNLOCK(devvp);
1.11 perry 1840: return 0;
1.1 hannken 1841: }
1842: /*
1843: * First check to see if it is in the preallocated list.
1844: * By doing this check we avoid several potential deadlocks.
1845: */
1846: fs = ip->i_fs;
1847: ns = UFS_FSNEEDSWAP(fs);
1848: lbn = fragstoblks(fs, dbtofsb(fs, bp->b_blkno));
1849: snapblklist = ump->um_snapblklist;
1.15 hannken 1850: upper = ump->um_snapblklist[0] - 1;
1.1 hannken 1851: lower = 1;
1852: while (lower <= upper) {
1853: mid = (lower + upper) / 2;
1.15 hannken 1854: if (snapblklist[mid] == lbn)
1.1 hannken 1855: break;
1.15 hannken 1856: if (snapblklist[mid] < lbn)
1.1 hannken 1857: lower = mid + 1;
1858: else
1859: upper = mid - 1;
1860: }
1861: if (lower <= upper) {
1862: VI_UNLOCK(devvp);
1863: return 0;
1864: }
1865: /*
1866: * Not in the precomputed list, so check the snapshots.
1867: */
1868: retry:
1869: TAILQ_FOREACH(ip, &ump->um_snapshots, i_nextsnap) {
1870: vp = ITOV(ip);
1871: /*
1872: * We ensure that everything of our own that needs to be
1873: * copied will be done at the time that ffs_snapshot is
1874: * called. Thus we can skip the check here which can
1.22 yamt 1875: * deadlock in doing the lookup in ffs_balloc.
1.1 hannken 1876: */
1877: if (bp->b_vp == vp)
1878: continue;
1879: /*
1880: * Check to see if block needs to be copied. We do not have
1881: * to hold the snapshot lock while doing this lookup as it
1882: * will never require any additional allocations for the
1883: * snapshot inode.
1884: */
1885: if (lbn < NDADDR) {
1886: blkno = db_get(ip, lbn);
1887: } else {
1888: if (snapshot_locked == 0 &&
1889: lockmgr(vp->v_vnlock,
1890: LK_INTERLOCK | LK_EXCLUSIVE | LK_SLEEPFAIL,
1891: VI_MTX(devvp)) != 0) {
1892: VI_LOCK(devvp);
1893: goto retry;
1894: }
1895: snapshot_locked = 1;
1.4 hannken 1896: s = cow_enter();
1.22 yamt 1897: error = ffs_balloc(vp, lblktosize(fs, (off_t)lbn),
1.1 hannken 1898: fs->fs_bsize, KERNCRED, B_METAONLY, &ibp);
1.4 hannken 1899: cow_leave(s);
1.1 hannken 1900: if (error)
1901: break;
1902: indiroff = (lbn - NDADDR) % NINDIR(fs);
1903: blkno = idb_get(ip, ibp->b_data, indiroff);
1904: brelse(ibp);
1905: }
1906: #ifdef DIAGNOSTIC
1907: if (blkno == BLK_SNAP && bp->b_lblkno >= 0)
1908: panic("ffs_copyonwrite: bad copy block");
1909: #endif
1910: if (blkno != 0)
1911: continue;
1.4 hannken 1912: #ifdef DIAGNOSTIC
1.41 ad 1913: if (curlwp->l_pflag & LP_UFSCOW)
1.4 hannken 1914: printf("ffs_copyonwrite: recursive call\n");
1915: #endif
1.1 hannken 1916: /*
1917: * Allocate the block into which to do the copy. Since
1918: * multiple processes may all try to copy the same block,
1919: * we have to recheck our need to do a copy if we sleep
1920: * waiting for the lock.
1921: *
1922: * Because all snapshots on a filesystem share a single
1923: * lock, we ensure that we will never be in competition
1924: * with another process to allocate a block.
1925: */
1926: if (snapshot_locked == 0 &&
1927: lockmgr(vp->v_vnlock,
1928: LK_INTERLOCK | LK_EXCLUSIVE | LK_SLEEPFAIL,
1929: VI_MTX(devvp)) != 0) {
1930: VI_LOCK(devvp);
1931: goto retry;
1932: }
1933: snapshot_locked = 1;
1934: #ifdef DEBUG
1935: if (snapdebug) {
1.19 christos 1936: printf("Copyonwrite: snapino %llu lbn %" PRId64 " for ",
1937: (unsigned long long)ip->i_number, lbn);
1.1 hannken 1938: if (bp->b_vp == devvp)
1939: printf("fs metadata");
1940: else
1.19 christos 1941: printf("inum %llu", (unsigned long long)
1942: VTOI(bp->b_vp)->i_number);
1.4 hannken 1943: printf(" lblkno %" PRId64 "\n", bp->b_lblkno);
1.1 hannken 1944: }
1945: #endif
1946: /*
1947: * If we have already read the old block contents, then
1948: * simply copy them to the new block. Note that we need
1949: * to synchronously write snapshots that have not been
1950: * unlinked, and hence will be visible after a crash,
1951: * to ensure their integrity.
1952: */
1953: if (saved_data) {
1954: error = writevnblk(vp, saved_data, lbn);
1955: if (error)
1956: break;
1957: continue;
1958: }
1959: /*
1960: * Otherwise, read the old block contents into the buffer.
1961: */
1962: saved_data = malloc(fs->fs_bsize, M_UFSMNT, M_WAITOK);
1963: saved_vp = vp;
1964: if ((error = readfsblk(vp, saved_data, lbn)) != 0) {
1965: free(saved_data, M_UFSMNT);
1966: saved_data = NULL;
1967: break;
1968: }
1969: }
1970: /*
1971: * Note that we need to synchronously write snapshots that
1972: * have not been unlinked, and hence will be visible after
1973: * a crash, to ensure their integrity.
1974: */
1975: if (saved_data) {
1976: error = writevnblk(saved_vp, saved_data, lbn);
1977: free(saved_data, M_UFSMNT);
1978: }
1979: if (snapshot_locked)
1980: VOP_UNLOCK(vp, 0);
1981: else
1982: VI_UNLOCK(devvp);
1983: return error;
1984: }
1985:
1986: /*
1987: * Read the specified block from disk. Vp is usually a snapshot vnode.
1988: */
1989: static int
1.43 christos 1990: readfsblk(struct vnode *vp, void *data, ufs2_daddr_t lbn)
1.1 hannken 1991: {
1.24 yamt 1992: int error;
1.1 hannken 1993: struct inode *ip = VTOI(vp);
1994: struct fs *fs = ip->i_fs;
1995: struct buf *nbp;
1996:
1.24 yamt 1997: nbp = getiobuf();
1.1 hannken 1998: nbp->b_flags = B_READ;
1999: nbp->b_bcount = nbp->b_bufsize = fs->fs_bsize;
2000: nbp->b_error = 0;
2001: nbp->b_data = data;
2002: nbp->b_blkno = nbp->b_rawblkno = fsbtodb(fs, blkstofrags(fs, lbn));
2003: nbp->b_proc = NULL;
2004: nbp->b_dev = ip->i_devvp->v_rdev;
2005: nbp->b_vp = NULLVP;
2006:
2007: DEV_STRATEGY(nbp);
2008:
2009: error = biowait(nbp);
2010:
1.24 yamt 2011: putiobuf(nbp);
1.1 hannken 2012:
2013: return error;
2014: }
2015:
1.37 christos 2016: #if !defined(FFS_NO_SNAPSHOT)
1.1 hannken 2017: /*
1.4 hannken 2018: * Read the specified block. Bypass UBC to prevent deadlocks.
1.1 hannken 2019: */
2020: static int
1.43 christos 2021: readvnblk(struct vnode *vp, void *data, ufs2_daddr_t lbn)
1.1 hannken 2022: {
1.4 hannken 2023: int error;
2024: daddr_t bn;
2025: off_t offset;
1.1 hannken 2026: struct inode *ip = VTOI(vp);
2027: struct fs *fs = ip->i_fs;
2028:
1.4 hannken 2029: error = VOP_BMAP(vp, lbn, NULL, &bn, NULL);
2030: if (error)
2031: return error;
1.1 hannken 2032:
1.4 hannken 2033: if (bn != (daddr_t)-1) {
2034: offset = dbtob(bn);
1.43.2.1 ad 2035: mutex_enter(&vp->v_interlock);
1.4 hannken 2036: error = VOP_PUTPAGES(vp, trunc_page(offset),
2037: round_page(offset+fs->fs_bsize),
2038: PGO_CLEANIT|PGO_SYNCIO|PGO_FREE);
1.1 hannken 2039: if (error)
1.4 hannken 2040: return error;
2041:
2042: return readfsblk(vp, data, fragstoblks(fs, dbtofsb(fs, bn)));
1.1 hannken 2043: }
2044:
1.4 hannken 2045: bzero(data, fs->fs_bsize);
2046:
2047: return 0;
1.1 hannken 2048: }
1.37 christos 2049: #endif /* !defined(FFS_NO_SNAPSHOT) */
1.1 hannken 2050:
2051: /*
1.4 hannken 2052: * Write the specified block. Bypass UBC to prevent deadlocks.
1.1 hannken 2053: */
2054: static int
1.43 christos 2055: writevnblk(struct vnode *vp, void *data, ufs2_daddr_t lbn)
1.1 hannken 2056: {
1.4 hannken 2057: int s, error;
2058: off_t offset;
2059: struct buf *bp;
1.1 hannken 2060: struct inode *ip = VTOI(vp);
2061: struct fs *fs = ip->i_fs;
2062:
1.4 hannken 2063: offset = lblktosize(fs, (off_t)lbn);
2064: s = cow_enter();
1.43.2.1 ad 2065: mutex_enter(&vp->v_interlock);
1.4 hannken 2066: error = VOP_PUTPAGES(vp, trunc_page(offset),
2067: round_page(offset+fs->fs_bsize), PGO_CLEANIT|PGO_SYNCIO|PGO_FREE);
2068: if (error == 0)
1.22 yamt 2069: error = ffs_balloc(vp, lblktosize(fs, (off_t)lbn),
1.4 hannken 2070: fs->fs_bsize, KERNCRED, B_SYNC, &bp);
2071: cow_leave(s);
1.1 hannken 2072: if (error)
2073: return error;
2074:
1.4 hannken 2075: bcopy(data, bp->b_data, fs->fs_bsize);
2076: bp->b_flags |= B_NOCACHE;
2077:
2078: return bwrite(bp);
2079: }
2080:
2081: /*
1.41 ad 2082: * Set/reset lwp's LP_UFSCOW flag.
1.4 hannken 2083: * May be called recursive.
2084: */
2085: static inline int
2086: cow_enter(void)
2087: {
2088: struct lwp *l = curlwp;
2089:
1.41 ad 2090: if (l->l_pflag & LP_UFSCOW) {
1.4 hannken 2091: return 0;
2092: } else {
1.41 ad 2093: l->l_pflag |= LP_UFSCOW;
2094: return LP_UFSCOW;
1.1 hannken 2095: }
1.4 hannken 2096: }
2097:
2098: static inline void
2099: cow_leave(int flag)
2100: {
2101: struct lwp *l = curlwp;
1.1 hannken 2102:
1.41 ad 2103: l->l_pflag &= ~flag;
1.1 hannken 2104: }
2105:
2106: /*
2107: * Get/Put direct block from inode or buffer containing disk addresses. Take
2108: * care for fs type (UFS1/UFS2) and byte swapping. These functions should go
2109: * into a global include.
2110: */
2111: static inline ufs2_daddr_t
2112: db_get(struct inode *ip, int loc)
2113: {
2114: if (ip->i_ump->um_fstype == UFS1)
1.2 hannken 2115: return ufs_rw32(ip->i_ffs1_db[loc], UFS_IPNEEDSWAP(ip));
1.1 hannken 2116: else
1.2 hannken 2117: return ufs_rw64(ip->i_ffs2_db[loc], UFS_IPNEEDSWAP(ip));
1.1 hannken 2118: }
2119:
2120: static inline void
2121: db_assign(struct inode *ip, int loc, ufs2_daddr_t val)
2122: {
2123: if (ip->i_ump->um_fstype == UFS1)
1.2 hannken 2124: ip->i_ffs1_db[loc] = ufs_rw32(val, UFS_IPNEEDSWAP(ip));
1.1 hannken 2125: else
1.2 hannken 2126: ip->i_ffs2_db[loc] = ufs_rw64(val, UFS_IPNEEDSWAP(ip));
1.1 hannken 2127: }
2128:
2129: static inline ufs2_daddr_t
1.43 christos 2130: idb_get(struct inode *ip, void *bf, int loc)
1.1 hannken 2131: {
2132: if (ip->i_ump->um_fstype == UFS1)
1.17 christos 2133: return ufs_rw32(((ufs1_daddr_t *)(bf))[loc],
1.2 hannken 2134: UFS_IPNEEDSWAP(ip));
1.1 hannken 2135: else
1.17 christos 2136: return ufs_rw64(((ufs2_daddr_t *)(bf))[loc],
1.2 hannken 2137: UFS_IPNEEDSWAP(ip));
1.1 hannken 2138: }
2139:
2140: static inline void
1.43 christos 2141: idb_assign(struct inode *ip, void *bf, int loc, ufs2_daddr_t val)
1.1 hannken 2142: {
2143: if (ip->i_ump->um_fstype == UFS1)
1.17 christos 2144: ((ufs1_daddr_t *)(bf))[loc] =
1.2 hannken 2145: ufs_rw32(val, UFS_IPNEEDSWAP(ip));
1.1 hannken 2146: else
1.17 christos 2147: ((ufs2_daddr_t *)(bf))[loc] =
1.2 hannken 2148: ufs_rw64(val, UFS_IPNEEDSWAP(ip));
1.1 hannken 2149: }
CVSweb <webmaster@jp.NetBSD.org>