1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/buf.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_filio.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_snap.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/fssnap_if.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_bio.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/inttypes.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/disp.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/policy.h> 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate static int ufs_snap_init_backfile(int *, int, vnode_t ***, struct ufsvfs *); 55*7c478bd9Sstevel@tonic-gate static void release_backing_vnodes(vnode_t ***, int); 56*7c478bd9Sstevel@tonic-gate static int ufs_snap_find_candidates(void *, struct ufsvfs *, int); 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate /* 59*7c478bd9Sstevel@tonic-gate * Create a snapshot on a file system 60*7c478bd9Sstevel@tonic-gate */ 61*7c478bd9Sstevel@tonic-gate int 62*7c478bd9Sstevel@tonic-gate ufs_snap_create(struct vnode *vp, struct fiosnapcreate_multi *fiosnapp, 63*7c478bd9Sstevel@tonic-gate cred_t *cr) 64*7c478bd9Sstevel@tonic-gate { 65*7c478bd9Sstevel@tonic-gate int error = 0; 66*7c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = VTOI(vp)->i_ufsvfs; 67*7c478bd9Sstevel@tonic-gate struct fs *fs = ufsvfsp->vfs_fs; 68*7c478bd9Sstevel@tonic-gate vnode_t **bfvpp = NULL; 69*7c478bd9Sstevel@tonic-gate struct lockfs lf; 70*7c478bd9Sstevel@tonic-gate void *snapid = NULL; 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate u_offset_t nchunks; 73*7c478bd9Sstevel@tonic-gate uint_t chunksize, fragsperchunk; 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate /* 76*7c478bd9Sstevel@tonic-gate * Only privilege processes can create a snapshot for now. This 77*7c478bd9Sstevel@tonic-gate * would be better if it was based on the permissions of the device 78*7c478bd9Sstevel@tonic-gate * file. 79*7c478bd9Sstevel@tonic-gate */ 80*7c478bd9Sstevel@tonic-gate if (secpolicy_fs_config(cr, ufsvfsp->vfs_vfs) != 0) 81*7c478bd9Sstevel@tonic-gate return (EPERM); 82*7c478bd9Sstevel@tonic-gate 83*7c478bd9Sstevel@tonic-gate /* 84*7c478bd9Sstevel@tonic-gate * There is no reason to make a snapshot of a read-only file system 85*7c478bd9Sstevel@tonic-gate */ 86*7c478bd9Sstevel@tonic-gate if (fs->fs_ronly) { 87*7c478bd9Sstevel@tonic-gate fiosnapp->error = FIOCOW_EREADONLY; 88*7c478bd9Sstevel@tonic-gate return (EROFS); 89*7c478bd9Sstevel@tonic-gate } 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate /* 92*7c478bd9Sstevel@tonic-gate * Initialize the backing files to store old data. This assumes any 93*7c478bd9Sstevel@tonic-gate * preallocation and setup has been done already. 94*7c478bd9Sstevel@tonic-gate * ufs_snap_init_backfile() allocates and returns a pointer to 95*7c478bd9Sstevel@tonic-gate * a null-terminated array of vnodes in bfvpp. 96*7c478bd9Sstevel@tonic-gate */ 97*7c478bd9Sstevel@tonic-gate error = ufs_snap_init_backfile(fiosnapp->backfiledesc, 98*7c478bd9Sstevel@tonic-gate fiosnapp->backfilecount, &bfvpp, ufsvfsp); 99*7c478bd9Sstevel@tonic-gate if (error) { 100*7c478bd9Sstevel@tonic-gate fiosnapp->error = FIOCOW_EBACKFILE; 101*7c478bd9Sstevel@tonic-gate return (error); 102*7c478bd9Sstevel@tonic-gate } 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate /* 105*7c478bd9Sstevel@tonic-gate * File system must be write locked to prevent updates while 106*7c478bd9Sstevel@tonic-gate * the snapshot is being established. 107*7c478bd9Sstevel@tonic-gate */ 108*7c478bd9Sstevel@tonic-gate if ((error = ufs_fiolfss(vp, &lf)) != 0) { 109*7c478bd9Sstevel@tonic-gate release_backing_vnodes(&bfvpp, fiosnapp->backfilecount); 110*7c478bd9Sstevel@tonic-gate return (error); 111*7c478bd9Sstevel@tonic-gate } 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate if (!LOCKFS_IS_ULOCK(&lf)) { 114*7c478bd9Sstevel@tonic-gate release_backing_vnodes(&bfvpp, fiosnapp->backfilecount); 115*7c478bd9Sstevel@tonic-gate fiosnapp->error = FIOCOW_EULOCK; 116*7c478bd9Sstevel@tonic-gate return (EINVAL); 117*7c478bd9Sstevel@tonic-gate } 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate lf.lf_lock = LOCKFS_WLOCK; 120*7c478bd9Sstevel@tonic-gate lf.lf_flags = 0; 121*7c478bd9Sstevel@tonic-gate lf.lf_comment = NULL; 122*7c478bd9Sstevel@tonic-gate if ((error = ufs_fiolfs(vp, &lf, 1)) != 0) { 123*7c478bd9Sstevel@tonic-gate release_backing_vnodes(&bfvpp, fiosnapp->backfilecount); 124*7c478bd9Sstevel@tonic-gate fiosnapp->error = FIOCOW_EWLOCK; 125*7c478bd9Sstevel@tonic-gate return (EINVAL); 126*7c478bd9Sstevel@tonic-gate } 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate /* 129*7c478bd9Sstevel@tonic-gate * File system must be fairly consistent to enable snapshots 130*7c478bd9Sstevel@tonic-gate */ 131*7c478bd9Sstevel@tonic-gate if (fs->fs_clean != FSACTIVE && 132*7c478bd9Sstevel@tonic-gate fs->fs_clean != FSSTABLE && 133*7c478bd9Sstevel@tonic-gate fs->fs_clean != FSCLEAN && 134*7c478bd9Sstevel@tonic-gate fs->fs_clean != FSLOG) { 135*7c478bd9Sstevel@tonic-gate fiosnapp->error = FIOCOW_ECLEAN; 136*7c478bd9Sstevel@tonic-gate error = EINVAL; 137*7c478bd9Sstevel@tonic-gate goto unlockout; 138*7c478bd9Sstevel@tonic-gate } 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate /* 141*7c478bd9Sstevel@tonic-gate * Only one snapshot is allowed per file system, so error if 142*7c478bd9Sstevel@tonic-gate * a snapshot is already enabled. 143*7c478bd9Sstevel@tonic-gate */ 144*7c478bd9Sstevel@tonic-gate if (ufsvfsp->vfs_snapshot) { 145*7c478bd9Sstevel@tonic-gate fiosnapp->error = FIOCOW_EBUSY; 146*7c478bd9Sstevel@tonic-gate error = EBUSY; 147*7c478bd9Sstevel@tonic-gate goto unlockout; 148*7c478bd9Sstevel@tonic-gate } 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate /* Tell bio.c how to call our strategy routine. XXX ugly hack */ 151*7c478bd9Sstevel@tonic-gate if (bio_snapshot_strategy == NULL) 152*7c478bd9Sstevel@tonic-gate bio_snapshot_strategy = 153*7c478bd9Sstevel@tonic-gate (void (*) (void *, buf_t *))fssnap_strategy; 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate /* 156*7c478bd9Sstevel@tonic-gate * use chunk size that is passed in, or the file system 157*7c478bd9Sstevel@tonic-gate * block size if it is zero. For most cases, the file system 158*7c478bd9Sstevel@tonic-gate * block size will be reasonably efficient. A larger 159*7c478bd9Sstevel@tonic-gate * chunksize uses less memory but may potentially induce more 160*7c478bd9Sstevel@tonic-gate * I/O copying the larger chunks aside. 161*7c478bd9Sstevel@tonic-gate */ 162*7c478bd9Sstevel@tonic-gate if (fiosnapp->chunksize != 0) 163*7c478bd9Sstevel@tonic-gate chunksize = fiosnapp->chunksize; 164*7c478bd9Sstevel@tonic-gate else 165*7c478bd9Sstevel@tonic-gate chunksize = fs->fs_bsize * 4; 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate /* 169*7c478bd9Sstevel@tonic-gate * compute the number of chunks in this whole file system. Since 170*7c478bd9Sstevel@tonic-gate * the UFS allocation bitmaps are in units of fragments, we first 171*7c478bd9Sstevel@tonic-gate * compute the number of fragments per chunk. Things work out 172*7c478bd9Sstevel@tonic-gate * nicer if the chunk size is a power-of-two multiple of the 173*7c478bd9Sstevel@tonic-gate * fragment size. 174*7c478bd9Sstevel@tonic-gate */ 175*7c478bd9Sstevel@tonic-gate if ((chunksize < fs->fs_fsize) || (chunksize % fs->fs_fsize != 0)) { 176*7c478bd9Sstevel@tonic-gate fiosnapp->error = FIOCOW_ECHUNKSZ; 177*7c478bd9Sstevel@tonic-gate error = EINVAL; 178*7c478bd9Sstevel@tonic-gate goto unlockout; 179*7c478bd9Sstevel@tonic-gate } 180*7c478bd9Sstevel@tonic-gate fragsperchunk = chunksize >> fs->fs_fshift; 181*7c478bd9Sstevel@tonic-gate nchunks = (fs->fs_size + fragsperchunk) / fragsperchunk; 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate /* 184*7c478bd9Sstevel@tonic-gate * Create and initialize snapshot state and allocate/initialize 185*7c478bd9Sstevel@tonic-gate * translation table. This does the real work of taking the snapshot. 186*7c478bd9Sstevel@tonic-gate */ 187*7c478bd9Sstevel@tonic-gate snapid = fssnap_create(nchunks, chunksize, fiosnapp->maxsize, vp, 188*7c478bd9Sstevel@tonic-gate fiosnapp->backfilecount, bfvpp, fiosnapp->backfilename, 189*7c478bd9Sstevel@tonic-gate fiosnapp->backfilesize); 190*7c478bd9Sstevel@tonic-gate if (snapid == NULL) { 191*7c478bd9Sstevel@tonic-gate fiosnapp->error = FIOCOW_ECREATE; 192*7c478bd9Sstevel@tonic-gate error = EINVAL; 193*7c478bd9Sstevel@tonic-gate goto unlockout; 194*7c478bd9Sstevel@tonic-gate } 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate error = ufs_snap_find_candidates(snapid, ufsvfsp, chunksize); 197*7c478bd9Sstevel@tonic-gate fiosnapp->snapshotnumber = fssnap_create_done(snapid); 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate if (error) { 200*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "ufs_snap_create: failed scanning bitmaps, " 201*7c478bd9Sstevel@tonic-gate "error = %d.", error); 202*7c478bd9Sstevel@tonic-gate fiosnapp->error = FIOCOW_EBITMAP; 203*7c478bd9Sstevel@tonic-gate goto unlockout; 204*7c478bd9Sstevel@tonic-gate } 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate ufsvfsp->vfs_snapshot = snapid; 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate unlockout: 209*7c478bd9Sstevel@tonic-gate /* 210*7c478bd9Sstevel@tonic-gate * Unlock the file system 211*7c478bd9Sstevel@tonic-gate */ 212*7c478bd9Sstevel@tonic-gate lf.lf_lock = LOCKFS_ULOCK; 213*7c478bd9Sstevel@tonic-gate lf.lf_flags = 0; 214*7c478bd9Sstevel@tonic-gate if ((ufs_fiolfs(vp, &lf, 1) != 0) && !error) { 215*7c478bd9Sstevel@tonic-gate fiosnapp->error = FIOCOW_ENOULOCK; 216*7c478bd9Sstevel@tonic-gate error = EINVAL; 217*7c478bd9Sstevel@tonic-gate } else { 218*7c478bd9Sstevel@tonic-gate fiosnapp->error = 0; 219*7c478bd9Sstevel@tonic-gate } 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate /* clean up the snapshot if an error occurred. */ 222*7c478bd9Sstevel@tonic-gate if (error && snapid != NULL) 223*7c478bd9Sstevel@tonic-gate (void) fssnap_delete(&snapid); 224*7c478bd9Sstevel@tonic-gate else if (error && bfvpp != NULL) 225*7c478bd9Sstevel@tonic-gate release_backing_vnodes(&bfvpp, fiosnapp->backfilecount); 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate return (error); 228*7c478bd9Sstevel@tonic-gate } 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate static int 231*7c478bd9Sstevel@tonic-gate ufs_snap_init_backfile(int *filedesc, int count, vnode_t ***vppp, 232*7c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp) 233*7c478bd9Sstevel@tonic-gate { 234*7c478bd9Sstevel@tonic-gate file_t *fp; 235*7c478bd9Sstevel@tonic-gate vnode_t **vpp; 236*7c478bd9Sstevel@tonic-gate int i; 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate vpp = (vnode_t **)kmem_zalloc((count + 1) * sizeof (vnode_t *), 239*7c478bd9Sstevel@tonic-gate KM_SLEEP); 240*7c478bd9Sstevel@tonic-gate *vppp = vpp; 241*7c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 242*7c478bd9Sstevel@tonic-gate if ((fp = getf(*filedesc)) == NULL) { 243*7c478bd9Sstevel@tonic-gate release_backing_vnodes(vppp, count); 244*7c478bd9Sstevel@tonic-gate *vppp = NULL; 245*7c478bd9Sstevel@tonic-gate return (EBADF); 246*7c478bd9Sstevel@tonic-gate } 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate ASSERT(fp->f_vnode != NULL); 249*7c478bd9Sstevel@tonic-gate VN_HOLD(fp->f_vnode); 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate *vpp = fp->f_vnode; 252*7c478bd9Sstevel@tonic-gate releasef(*filedesc); 253*7c478bd9Sstevel@tonic-gate filedesc++; 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate /* make sure the backing file is on a different file system */ 256*7c478bd9Sstevel@tonic-gate if ((*vpp)->v_vfsp == ufsvfsp->vfs_vfs) { 257*7c478bd9Sstevel@tonic-gate release_backing_vnodes(vppp, count); 258*7c478bd9Sstevel@tonic-gate *vppp = NULL; 259*7c478bd9Sstevel@tonic-gate return (EINVAL); 260*7c478bd9Sstevel@tonic-gate } 261*7c478bd9Sstevel@tonic-gate vpp++; 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate return (0); 264*7c478bd9Sstevel@tonic-gate } 265*7c478bd9Sstevel@tonic-gate 266*7c478bd9Sstevel@tonic-gate static void 267*7c478bd9Sstevel@tonic-gate release_backing_vnodes(vnode_t ***bvppp, int count) 268*7c478bd9Sstevel@tonic-gate { 269*7c478bd9Sstevel@tonic-gate vnode_t **vpp; 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate vpp = *bvppp; 272*7c478bd9Sstevel@tonic-gate while (*vpp) { 273*7c478bd9Sstevel@tonic-gate VN_RELE(*vpp); 274*7c478bd9Sstevel@tonic-gate *vpp++ = NULL; 275*7c478bd9Sstevel@tonic-gate } 276*7c478bd9Sstevel@tonic-gate kmem_free(*bvppp, (count + 1) * sizeof (vnode_t *)); 277*7c478bd9Sstevel@tonic-gate *bvppp = NULL; 278*7c478bd9Sstevel@tonic-gate } 279*7c478bd9Sstevel@tonic-gate 280*7c478bd9Sstevel@tonic-gate static int 281*7c478bd9Sstevel@tonic-gate ufs_snap_find_candidates(void *snapid, struct ufsvfs *ufsvfsp, int chunksize) 282*7c478bd9Sstevel@tonic-gate { 283*7c478bd9Sstevel@tonic-gate struct fs *fs = ufsvfsp->vfs_fs; 284*7c478bd9Sstevel@tonic-gate struct buf *cgbp; /* cylinder group buffer */ 285*7c478bd9Sstevel@tonic-gate struct cg *cgp; /* cylinder group data */ 286*7c478bd9Sstevel@tonic-gate ulong_t cg; 287*7c478bd9Sstevel@tonic-gate ulong_t cgbase; 288*7c478bd9Sstevel@tonic-gate ulong_t chunk; 289*7c478bd9Sstevel@tonic-gate uchar_t *blksfree; 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate ulong_t curfrag; 292*7c478bd9Sstevel@tonic-gate int error = 0; 293*7c478bd9Sstevel@tonic-gate 294*7c478bd9Sstevel@tonic-gate /* 295*7c478bd9Sstevel@tonic-gate * read through each ufs cylinder group and fetch the fragment 296*7c478bd9Sstevel@tonic-gate * allocation bitmap. UFS indicates a fragment is allocated by 297*7c478bd9Sstevel@tonic-gate * a zero bit (not a one bit) in the fragment offset. 298*7c478bd9Sstevel@tonic-gate */ 299*7c478bd9Sstevel@tonic-gate cgbase = 0LL; 300*7c478bd9Sstevel@tonic-gate for (cg = 0; cg < fs->fs_ncg; cg++) { 301*7c478bd9Sstevel@tonic-gate /* read the cylinder group in */ 302*7c478bd9Sstevel@tonic-gate cgbp = BREAD(ufsvfsp->vfs_dev, 303*7c478bd9Sstevel@tonic-gate (daddr_t)fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize); 304*7c478bd9Sstevel@tonic-gate if ((error = geterror(cgbp)) != 0) { 305*7c478bd9Sstevel@tonic-gate brelse(cgbp); 306*7c478bd9Sstevel@tonic-gate goto errout; 307*7c478bd9Sstevel@tonic-gate } 308*7c478bd9Sstevel@tonic-gate cgp = cgbp->b_un.b_cg; 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate /* check the magic number */ 311*7c478bd9Sstevel@tonic-gate if (cgp->cg_magic != CG_MAGIC) { 312*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "ufs_snap_find_candidates: cg %lu " 313*7c478bd9Sstevel@tonic-gate "magic number (0x%x) does not match expected " 314*7c478bd9Sstevel@tonic-gate "magic number (0x%x)", cg, cgp->cg_magic, CG_MAGIC); 315*7c478bd9Sstevel@tonic-gate error = EIO; 316*7c478bd9Sstevel@tonic-gate goto errout; 317*7c478bd9Sstevel@tonic-gate } 318*7c478bd9Sstevel@tonic-gate 319*7c478bd9Sstevel@tonic-gate blksfree = cg_blksfree(cgp); 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate /* 322*7c478bd9Sstevel@tonic-gate * go through the allocation bitmap and set the 323*7c478bd9Sstevel@tonic-gate * corresponding bit in the candidate map. 324*7c478bd9Sstevel@tonic-gate */ 325*7c478bd9Sstevel@tonic-gate for (curfrag = 0; curfrag < cgp->cg_ndblk; curfrag++) { 326*7c478bd9Sstevel@tonic-gate if (isclr(blksfree, curfrag)) { 327*7c478bd9Sstevel@tonic-gate /* 328*7c478bd9Sstevel@tonic-gate * this assumes chunksize is a multiple of 329*7c478bd9Sstevel@tonic-gate * the fragment size 330*7c478bd9Sstevel@tonic-gate */ 331*7c478bd9Sstevel@tonic-gate chunk = (ulong_t)((cgbase + curfrag) / 332*7c478bd9Sstevel@tonic-gate (chunksize >> fs->fs_fshift)); 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate fssnap_set_candidate(snapid, chunk); 335*7c478bd9Sstevel@tonic-gate /* 336*7c478bd9Sstevel@tonic-gate * no need to scan the rest of this chunk since 337*7c478bd9Sstevel@tonic-gate * it is already marked, so skip to the next 338*7c478bd9Sstevel@tonic-gate */ 339*7c478bd9Sstevel@tonic-gate curfrag += ((chunksize >> fs->fs_fshift) - 340*7c478bd9Sstevel@tonic-gate ((cgbase + curfrag) % 341*7c478bd9Sstevel@tonic-gate (chunksize >> fs->fs_fshift))) - 1; 342*7c478bd9Sstevel@tonic-gate } 343*7c478bd9Sstevel@tonic-gate } 344*7c478bd9Sstevel@tonic-gate 345*7c478bd9Sstevel@tonic-gate cgbase += cgp->cg_ndblk; 346*7c478bd9Sstevel@tonic-gate ASSERT(cgbase <= fs->fs_size); 347*7c478bd9Sstevel@tonic-gate brelse(cgbp); 348*7c478bd9Sstevel@tonic-gate } /* cylinder group loop */ 349*7c478bd9Sstevel@tonic-gate 350*7c478bd9Sstevel@tonic-gate ASSERT(cgbase == fs->fs_size); 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate errout: 353*7c478bd9Sstevel@tonic-gate return (error); 354*7c478bd9Sstevel@tonic-gate } 355*7c478bd9Sstevel@tonic-gate 356*7c478bd9Sstevel@tonic-gate 357*7c478bd9Sstevel@tonic-gate int 358*7c478bd9Sstevel@tonic-gate ufs_snap_delete(struct vnode *vp, struct fiosnapdelete *fiosnapp, cred_t *cr) 359*7c478bd9Sstevel@tonic-gate { 360*7c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = VTOI(vp)->i_ufsvfs; 361*7c478bd9Sstevel@tonic-gate struct fs *fs = ufsvfsp->vfs_fs; 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate /* 364*7c478bd9Sstevel@tonic-gate * Initialize fields in the user's buffer 365*7c478bd9Sstevel@tonic-gate */ 366*7c478bd9Sstevel@tonic-gate fiosnapp->error = 0; 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate /* 369*7c478bd9Sstevel@tonic-gate * No snapshot exists, we're done. 370*7c478bd9Sstevel@tonic-gate */ 371*7c478bd9Sstevel@tonic-gate if (ufsvfsp->vfs_snapshot == NULL) 372*7c478bd9Sstevel@tonic-gate return (ENOENT); 373*7c478bd9Sstevel@tonic-gate 374*7c478bd9Sstevel@tonic-gate /* 375*7c478bd9Sstevel@tonic-gate * must have sufficient privileges. 376*7c478bd9Sstevel@tonic-gate */ 377*7c478bd9Sstevel@tonic-gate if (secpolicy_fs_config(cr, ufsvfsp->vfs_vfs) != 0) 378*7c478bd9Sstevel@tonic-gate return (EPERM); 379*7c478bd9Sstevel@tonic-gate 380*7c478bd9Sstevel@tonic-gate /* 381*7c478bd9Sstevel@tonic-gate * Readonly file system 382*7c478bd9Sstevel@tonic-gate */ 383*7c478bd9Sstevel@tonic-gate if (fs->fs_ronly) { 384*7c478bd9Sstevel@tonic-gate fiosnapp->error = FIOCOW_EREADONLY; 385*7c478bd9Sstevel@tonic-gate return (EROFS); 386*7c478bd9Sstevel@tonic-gate } 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate /* free the data structures and clear the vfs_snapshot field. */ 389*7c478bd9Sstevel@tonic-gate fiosnapp->snapshotnumber = fssnap_delete(&ufsvfsp->vfs_snapshot); 390*7c478bd9Sstevel@tonic-gate 391*7c478bd9Sstevel@tonic-gate if (fiosnapp->snapshotnumber == -1) 392*7c478bd9Sstevel@tonic-gate return (EINVAL); 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate return (0); 395*7c478bd9Sstevel@tonic-gate } 396