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