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