PageRenderTime 94ms CodeModel.GetById 40ms RepoModel.GetById 1ms app.codeStats 0ms

/sys/ufs/ffs/ffs_snapshot.c

https://bitbucket.org/gthummalapalle/minix
C | 2331 lines | 1743 code | 118 blank | 470 comment | 498 complexity | 27ec15d6707848c853fe2beb84891c55 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0, WTFPL, AGPL-1.0

Large files files are truncated, but you can click here to view the full file

  1. /* $NetBSD: ffs_snapshot.c,v 1.118 2011/10/07 09:35:06 hannken Exp $ */
  2. /*
  3. * Copyright 2000 Marshall Kirk McKusick. All Rights Reserved.
  4. *
  5. * Further information about snapshots can be obtained from:
  6. *
  7. * Marshall Kirk McKusick http://www.mckusick.com/softdep/
  8. * 1614 Oxford Street mckusick@mckusick.com
  9. * Berkeley, CA 94709-1608 +1-510-843-9542
  10. * USA
  11. *
  12. * Redistribution and use in source and binary forms, with or without
  13. * modification, are permitted provided that the following conditions
  14. * are met:
  15. *
  16. * 1. Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. * 2. Redistributions in binary form must reproduce the above copyright
  19. * notice, this list of conditions and the following disclaimer in the
  20. * documentation and/or other materials provided with the distribution.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY MARSHALL KIRK MCKUSICK ``AS IS'' AND ANY
  23. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  24. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  25. * DISCLAIMED. IN NO EVENT SHALL MARSHALL KIRK MCKUSICK BE LIABLE FOR
  26. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32. * SUCH DAMAGE.
  33. *
  34. * @(#)ffs_snapshot.c 8.11 (McKusick) 7/23/00
  35. *
  36. * from FreeBSD: ffs_snapshot.c,v 1.79 2004/02/13 02:02:06 kuriyama Exp
  37. */
  38. #include <sys/cdefs.h>
  39. __KERNEL_RCSID(0, "$NetBSD: ffs_snapshot.c,v 1.118 2011/10/07 09:35:06 hannken Exp $");
  40. #if defined(_KERNEL_OPT)
  41. #include "opt_ffs.h"
  42. #include "opt_quota.h"
  43. #endif
  44. #include <sys/param.h>
  45. #include <sys/kernel.h>
  46. #include <sys/systm.h>
  47. #include <sys/conf.h>
  48. #include <sys/buf.h>
  49. #include <sys/proc.h>
  50. #include <sys/namei.h>
  51. #include <sys/sched.h>
  52. #include <sys/stat.h>
  53. #include <sys/malloc.h>
  54. #include <sys/mount.h>
  55. #include <sys/resource.h>
  56. #include <sys/resourcevar.h>
  57. #include <sys/vnode.h>
  58. #include <sys/kauth.h>
  59. #include <sys/fstrans.h>
  60. #include <sys/wapbl.h>
  61. #include <miscfs/specfs/specdev.h>
  62. #include <ufs/ufs/quota.h>
  63. #include <ufs/ufs/ufsmount.h>
  64. #include <ufs/ufs/inode.h>
  65. #include <ufs/ufs/ufs_extern.h>
  66. #include <ufs/ufs/ufs_bswap.h>
  67. #include <ufs/ufs/ufs_wapbl.h>
  68. #include <ufs/ffs/fs.h>
  69. #include <ufs/ffs/ffs_extern.h>
  70. #include <uvm/uvm.h>
  71. struct snap_info {
  72. kmutex_t si_lock; /* Lock this snapinfo */
  73. kmutex_t si_snaplock; /* Snapshot vnode common lock */
  74. lwp_t *si_owner; /* Sanplock owner */
  75. TAILQ_HEAD(inodelst, inode) si_snapshots; /* List of active snapshots */
  76. daddr_t *si_snapblklist; /* Snapshot block hints list */
  77. uint32_t si_gen; /* Incremented on change */
  78. };
  79. #if !defined(FFS_NO_SNAPSHOT)
  80. typedef int (*acctfunc_t)
  81. (struct vnode *, void *, int, int, struct fs *, daddr_t, int);
  82. static int snapshot_setup(struct mount *, struct vnode *);
  83. static int snapshot_copyfs(struct mount *, struct vnode *, void **);
  84. static int snapshot_expunge(struct mount *, struct vnode *,
  85. struct fs *, daddr_t *, daddr_t **);
  86. static int snapshot_expunge_snap(struct mount *, struct vnode *,
  87. struct fs *, daddr_t);
  88. static int snapshot_writefs(struct mount *, struct vnode *, void *);
  89. static int cgaccount(struct vnode *, int, int *);
  90. static int cgaccount1(int, struct vnode *, void *, int);
  91. static int expunge(struct vnode *, struct inode *, struct fs *,
  92. acctfunc_t, int);
  93. static int indiracct(struct vnode *, struct vnode *, int, daddr_t,
  94. daddr_t, daddr_t, daddr_t, daddr_t, struct fs *, acctfunc_t, int);
  95. static int fullacct(struct vnode *, void *, int, int, struct fs *,
  96. daddr_t, int);
  97. static int snapacct(struct vnode *, void *, int, int, struct fs *,
  98. daddr_t, int);
  99. static int mapacct(struct vnode *, void *, int, int, struct fs *,
  100. daddr_t, int);
  101. #endif /* !defined(FFS_NO_SNAPSHOT) */
  102. static int ffs_copyonwrite(void *, struct buf *, bool);
  103. static int snapblkaddr(struct vnode *, daddr_t, daddr_t *);
  104. static int rwfsblk(struct vnode *, int, void *, daddr_t);
  105. static int syncsnap(struct vnode *);
  106. static int wrsnapblk(struct vnode *, void *, daddr_t);
  107. #if !defined(FFS_NO_SNAPSHOT)
  108. static int blocks_in_journal(struct fs *);
  109. #endif
  110. static inline bool is_active_snapshot(struct snap_info *, struct inode *);
  111. static inline daddr_t db_get(struct inode *, int);
  112. static inline void db_assign(struct inode *, int, daddr_t);
  113. static inline daddr_t ib_get(struct inode *, int);
  114. static inline void ib_assign(struct inode *, int, daddr_t);
  115. static inline daddr_t idb_get(struct inode *, void *, int);
  116. static inline void idb_assign(struct inode *, void *, int, daddr_t);
  117. #ifdef DEBUG
  118. static int snapdebug = 0;
  119. #endif
  120. int
  121. ffs_snapshot_init(struct ufsmount *ump)
  122. {
  123. struct snap_info *si;
  124. si = ump->um_snapinfo = kmem_alloc(sizeof(*si), KM_SLEEP);
  125. if (si == NULL)
  126. return ENOMEM;
  127. TAILQ_INIT(&si->si_snapshots);
  128. mutex_init(&si->si_lock, MUTEX_DEFAULT, IPL_NONE);
  129. mutex_init(&si->si_snaplock, MUTEX_DEFAULT, IPL_NONE);
  130. si->si_owner = NULL;
  131. si->si_gen = 0;
  132. si->si_snapblklist = NULL;
  133. return 0;
  134. }
  135. void
  136. ffs_snapshot_fini(struct ufsmount *ump)
  137. {
  138. struct snap_info *si;
  139. si = ump->um_snapinfo;
  140. ump->um_snapinfo = NULL;
  141. KASSERT(TAILQ_EMPTY(&si->si_snapshots));
  142. mutex_destroy(&si->si_lock);
  143. mutex_destroy(&si->si_snaplock);
  144. KASSERT(si->si_snapblklist == NULL);
  145. kmem_free(si, sizeof(*si));
  146. }
  147. /*
  148. * Create a snapshot file and initialize it for the filesystem.
  149. * Vnode is locked on entry and return.
  150. */
  151. int
  152. ffs_snapshot(struct mount *mp, struct vnode *vp, struct timespec *ctime)
  153. {
  154. #if defined(FFS_NO_SNAPSHOT)
  155. return EOPNOTSUPP;
  156. }
  157. #else /* defined(FFS_NO_SNAPSHOT) */
  158. bool suspended = false;
  159. int error, redo = 0, snaploc;
  160. void *sbbuf = NULL;
  161. daddr_t *snaplist = NULL, snaplistsize = 0;
  162. struct buf *bp, *nbp;
  163. struct fs *copy_fs = NULL;
  164. struct fs *fs = VFSTOUFS(mp)->um_fs;
  165. struct inode *ip = VTOI(vp);
  166. struct lwp *l = curlwp;
  167. struct snap_info *si = VFSTOUFS(mp)->um_snapinfo;
  168. struct timespec ts;
  169. struct timeval starttime;
  170. #ifdef DEBUG
  171. struct timeval endtime;
  172. #endif
  173. struct vnode *devvp = ip->i_devvp;
  174. /*
  175. * If the vnode already is a snapshot, return.
  176. */
  177. if ((VTOI(vp)->i_flags & SF_SNAPSHOT)) {
  178. if ((VTOI(vp)->i_flags & SF_SNAPINVAL))
  179. return EINVAL;
  180. if (ctime) {
  181. ctime->tv_sec = DIP(VTOI(vp), mtime);
  182. ctime->tv_nsec = DIP(VTOI(vp), mtimensec);
  183. }
  184. return 0;
  185. }
  186. /*
  187. * Check for free snapshot slot in the superblock.
  188. */
  189. for (snaploc = 0; snaploc < FSMAXSNAP; snaploc++)
  190. if (fs->fs_snapinum[snaploc] == 0)
  191. break;
  192. if (snaploc == FSMAXSNAP)
  193. return (ENOSPC);
  194. /*
  195. * Prepare the vnode to become a snapshot.
  196. */
  197. error = snapshot_setup(mp, vp);
  198. if (error)
  199. goto out;
  200. /*
  201. * Copy all the cylinder group maps. Although the
  202. * filesystem is still active, we hope that only a few
  203. * cylinder groups will change between now and when we
  204. * suspend operations. Thus, we will be able to quickly
  205. * touch up the few cylinder groups that changed during
  206. * the suspension period.
  207. */
  208. error = cgaccount(vp, 1, NULL);
  209. if (error)
  210. goto out;
  211. /*
  212. * snapshot is now valid
  213. */
  214. ip->i_flags &= ~SF_SNAPINVAL;
  215. DIP_ASSIGN(ip, flags, ip->i_flags);
  216. ip->i_flag |= IN_CHANGE | IN_UPDATE;
  217. /*
  218. * Ensure that the snapshot is completely on disk.
  219. * Since we have marked it as a snapshot it is safe to
  220. * unlock it as no process will be allowed to write to it.
  221. */
  222. error = VOP_FSYNC(vp, l->l_cred, FSYNC_WAIT, 0, 0);
  223. if (error)
  224. goto out;
  225. VOP_UNLOCK(vp);
  226. /*
  227. * All allocations are done, so we can now suspend the filesystem.
  228. */
  229. error = vfs_suspend(vp->v_mount, 0);
  230. vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  231. if (error)
  232. goto out;
  233. suspended = true;
  234. getmicrotime(&starttime);
  235. /*
  236. * First, copy all the cylinder group maps that have changed.
  237. */
  238. error = cgaccount(vp, 2, &redo);
  239. if (error)
  240. goto out;
  241. /*
  242. * Create a copy of the superblock and its summary information.
  243. */
  244. error = snapshot_copyfs(mp, vp, &sbbuf);
  245. copy_fs = (struct fs *)((char *)sbbuf + blkoff(fs, fs->fs_sblockloc));
  246. if (error)
  247. goto out;
  248. /*
  249. * Expunge unlinked files from our view.
  250. */
  251. error = snapshot_expunge(mp, vp, copy_fs, &snaplistsize, &snaplist);
  252. if (error)
  253. goto out;
  254. /*
  255. * Record snapshot inode. Since this is the newest snapshot,
  256. * it must be placed at the end of the list.
  257. */
  258. if (ip->i_nlink > 0)
  259. fs->fs_snapinum[snaploc] = ip->i_number;
  260. mutex_enter(&si->si_lock);
  261. if (is_active_snapshot(si, ip))
  262. panic("ffs_snapshot: %"PRIu64" already on list", ip->i_number);
  263. TAILQ_INSERT_TAIL(&si->si_snapshots, ip, i_nextsnap);
  264. if (TAILQ_FIRST(&si->si_snapshots) == ip) {
  265. /*
  266. * If this is the first snapshot on this filesystem, put the
  267. * preliminary list in place and establish the cow handler.
  268. */
  269. si->si_snapblklist = snaplist;
  270. fscow_establish(mp, ffs_copyonwrite, devvp);
  271. }
  272. si->si_gen++;
  273. mutex_exit(&si->si_lock);
  274. vp->v_vflag |= VV_SYSTEM;
  275. /*
  276. * Set the mtime to the time the snapshot has been taken.
  277. */
  278. TIMEVAL_TO_TIMESPEC(&starttime, &ts);
  279. if (ctime)
  280. *ctime = ts;
  281. DIP_ASSIGN(ip, mtime, ts.tv_sec);
  282. DIP_ASSIGN(ip, mtimensec, ts.tv_nsec);
  283. ip->i_flag |= IN_CHANGE | IN_UPDATE;
  284. /*
  285. * Copy allocation information from all snapshots and then
  286. * expunge them from our view.
  287. */
  288. error = snapshot_expunge_snap(mp, vp, copy_fs, snaplistsize);
  289. if (error)
  290. goto out;
  291. /*
  292. * Write the superblock and its summary information to the snapshot.
  293. */
  294. error = snapshot_writefs(mp, vp, sbbuf);
  295. if (error)
  296. goto out;
  297. /*
  298. * We're nearly done, ensure that the snapshot is completely on disk.
  299. */
  300. error = VOP_FSYNC(vp, l->l_cred, FSYNC_WAIT, 0, 0);
  301. if (error)
  302. goto out;
  303. /*
  304. * Invalidate and free all pages on the snapshot vnode.
  305. * We will read and write through the buffercache.
  306. */
  307. mutex_enter(vp->v_interlock);
  308. error = VOP_PUTPAGES(vp, 0, 0,
  309. PGO_ALLPAGES | PGO_CLEANIT | PGO_SYNCIO | PGO_FREE);
  310. if (error)
  311. goto out;
  312. /*
  313. * Invalidate short ( < fs_bsize ) buffers. We will always read
  314. * full size buffers later.
  315. */
  316. mutex_enter(&bufcache_lock);
  317. KASSERT(LIST_FIRST(&vp->v_dirtyblkhd) == NULL);
  318. for (bp = LIST_FIRST(&vp->v_cleanblkhd); bp; bp = nbp) {
  319. nbp = LIST_NEXT(bp, b_vnbufs);
  320. KASSERT((bp->b_cflags & BC_BUSY) == 0);
  321. if (bp->b_bcount < fs->fs_bsize) {
  322. bp->b_cflags |= BC_BUSY;
  323. brelsel(bp, BC_INVAL | BC_VFLUSH);
  324. }
  325. }
  326. mutex_exit(&bufcache_lock);
  327. out:
  328. if (sbbuf != NULL) {
  329. free(copy_fs->fs_csp, M_UFSMNT);
  330. free(sbbuf, M_UFSMNT);
  331. }
  332. if (fs->fs_active != NULL) {
  333. free(fs->fs_active, M_DEVBUF);
  334. fs->fs_active = NULL;
  335. }
  336. mutex_enter(&si->si_lock);
  337. if (snaplist != NULL) {
  338. if (si->si_snapblklist == snaplist)
  339. si->si_snapblklist = NULL;
  340. free(snaplist, M_UFSMNT);
  341. }
  342. if (error) {
  343. fs->fs_snapinum[snaploc] = 0;
  344. } else {
  345. /*
  346. * As this is the newest list, it is the most inclusive, so
  347. * should replace the previous list.
  348. */
  349. si->si_snapblklist = ip->i_snapblklist;
  350. }
  351. si->si_gen++;
  352. mutex_exit(&si->si_lock);
  353. if (suspended) {
  354. VOP_UNLOCK(vp);
  355. vfs_resume(vp->v_mount);
  356. vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  357. #ifdef DEBUG
  358. getmicrotime(&endtime);
  359. timersub(&endtime, &starttime, &endtime);
  360. printf("%s: suspended %lld.%03d sec, redo %d of %d\n",
  361. mp->mnt_stat.f_mntonname, (long long)endtime.tv_sec,
  362. endtime.tv_usec / 1000, redo, fs->fs_ncg);
  363. #endif
  364. }
  365. if (error) {
  366. if (!UFS_WAPBL_BEGIN(mp)) {
  367. (void) ffs_truncate(vp, (off_t)0, 0, NOCRED);
  368. UFS_WAPBL_END(mp);
  369. }
  370. } else if (ip->i_nlink > 0)
  371. vref(vp);
  372. return (error);
  373. }
  374. /*
  375. * Prepare vnode to become a snapshot.
  376. */
  377. static int
  378. snapshot_setup(struct mount *mp, struct vnode *vp)
  379. {
  380. int error, n, len, loc, cg;
  381. daddr_t blkno, numblks;
  382. struct buf *ibp, *nbp;
  383. struct fs *fs = VFSTOUFS(mp)->um_fs;
  384. struct lwp *l = curlwp;
  385. const int wbreak = blocks_in_journal(fs)/8;
  386. struct inode *ip = VTOI(vp);
  387. /*
  388. * Check mount, exclusive reference and owner.
  389. */
  390. if (vp->v_mount != mp)
  391. return EXDEV;
  392. if (vp->v_usecount != 1 || vp->v_writecount != 0)
  393. return EBUSY;
  394. if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
  395. NULL) != 0 &&
  396. VTOI(vp)->i_uid != kauth_cred_geteuid(l->l_cred))
  397. return EACCES;
  398. if (vp->v_size != 0) {
  399. error = ffs_truncate(vp, 0, 0, NOCRED);
  400. if (error)
  401. return error;
  402. }
  403. /* Change inode to snapshot type file. */
  404. error = UFS_WAPBL_BEGIN(mp);
  405. if (error)
  406. return error;
  407. #if defined(QUOTA) || defined(QUOTA2)
  408. /* shapshot inodes are not accounted in quotas */
  409. chkiq(ip, -1, l->l_cred, 0);
  410. #endif
  411. ip->i_flags |= (SF_SNAPSHOT | SF_SNAPINVAL);
  412. DIP_ASSIGN(ip, flags, ip->i_flags);
  413. ip->i_flag |= IN_CHANGE | IN_UPDATE;
  414. ffs_update(vp, NULL, NULL, UPDATE_WAIT);
  415. UFS_WAPBL_END(mp);
  416. KASSERT(ip->i_flags & SF_SNAPSHOT);
  417. /*
  418. * Write an empty list of preallocated blocks to the end of
  419. * the snapshot to set size to at least that of the filesystem.
  420. */
  421. numblks = howmany(fs->fs_size, fs->fs_frag);
  422. blkno = 1;
  423. blkno = ufs_rw64(blkno, UFS_FSNEEDSWAP(fs));
  424. error = vn_rdwr(UIO_WRITE, vp,
  425. (void *)&blkno, sizeof(blkno), lblktosize(fs, (off_t)numblks),
  426. UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, l->l_cred, NULL, NULL);
  427. if (error)
  428. return error;
  429. /*
  430. * Preallocate critical data structures so that we can copy
  431. * them in without further allocation after we suspend all
  432. * operations on the filesystem. We would like to just release
  433. * the allocated buffers without writing them since they will
  434. * be filled in below once we are ready to go, but this upsets
  435. * the soft update code, so we go ahead and write the new buffers.
  436. *
  437. * Allocate all indirect blocks and mark all of them as not
  438. * needing to be copied.
  439. */
  440. error = UFS_WAPBL_BEGIN(mp);
  441. if (error)
  442. return error;
  443. for (blkno = NDADDR, n = 0; blkno < numblks; blkno += NINDIR(fs)) {
  444. error = ffs_balloc(vp, lblktosize(fs, (off_t)blkno),
  445. fs->fs_bsize, l->l_cred, B_METAONLY, &ibp);
  446. if (error)
  447. goto out;
  448. brelse(ibp, 0);
  449. if (wbreak > 0 && (++n % wbreak) == 0) {
  450. UFS_WAPBL_END(mp);
  451. error = UFS_WAPBL_BEGIN(mp);
  452. if (error)
  453. return error;
  454. }
  455. }
  456. /*
  457. * Allocate copies for the superblock and its summary information.
  458. */
  459. error = ffs_balloc(vp, fs->fs_sblockloc, fs->fs_sbsize, l->l_cred,
  460. 0, &nbp);
  461. if (error)
  462. goto out;
  463. bawrite(nbp);
  464. blkno = fragstoblks(fs, fs->fs_csaddr);
  465. len = howmany(fs->fs_cssize, fs->fs_bsize);
  466. for (loc = 0; loc < len; loc++) {
  467. error = ffs_balloc(vp, lblktosize(fs, (off_t)(blkno + loc)),
  468. fs->fs_bsize, l->l_cred, 0, &nbp);
  469. if (error)
  470. goto out;
  471. bawrite(nbp);
  472. if (wbreak > 0 && (++n % wbreak) == 0) {
  473. UFS_WAPBL_END(mp);
  474. error = UFS_WAPBL_BEGIN(mp);
  475. if (error)
  476. return error;
  477. }
  478. }
  479. /*
  480. * Allocate all cylinder group blocks.
  481. */
  482. for (cg = 0; cg < fs->fs_ncg; cg++) {
  483. error = ffs_balloc(vp, lfragtosize(fs, cgtod(fs, cg)),
  484. fs->fs_bsize, l->l_cred, 0, &nbp);
  485. if (error)
  486. goto out;
  487. bawrite(nbp);
  488. if (wbreak > 0 && (++n % wbreak) == 0) {
  489. UFS_WAPBL_END(mp);
  490. error = UFS_WAPBL_BEGIN(mp);
  491. if (error)
  492. return error;
  493. }
  494. }
  495. out:
  496. UFS_WAPBL_END(mp);
  497. return error;
  498. }
  499. /*
  500. * Create a copy of the superblock and its summary information.
  501. * It is up to the caller to free copyfs and copy_fs->fs_csp.
  502. */
  503. static int
  504. snapshot_copyfs(struct mount *mp, struct vnode *vp, void **sbbuf)
  505. {
  506. int error, i, len, loc, size;
  507. void *space;
  508. int32_t *lp;
  509. struct buf *bp;
  510. struct fs *copyfs, *fs = VFSTOUFS(mp)->um_fs;
  511. struct lwp *l = curlwp;
  512. struct vnode *devvp = VTOI(vp)->i_devvp;
  513. /*
  514. * Grab a copy of the superblock and its summary information.
  515. * We delay writing it until the suspension is released below.
  516. */
  517. *sbbuf = malloc(fs->fs_bsize, M_UFSMNT, M_WAITOK);
  518. loc = blkoff(fs, fs->fs_sblockloc);
  519. if (loc > 0)
  520. memset(*sbbuf, 0, loc);
  521. copyfs = (struct fs *)((char *)(*sbbuf) + loc);
  522. memcpy(copyfs, fs, fs->fs_sbsize);
  523. size = fs->fs_bsize < SBLOCKSIZE ? fs->fs_bsize : SBLOCKSIZE;
  524. if (fs->fs_sbsize < size)
  525. memset((char *)(*sbbuf) + loc + fs->fs_sbsize, 0,
  526. size - fs->fs_sbsize);
  527. size = blkroundup(fs, fs->fs_cssize);
  528. if (fs->fs_contigsumsize > 0)
  529. size += fs->fs_ncg * sizeof(int32_t);
  530. space = malloc(size, M_UFSMNT, M_WAITOK);
  531. copyfs->fs_csp = space;
  532. memcpy(copyfs->fs_csp, fs->fs_csp, fs->fs_cssize);
  533. space = (char *)space + fs->fs_cssize;
  534. loc = howmany(fs->fs_cssize, fs->fs_fsize);
  535. i = fs->fs_frag - loc % fs->fs_frag;
  536. len = (i == fs->fs_frag) ? 0 : i * fs->fs_fsize;
  537. if (len > 0) {
  538. if ((error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + loc),
  539. len, l->l_cred, 0, &bp)) != 0) {
  540. brelse(bp, 0);
  541. free(copyfs->fs_csp, M_UFSMNT);
  542. free(*sbbuf, M_UFSMNT);
  543. *sbbuf = NULL;
  544. return error;
  545. }
  546. memcpy(space, bp->b_data, (u_int)len);
  547. space = (char *)space + len;
  548. brelse(bp, BC_INVAL | BC_NOCACHE);
  549. }
  550. if (fs->fs_contigsumsize > 0) {
  551. copyfs->fs_maxcluster = lp = space;
  552. for (i = 0; i < fs->fs_ncg; i++)
  553. *lp++ = fs->fs_contigsumsize;
  554. }
  555. if (mp->mnt_wapbl)
  556. copyfs->fs_flags &= ~FS_DOWAPBL;
  557. return 0;
  558. }
  559. /*
  560. * We must check for active files that have been unlinked (e.g., with a zero
  561. * link count). We have to expunge all trace of these files from the snapshot
  562. * so that they are not reclaimed prematurely by fsck or unnecessarily dumped.
  563. * Note that we skip unlinked snapshot files as they will be handled separately.
  564. * Calculate the snapshot list size and create a preliminary list.
  565. */
  566. static int
  567. snapshot_expunge(struct mount *mp, struct vnode *vp, struct fs *copy_fs,
  568. daddr_t *snaplistsize, daddr_t **snaplist)
  569. {
  570. int cg, error = 0, len, loc;
  571. daddr_t blkno, *blkp;
  572. struct fs *fs = VFSTOUFS(mp)->um_fs;
  573. struct inode *xp;
  574. struct lwp *l = curlwp;
  575. struct vattr vat;
  576. struct vnode *logvp = NULL, *mvp = NULL, *xvp;
  577. *snaplist = NULL;
  578. /*
  579. * Get the log inode if any.
  580. */
  581. if ((fs->fs_flags & FS_DOWAPBL) &&
  582. fs->fs_journal_location == UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM) {
  583. error = VFS_VGET(mp,
  584. fs->fs_journallocs[UFS_WAPBL_INFS_INO], &logvp);
  585. if (error)
  586. goto out;
  587. }
  588. /*
  589. * Allocate a marker vnode.
  590. */
  591. mvp = vnalloc(mp);
  592. /*
  593. * We also calculate the needed size for the snapshot list.
  594. */
  595. *snaplistsize = fs->fs_ncg + howmany(fs->fs_cssize, fs->fs_bsize) +
  596. FSMAXSNAP + 1 /* superblock */ + 1 /* last block */ + 1 /* size */;
  597. mutex_enter(&mntvnode_lock);
  598. /*
  599. * NOTE: not using the TAILQ_FOREACH here since in this loop vgone()
  600. * and vclean() can be called indirectly
  601. */
  602. for (xvp = TAILQ_FIRST(&mp->mnt_vnodelist); xvp; xvp = vunmark(mvp)) {
  603. vmark(mvp, xvp);
  604. /*
  605. * Make sure this vnode wasn't reclaimed in getnewvnode().
  606. * Start over if it has (it won't be on the list anymore).
  607. */
  608. if (xvp->v_mount != mp || vismarker(xvp))
  609. continue;
  610. mutex_enter(xvp->v_interlock);
  611. if ((xvp->v_iflag & VI_XLOCK) ||
  612. xvp->v_usecount == 0 || xvp->v_type == VNON ||
  613. VTOI(xvp) == NULL ||
  614. (VTOI(xvp)->i_flags & SF_SNAPSHOT)) {
  615. mutex_exit(xvp->v_interlock);
  616. continue;
  617. }
  618. mutex_exit(&mntvnode_lock);
  619. /*
  620. * XXXAD should increase vnode ref count to prevent it
  621. * disappearing or being recycled.
  622. */
  623. mutex_exit(xvp->v_interlock);
  624. #ifdef DEBUG
  625. if (snapdebug)
  626. vprint("ffs_snapshot: busy vnode", xvp);
  627. #endif
  628. xp = VTOI(xvp);
  629. if (xvp != logvp) {
  630. if (VOP_GETATTR(xvp, &vat, l->l_cred) == 0 &&
  631. vat.va_nlink > 0) {
  632. mutex_enter(&mntvnode_lock);
  633. continue;
  634. }
  635. if (ffs_checkfreefile(copy_fs, vp, xp->i_number)) {
  636. mutex_enter(&mntvnode_lock);
  637. continue;
  638. }
  639. }
  640. /*
  641. * If there is a fragment, clear it here.
  642. */
  643. blkno = 0;
  644. loc = howmany(xp->i_size, fs->fs_bsize) - 1;
  645. if (loc < NDADDR) {
  646. len = fragroundup(fs, blkoff(fs, xp->i_size));
  647. if (len > 0 && len < fs->fs_bsize) {
  648. error = UFS_WAPBL_BEGIN(mp);
  649. if (error) {
  650. (void)vunmark(mvp);
  651. goto out;
  652. }
  653. ffs_blkfree_snap(copy_fs, vp, db_get(xp, loc),
  654. len, xp->i_number);
  655. blkno = db_get(xp, loc);
  656. db_assign(xp, loc, 0);
  657. UFS_WAPBL_END(mp);
  658. }
  659. }
  660. *snaplistsize += 1;
  661. error = expunge(vp, xp, copy_fs, fullacct, BLK_NOCOPY);
  662. if (blkno)
  663. db_assign(xp, loc, blkno);
  664. if (!error) {
  665. error = UFS_WAPBL_BEGIN(mp);
  666. if (!error) {
  667. error = ffs_freefile_snap(copy_fs, vp,
  668. xp->i_number, xp->i_mode);
  669. UFS_WAPBL_END(mp);
  670. }
  671. }
  672. if (error) {
  673. (void)vunmark(mvp);
  674. goto out;
  675. }
  676. mutex_enter(&mntvnode_lock);
  677. }
  678. mutex_exit(&mntvnode_lock);
  679. /*
  680. * Create a preliminary list of preallocated snapshot blocks.
  681. */
  682. *snaplist = malloc(*snaplistsize * sizeof(daddr_t), M_UFSMNT, M_WAITOK);
  683. blkp = &(*snaplist)[1];
  684. *blkp++ = lblkno(fs, fs->fs_sblockloc);
  685. blkno = fragstoblks(fs, fs->fs_csaddr);
  686. for (cg = 0; cg < fs->fs_ncg; cg++) {
  687. if (fragstoblks(fs, cgtod(fs, cg)) > blkno)
  688. break;
  689. *blkp++ = fragstoblks(fs, cgtod(fs, cg));
  690. }
  691. len = howmany(fs->fs_cssize, fs->fs_bsize);
  692. for (loc = 0; loc < len; loc++)
  693. *blkp++ = blkno + loc;
  694. for (; cg < fs->fs_ncg; cg++)
  695. *blkp++ = fragstoblks(fs, cgtod(fs, cg));
  696. (*snaplist)[0] = blkp - &(*snaplist)[0];
  697. out:
  698. if (mvp != NULL)
  699. vnfree(mvp);
  700. if (logvp != NULL)
  701. vput(logvp);
  702. if (error && *snaplist != NULL) {
  703. free(*snaplist, M_UFSMNT);
  704. *snaplist = NULL;
  705. }
  706. return error;
  707. }
  708. /*
  709. * Copy allocation information from all the snapshots in this snapshot and
  710. * then expunge them from its view. Also, collect the list of allocated
  711. * blocks in i_snapblklist.
  712. */
  713. static int
  714. snapshot_expunge_snap(struct mount *mp, struct vnode *vp,
  715. struct fs *copy_fs, daddr_t snaplistsize)
  716. {
  717. int error = 0, i;
  718. daddr_t numblks, *snaplist = NULL;
  719. struct fs *fs = VFSTOUFS(mp)->um_fs;
  720. struct inode *ip = VTOI(vp), *xp;
  721. struct lwp *l = curlwp;
  722. struct snap_info *si = VFSTOUFS(mp)->um_snapinfo;
  723. TAILQ_FOREACH(xp, &si->si_snapshots, i_nextsnap) {
  724. if (xp != ip) {
  725. error = expunge(vp, xp, fs, snapacct, BLK_SNAP);
  726. if (error)
  727. break;
  728. }
  729. if (xp->i_nlink != 0)
  730. continue;
  731. error = UFS_WAPBL_BEGIN(mp);
  732. if (error)
  733. break;
  734. error = ffs_freefile_snap(copy_fs, vp, xp->i_number, xp->i_mode);
  735. UFS_WAPBL_END(mp);
  736. if (error)
  737. break;
  738. }
  739. if (error)
  740. goto out;
  741. /*
  742. * Allocate space for the full list of preallocated snapshot blocks.
  743. */
  744. snaplist = malloc(snaplistsize * sizeof(daddr_t), M_UFSMNT, M_WAITOK);
  745. ip->i_snapblklist = &snaplist[1];
  746. /*
  747. * Expunge the blocks used by the snapshots from the set of
  748. * blocks marked as used in the snapshot bitmaps. Also, collect
  749. * the list of allocated blocks in i_snapblklist.
  750. */
  751. error = expunge(vp, ip, copy_fs, mapacct, BLK_SNAP);
  752. if (error)
  753. goto out;
  754. if (snaplistsize < ip->i_snapblklist - snaplist)
  755. panic("ffs_snapshot: list too small");
  756. snaplistsize = ip->i_snapblklist - snaplist;
  757. snaplist[0] = snaplistsize;
  758. ip->i_snapblklist = &snaplist[0];
  759. /*
  760. * Write out the list of allocated blocks to the end of the snapshot.
  761. */
  762. numblks = howmany(fs->fs_size, fs->fs_frag);
  763. for (i = 0; i < snaplistsize; i++)
  764. snaplist[i] = ufs_rw64(snaplist[i], UFS_FSNEEDSWAP(fs));
  765. error = vn_rdwr(UIO_WRITE, vp, (void *)snaplist,
  766. snaplistsize * sizeof(daddr_t), lblktosize(fs, (off_t)numblks),
  767. UIO_SYSSPACE, IO_NODELOCKED | IO_UNIT, l->l_cred, NULL, NULL);
  768. for (i = 0; i < snaplistsize; i++)
  769. snaplist[i] = ufs_rw64(snaplist[i], UFS_FSNEEDSWAP(fs));
  770. out:
  771. if (error && snaplist != NULL) {
  772. free(snaplist, M_UFSMNT);
  773. ip->i_snapblklist = NULL;
  774. }
  775. return error;
  776. }
  777. /*
  778. * Write the superblock and its summary information to the snapshot.
  779. * Make sure, the first NDADDR blocks get copied to the snapshot.
  780. */
  781. static int
  782. snapshot_writefs(struct mount *mp, struct vnode *vp, void *sbbuf)
  783. {
  784. int error, len, loc;
  785. void *space;
  786. daddr_t blkno;
  787. struct buf *bp;
  788. struct fs *copyfs, *fs = VFSTOUFS(mp)->um_fs;
  789. struct inode *ip = VTOI(vp);
  790. struct lwp *l = curlwp;
  791. copyfs = (struct fs *)((char *)sbbuf + blkoff(fs, fs->fs_sblockloc));
  792. /*
  793. * Write the superblock and its summary information
  794. * to the snapshot.
  795. */
  796. blkno = fragstoblks(fs, fs->fs_csaddr);
  797. len = howmany(fs->fs_cssize, fs->fs_bsize);
  798. space = copyfs->fs_csp;
  799. #ifdef FFS_EI
  800. if (UFS_FSNEEDSWAP(fs)) {
  801. ffs_sb_swap(copyfs, copyfs);
  802. ffs_csum_swap(space, space, fs->fs_cssize);
  803. }
  804. #endif
  805. error = UFS_WAPBL_BEGIN(mp);
  806. if (error)
  807. return error;
  808. for (loc = 0; loc < len; loc++) {
  809. error = bread(vp, blkno + loc, fs->fs_bsize, l->l_cred,
  810. B_MODIFY, &bp);
  811. if (error) {
  812. brelse(bp, 0);
  813. break;
  814. }
  815. memcpy(bp->b_data, space, fs->fs_bsize);
  816. space = (char *)space + fs->fs_bsize;
  817. bawrite(bp);
  818. }
  819. if (error)
  820. goto out;
  821. error = bread(vp, lblkno(fs, fs->fs_sblockloc),
  822. fs->fs_bsize, l->l_cred, B_MODIFY, &bp);
  823. if (error) {
  824. brelse(bp, 0);
  825. goto out;
  826. } else {
  827. memcpy(bp->b_data, sbbuf, fs->fs_bsize);
  828. bawrite(bp);
  829. }
  830. /*
  831. * Copy the first NDADDR blocks to the snapshot so ffs_copyonwrite()
  832. * and ffs_snapblkfree() will always work on indirect blocks.
  833. */
  834. for (loc = 0; loc < NDADDR; loc++) {
  835. if (db_get(ip, loc) != 0)
  836. continue;
  837. error = ffs_balloc(vp, lblktosize(fs, (off_t)loc),
  838. fs->fs_bsize, l->l_cred, 0, &bp);
  839. if (error)
  840. break;
  841. error = rwfsblk(vp, B_READ, bp->b_data, loc);
  842. if (error) {
  843. brelse(bp, 0);
  844. break;
  845. }
  846. bawrite(bp);
  847. }
  848. out:
  849. UFS_WAPBL_END(mp);
  850. return error;
  851. }
  852. /*
  853. * Copy all cylinder group maps.
  854. */
  855. static int
  856. cgaccount(struct vnode *vp, int passno, int *redo)
  857. {
  858. int cg, error = 0;
  859. struct buf *nbp;
  860. struct fs *fs = VTOI(vp)->i_fs;
  861. if (redo != NULL)
  862. *redo = 0;
  863. if (passno == 1)
  864. fs->fs_active = malloc(howmany(fs->fs_ncg, NBBY),
  865. M_DEVBUF, M_WAITOK | M_ZERO);
  866. for (cg = 0; cg < fs->fs_ncg; cg++) {
  867. if (passno == 2 && ACTIVECG_ISSET(fs, cg))
  868. continue;
  869. if (redo != NULL)
  870. *redo += 1;
  871. error = UFS_WAPBL_BEGIN(vp->v_mount);
  872. if (error)
  873. return error;
  874. error = ffs_balloc(vp, lfragtosize(fs, cgtod(fs, cg)),
  875. fs->fs_bsize, curlwp->l_cred, 0, &nbp);
  876. if (error) {
  877. UFS_WAPBL_END(vp->v_mount);
  878. break;
  879. }
  880. error = cgaccount1(cg, vp, nbp->b_data, passno);
  881. bawrite(nbp);
  882. UFS_WAPBL_END(vp->v_mount);
  883. if (error)
  884. break;
  885. }
  886. return error;
  887. }
  888. /*
  889. * Copy a cylinder group map. All the unallocated blocks are marked
  890. * BLK_NOCOPY so that the snapshot knows that it need not copy them
  891. * if they are later written. If passno is one, then this is a first
  892. * pass, so only setting needs to be done. If passno is 2, then this
  893. * is a revision to a previous pass which must be undone as the
  894. * replacement pass is done.
  895. */
  896. static int
  897. cgaccount1(int cg, struct vnode *vp, void *data, int passno)
  898. {
  899. struct buf *bp, *ibp;
  900. struct inode *ip;
  901. struct cg *cgp;
  902. struct fs *fs;
  903. struct lwp *l = curlwp;
  904. daddr_t base, numblks;
  905. int error, len, loc, ns, indiroff;
  906. ip = VTOI(vp);
  907. fs = ip->i_fs;
  908. ns = UFS_FSNEEDSWAP(fs);
  909. error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
  910. (int)fs->fs_cgsize, l->l_cred, 0, &bp);
  911. if (error) {
  912. brelse(bp, 0);
  913. return (error);
  914. }
  915. cgp = (struct cg *)bp->b_data;
  916. if (!cg_chkmagic(cgp, ns)) {
  917. brelse(bp, 0);
  918. return (EIO);
  919. }
  920. ACTIVECG_SET(fs, cg);
  921. memcpy(data, bp->b_data, fs->fs_cgsize);
  922. brelse(bp, 0);
  923. if (fs->fs_cgsize < fs->fs_bsize)
  924. memset((char *)data + fs->fs_cgsize, 0,
  925. fs->fs_bsize - fs->fs_cgsize);
  926. numblks = howmany(fs->fs_size, fs->fs_frag);
  927. len = howmany(fs->fs_fpg, fs->fs_frag);
  928. base = cg * fs->fs_fpg / fs->fs_frag;
  929. if (base + len >= numblks)
  930. len = numblks - base - 1;
  931. loc = 0;
  932. if (base < NDADDR) {
  933. for ( ; loc < NDADDR; loc++) {
  934. if (ffs_isblock(fs, cg_blksfree(cgp, ns), loc))
  935. db_assign(ip, loc, BLK_NOCOPY);
  936. else if (db_get(ip, loc) == BLK_NOCOPY) {
  937. if (passno == 2)
  938. db_assign(ip, loc, 0);
  939. else if (passno == 1)
  940. panic("ffs_snapshot: lost direct block");
  941. }
  942. }
  943. }
  944. if ((error = ffs_balloc(vp, lblktosize(fs, (off_t)(base + loc)),
  945. fs->fs_bsize, l->l_cred, B_METAONLY, &ibp)) != 0)
  946. return (error);
  947. indiroff = (base + loc - NDADDR) % NINDIR(fs);
  948. for ( ; loc < len; loc++, indiroff++) {
  949. if (indiroff >= NINDIR(fs)) {
  950. bawrite(ibp);
  951. if ((error = ffs_balloc(vp,
  952. lblktosize(fs, (off_t)(base + loc)),
  953. fs->fs_bsize, l->l_cred, B_METAONLY, &ibp)) != 0)
  954. return (error);
  955. indiroff = 0;
  956. }
  957. if (ffs_isblock(fs, cg_blksfree(cgp, ns), loc))
  958. idb_assign(ip, ibp->b_data, indiroff, BLK_NOCOPY);
  959. else if (idb_get(ip, ibp->b_data, indiroff) == BLK_NOCOPY) {
  960. if (passno == 2)
  961. idb_assign(ip, ibp->b_data, indiroff, 0);
  962. else if (passno == 1)
  963. panic("ffs_snapshot: lost indirect block");
  964. }
  965. }
  966. bdwrite(ibp);
  967. return (0);
  968. }
  969. /*
  970. * Before expunging a snapshot inode, note all the
  971. * blocks that it claims with BLK_SNAP so that fsck will
  972. * be able to account for those blocks properly and so
  973. * that this snapshot knows that it need not copy them
  974. * if the other snapshot holding them is freed.
  975. */
  976. static int
  977. expunge(struct vnode *snapvp, struct inode *cancelip, struct fs *fs,
  978. acctfunc_t acctfunc, int expungetype)
  979. {
  980. int i, error, ns;
  981. daddr_t lbn, rlbn;
  982. daddr_t len, blkno, numblks, blksperindir;
  983. struct ufs1_dinode *dip1;
  984. struct ufs2_dinode *dip2;
  985. struct lwp *l = curlwp;
  986. void *bap;
  987. struct buf *bp;
  988. struct mount *mp;
  989. ns = UFS_FSNEEDSWAP(fs);
  990. mp = snapvp->v_mount;
  991. error = UFS_WAPBL_BEGIN(mp);
  992. if (error)
  993. return error;
  994. /*
  995. * Prepare to expunge the inode. If its inode block has not
  996. * yet been copied, then allocate and fill the copy.
  997. */
  998. lbn = fragstoblks(fs, ino_to_fsba(fs, cancelip->i_number));
  999. error = snapblkaddr(snapvp, lbn, &blkno);
  1000. if (error)
  1001. return error;
  1002. if (blkno != 0) {
  1003. error = bread(snapvp, lbn, fs->fs_bsize, l->l_cred,
  1004. B_MODIFY, &bp);
  1005. } else {
  1006. error = ffs_balloc(snapvp, lblktosize(fs, (off_t)lbn),
  1007. fs->fs_bsize, l->l_cred, 0, &bp);
  1008. if (! error)
  1009. error = rwfsblk(snapvp, B_READ, bp->b_data, lbn);
  1010. }
  1011. if (error) {
  1012. UFS_WAPBL_END(mp);
  1013. return error;
  1014. }
  1015. /*
  1016. * Set a snapshot inode to be a zero length file, regular files
  1017. * or unlinked snapshots to be completely unallocated.
  1018. */
  1019. if (fs->fs_magic == FS_UFS1_MAGIC) {
  1020. dip1 = (struct ufs1_dinode *)bp->b_data +
  1021. ino_to_fsbo(fs, cancelip->i_number);
  1022. if (cancelip->i_flags & SF_SNAPSHOT) {
  1023. dip1->di_flags =
  1024. ufs_rw32(ufs_rw32(dip1->di_flags, ns) |
  1025. SF_SNAPINVAL, ns);
  1026. }
  1027. if (expungetype == BLK_NOCOPY || cancelip->i_nlink == 0)
  1028. dip1->di_mode = 0;
  1029. dip1->di_size = 0;
  1030. dip1->di_blocks = 0;
  1031. memset(&dip1->di_db[0], 0, (NDADDR + NIADDR) * sizeof(int32_t));
  1032. } else {
  1033. dip2 = (struct ufs2_dinode *)bp->b_data +
  1034. ino_to_fsbo(fs, cancelip->i_number);
  1035. if (cancelip->i_flags & SF_SNAPSHOT) {
  1036. dip2->di_flags =
  1037. ufs_rw32(ufs_rw32(dip2->di_flags, ns) |
  1038. SF_SNAPINVAL, ns);
  1039. }
  1040. if (expungetype == BLK_NOCOPY || cancelip->i_nlink == 0)
  1041. dip2->di_mode = 0;
  1042. dip2->di_size = 0;
  1043. dip2->di_blocks = 0;
  1044. memset(&dip2->di_db[0], 0, (NDADDR + NIADDR) * sizeof(int64_t));
  1045. }
  1046. bdwrite(bp);
  1047. UFS_WAPBL_END(mp);
  1048. /*
  1049. * Now go through and expunge all the blocks in the file
  1050. * using the function requested.
  1051. */
  1052. numblks = howmany(cancelip->i_size, fs->fs_bsize);
  1053. if (fs->fs_magic == FS_UFS1_MAGIC)
  1054. bap = &cancelip->i_ffs1_db[0];
  1055. else
  1056. bap = &cancelip->i_ffs2_db[0];
  1057. error = (*acctfunc)(snapvp, bap, 0, NDADDR, fs, 0, expungetype);
  1058. if (error)
  1059. return (error);
  1060. if (fs->fs_magic == FS_UFS1_MAGIC)
  1061. bap = &cancelip->i_ffs1_ib[0];
  1062. else
  1063. bap = &cancelip->i_ffs2_ib[0];
  1064. error = (*acctfunc)(snapvp, bap, 0, NIADDR, fs, -1, expungetype);
  1065. if (error)
  1066. return (error);
  1067. blksperindir = 1;
  1068. lbn = -NDADDR;
  1069. len = numblks - NDADDR;
  1070. rlbn = NDADDR;
  1071. for (i = 0; len > 0 && i < NIADDR; i++) {
  1072. error = indiracct(snapvp, ITOV(cancelip), i,
  1073. ib_get(cancelip, i), lbn, rlbn, len,
  1074. blksperindir, fs, acctfunc, expungetype);
  1075. if (error)
  1076. return (error);
  1077. blksperindir *= NINDIR(fs);
  1078. lbn -= blksperindir + 1;
  1079. len -= blksperindir;
  1080. rlbn += blksperindir;
  1081. }
  1082. return (0);
  1083. }
  1084. /*
  1085. * Descend an indirect block chain for vnode cancelvp accounting for all
  1086. * its indirect blocks in snapvp.
  1087. */
  1088. static int
  1089. indiracct(struct vnode *snapvp, struct vnode *cancelvp, int level,
  1090. daddr_t blkno, daddr_t lbn, daddr_t rlbn, daddr_t remblks,
  1091. daddr_t blksperindir, struct fs *fs, acctfunc_t acctfunc, int expungetype)
  1092. {
  1093. int error, num, i;
  1094. daddr_t subblksperindir;
  1095. struct indir indirs[NIADDR + 2];
  1096. daddr_t last;
  1097. void *bap;
  1098. struct buf *bp;
  1099. if (blkno == 0) {
  1100. if (expungetype == BLK_NOCOPY)
  1101. return (0);
  1102. panic("indiracct: missing indir");
  1103. }
  1104. if ((error = ufs_getlbns(cancelvp, rlbn, indirs, &num)) != 0)
  1105. return (error);
  1106. if (lbn != indirs[num - 1 - level].in_lbn || num < 2)
  1107. panic("indiracct: botched params");
  1108. /*
  1109. * We have to expand bread here since it will deadlock looking
  1110. * up the block number for any blocks that are not in the cache.
  1111. */
  1112. error = ffs_getblk(cancelvp, lbn, fsbtodb(fs, blkno), fs->fs_bsize,
  1113. false, &bp);
  1114. if (error)
  1115. return error;
  1116. if ((bp->b_oflags & (BO_DONE | BO_DELWRI)) == 0 && (error =
  1117. rwfsblk(bp->b_vp, B_READ, bp->b_data, fragstoblks(fs, blkno)))) {
  1118. brelse(bp, 0);
  1119. return (error);
  1120. }
  1121. /*
  1122. * Account for the block pointers in this indirect block.
  1123. */
  1124. last = howmany(remblks, blksperindir);
  1125. if (last > NINDIR(fs))
  1126. last = NINDIR(fs);
  1127. bap = malloc(fs->fs_bsize, M_DEVBUF, M_WAITOK | M_ZERO);
  1128. memcpy((void *)bap, bp->b_data, fs->fs_bsize);
  1129. brelse(bp, 0);
  1130. error = (*acctfunc)(snapvp, bap, 0, last,
  1131. fs, level == 0 ? rlbn : -1, expungetype);
  1132. if (error || level == 0)
  1133. goto out;
  1134. /*
  1135. * Account for the block pointers in each of the indirect blocks
  1136. * in the levels below us.
  1137. */
  1138. subblksperindir = blksperindir / NINDIR(fs);
  1139. for (lbn++, level--, i = 0; i < last; i++) {
  1140. error = indiracct(snapvp, cancelvp, level,
  1141. idb_get(VTOI(snapvp), bap, i), lbn, rlbn, remblks,
  1142. subblksperindir, fs, acctfunc, expungetype);
  1143. if (error)
  1144. goto out;
  1145. rlbn += blksperindir;
  1146. lbn -= blksperindir;
  1147. remblks -= blksperindir;
  1148. }
  1149. out:
  1150. free(bap, M_DEVBUF);
  1151. return (error);
  1152. }
  1153. /*
  1154. * Do both snap accounting and map accounting.
  1155. */
  1156. static int
  1157. fullacct(struct vnode *vp, void *bap, int oldblkp, int lastblkp,
  1158. struct fs *fs, daddr_t lblkno,
  1159. int exptype /* BLK_SNAP or BLK_NOCOPY */)
  1160. {
  1161. int error;
  1162. if ((error = snapacct(vp, bap, oldblkp, lastblkp, fs, lblkno, exptype)))
  1163. return (error);
  1164. return (mapacct(vp, bap, oldblkp, lastblkp, fs, lblkno, exptype));
  1165. }
  1166. /*
  1167. * Identify a set of blocks allocated in a snapshot inode.
  1168. */
  1169. static int
  1170. snapacct(struct vnode *vp, void *bap, int oldblkp, int lastblkp,
  1171. struct fs *fs, daddr_t lblkno,
  1172. int expungetype /* BLK_SNAP or BLK_NOCOPY */)
  1173. {
  1174. struct inode *ip = VTOI(vp);
  1175. struct lwp *l = curlwp;
  1176. struct mount *mp = vp->v_mount;
  1177. daddr_t blkno;
  1178. daddr_t lbn;
  1179. struct buf *ibp;
  1180. int error, n;
  1181. const int wbreak = blocks_in_journal(VFSTOUFS(mp)->um_fs)/8;
  1182. error = UFS_WAPBL_BEGIN(mp);
  1183. if (error)
  1184. return error;
  1185. for ( n = 0; oldblkp < lastblkp; oldblkp++) {
  1186. blkno = idb_get(ip, bap, oldblkp);
  1187. if (blkno == 0 || blkno == BLK_NOCOPY || blkno == BLK_SNAP)
  1188. continue;
  1189. lbn = fragstoblks(fs, blkno);
  1190. if (lbn < NDADDR) {
  1191. blkno = db_get(ip, lbn);
  1192. ip->i_flag |= IN_CHANGE | IN_UPDATE;
  1193. } else {
  1194. error = ffs_balloc(vp, lblktosize(fs, (off_t)lbn),
  1195. fs->fs_bsize, l->l_cred, B_METAONLY, &ibp);
  1196. if (error)
  1197. break;
  1198. blkno = idb_get(ip, ibp->b_data,
  1199. (lbn - NDADDR) % NINDIR(fs));
  1200. }
  1201. /*
  1202. * If we are expunging a snapshot vnode and we
  1203. * find a block marked BLK_NOCOPY, then it is
  1204. * one that has been allocated to this snapshot after
  1205. * we took our current snapshot and can be ignored.
  1206. */
  1207. if (expungetype == BLK_SNAP && blkno == BLK_NOCOPY) {
  1208. if (lbn >= NDADDR)
  1209. brelse(ibp, 0);
  1210. } else {
  1211. if (blkno != 0)
  1212. panic("snapacct: bad block");
  1213. if (lbn < NDADDR)
  1214. db_assign(ip, lbn, expungetype);
  1215. else {
  1216. idb_assign(ip, ibp->b_data,
  1217. (lbn - NDADDR) % NINDIR(fs), expungetype);
  1218. bdwrite(ibp);
  1219. }
  1220. }
  1221. if (wbreak > 0 && (++n % wbreak) == 0) {
  1222. UFS_WAPBL_END(mp);
  1223. error = UFS_WAPBL_BEGIN(mp);
  1224. if (error)
  1225. return error;
  1226. }
  1227. }
  1228. UFS_WAPBL_END(mp);
  1229. return error;
  1230. }
  1231. /*
  1232. * Account for a set of blocks allocated in a snapshot inode.
  1233. */
  1234. static int
  1235. mapacct(struct vnode *vp, void *bap, int oldblkp, int lastblkp,
  1236. struct fs *fs, daddr_t lblkno, int expungetype)
  1237. {
  1238. daddr_t blkno;
  1239. struct inode *ip;
  1240. struct mount *mp = vp->v_mount;
  1241. ino_t inum;
  1242. int acctit, error, n;
  1243. const int wbreak = blocks_in_journal(VFSTOUFS(mp)->um_fs)/8;
  1244. error = UFS_WAPBL_BEGIN(mp);
  1245. if (error)
  1246. return error;
  1247. ip = VTOI(vp);
  1248. inum = ip->i_number;
  1249. if (lblkno == -1)
  1250. acctit = 0;
  1251. else
  1252. acctit = 1;
  1253. for ( n = 0; oldblkp < lastblkp; oldblkp++, lblkno++) {
  1254. blkno = idb_get(ip, bap, oldblkp);
  1255. if (blkno == 0 || blkno == BLK_NOCOPY)
  1256. continue;
  1257. if (acctit && expungetype == BLK_SNAP && blkno != BLK_SNAP)
  1258. *ip->i_snapblklist++ = lblkno;
  1259. if (blkno == BLK_SNAP)
  1260. blkno = blkstofrags(fs, lblkno);
  1261. ffs_blkfree_snap(fs, vp, blkno, fs->fs_bsize, inum);
  1262. if (wbreak > 0 && (++n % wbreak) == 0) {
  1263. UFS_WAPBL_END(mp);
  1264. error = UFS_WAPBL_BEGIN(mp);
  1265. if (error)
  1266. return error;
  1267. }
  1268. }
  1269. UFS_WAPBL_END(mp);
  1270. return (0);
  1271. }
  1272. /*
  1273. * Number of blocks that fit into the journal or zero if not logging.
  1274. */
  1275. static int
  1276. blocks_in_journal(struct fs *fs)
  1277. {
  1278. off_t bpj;
  1279. if ((fs->fs_flags & FS_DOWAPBL) == 0)
  1280. return 0;
  1281. bpj = 1;
  1282. if (fs->fs_journal_version == UFS_WAPBL_VERSION) {
  1283. switch (fs->fs_journal_location) {
  1284. case UFS_WAPBL_JOURNALLOC_END_PARTITION:
  1285. bpj = (off_t)fs->fs_journallocs[UFS_WAPBL_EPART_BLKSZ]*
  1286. fs->fs_journallocs[UFS_WAPBL_EPART_COUNT];
  1287. break;
  1288. case UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM:
  1289. bpj = (off_t)fs->fs_journallocs[UFS_WAPBL_INFS_BLKSZ]*
  1290. fs->fs_journallocs[UFS_WAPBL_INFS_COUNT];
  1291. break;
  1292. }
  1293. }
  1294. bpj /= fs->fs_bsize;
  1295. return (bpj > 0 ? bpj : 1);
  1296. }
  1297. #endif /* defined(FFS_NO_SNAPSHOT) */
  1298. /*
  1299. * Decrement extra reference on snapshot when last name is removed.
  1300. * It will not be freed until the last open reference goes away.
  1301. */
  1302. void
  1303. ffs_snapgone(struct inode *ip)
  1304. {
  1305. struct mount *mp = ip->i_devvp->v_specmountpoint;
  1306. struct inode *xp;
  1307. struct fs *fs;
  1308. struct snap_info *si;
  1309. int snaploc;
  1310. si = VFSTOUFS(mp)->um_snapinfo;
  1311. /*
  1312. * Find snapshot in incore list.
  1313. */
  1314. mutex_enter(&si->si_lock);
  1315. TAILQ_FOREACH(xp, &si->si_snapshots, i_nextsnap)
  1316. if (xp == ip)
  1317. break;
  1318. mutex_exit(&si->si_lock);
  1319. if (xp != NULL)
  1320. vrele(ITOV(ip));
  1321. #ifdef DEBUG
  1322. else if (snapdebug)
  1323. printf("ffs_snapgone: lost snapshot vnode %llu\n",
  1324. (unsigned long long)ip->i_number);
  1325. #endif
  1326. /*
  1327. * Delete snapshot inode from superblock. Keep list dense.
  1328. */
  1329. mutex_enter(&si->si_lock);
  1330. fs = ip->i_fs;
  1331. for (snaploc = 0; snaploc < FSMAXSNAP; snaploc++)
  1332. if (fs->fs_snapinum[snaploc] == ip->i_number)
  1333. break;
  1334. if (snaploc < FSMAXSNAP) {
  1335. for (snaploc++; snaploc < FSMAXSNAP; snaploc++) {
  1336. if (fs->fs_snapinum[snaploc] == 0)
  1337. break;
  1338. fs->fs_snapinum[snaploc - 1] = fs->fs_snapinum[snaploc];
  1339. }
  1340. fs->fs_snapinum[snaploc - 1] = 0;
  1341. }
  1342. si->si_gen++;
  1343. mutex_exit(&si->si_lock);
  1344. }
  1345. /*
  1346. * Prepare a snapshot file for being removed.
  1347. */
  1348. void
  1349. ffs_snapremove(struct vnode *vp)
  1350. {
  1351. struct inode *ip = VTOI(vp), *xp;
  1352. struct vnode *devvp = ip->i_devvp;
  1353. struct fs *fs = ip->i_fs;
  1354. struct mount *mp = devvp->v_specmountpoint;
  1355. struct buf *ibp;
  1356. struct snap_info *si;
  1357. struct lwp *l = curlwp;
  1358. daddr_t numblks, blkno, dblk;
  1359. int error, loc, last;
  1360. si = VFSTOUFS(mp)->um_snapinfo;
  1361. /*
  1362. * If active, delete from incore list (this snapshot may
  1363. * already have been in the process of being deleted, so
  1364. * would not have been active).
  1365. *
  1366. * Clear copy-on-write flag if last snapshot.
  1367. */
  1368. mutex_enter(&si->si_snaplock);
  1369. mutex_enter(&si->si_lock);
  1370. if (is_active_snapshot(si, ip)) {
  1371. TAILQ_REMOVE(&si->si_snapshots, ip, i_nextsnap);
  1372. if (TAILQ_FIRST(&si->si_snapshots) != 0) {
  1373. /* Roll back the list of preallocated blocks. */
  1374. xp = TAILQ_LAST(&si->si_snapshots, inodelst);
  1375. si->si_snapblklist = xp->i_snapblklist;
  1376. si->si_gen++;
  1377. mutex_exit(&si->si_lock);
  1378. mutex_exit(&si->si_snaplock);
  1379. } else {
  1380. si->si_snapblklist = 0;
  1381. si->si_gen++;
  1382. mutex_exit(&si->si_lock);
  1383. mutex_exit(&si->si_snaplock);
  1384. fscow_disestablish(mp, ffs_copyonwrite, devvp);
  1385. }
  1386. if (ip->i_snapblklist != NULL) {
  1387. free(ip->i_snapblklist, M_UFSMNT);
  1388. ip->i_snapblklist = NULL;
  1389. }
  1390. } else {
  1391. mutex_exit(&si->si_lock);
  1392. mutex_exit(&si->si_snaplock);
  1393. }
  1394. /*
  1395. * Clear all BLK_NOCOPY fields. Pass any block claims to other
  1396. * snapshots that want them (see ffs_snapblkfree below).
  1397. */
  1398. for (blkno = 1; blkno < NDADDR; blkno++) {
  1399. dblk = db_get(ip, blkno);
  1400. if (dblk == BLK_NOCOPY || dblk == BLK_SNAP)
  1401. db_assign(ip, blkno, 0);
  1402. else if ((dblk == blkstofrags(fs, blkno) &&
  1403. ffs_snapblkfree(fs, ip->i_devvp, dblk, fs->fs_bsize,
  1404. ip->i_number))) {
  1405. DIP_ADD(ip, blocks, -btodb(fs->fs_bsize));
  1406. db_assign(ip, blkno, 0);
  1407. }
  1408. }
  1409. numblks = howmany(ip->i_size, fs->fs_bsize);
  1410. for (blkno = NDADDR; blkno < numblks; blkno += NINDIR(fs)) {
  1411. error = ffs_balloc(vp, lblktosize(fs, (off_t)blkno),
  1412. fs->fs_bsize, l->l_cred, B_METAONLY, &ibp);
  1413. if (error)
  1414. continue;
  1415. if (fs->fs_size - blkno > NINDIR(fs))
  1416. last = NINDIR(fs);
  1417. else
  1418. last = fs->fs_size - blkno;
  1419. for (loc = 0; loc < last; loc++) {
  1420. dblk = idb_get(ip, ibp->b_data, loc);
  1421. if (dblk == BLK_NOCOPY || dblk == BLK_SNAP)
  1422. idb_assign(ip, ibp->b_data, loc, 0);
  1423. else if (dblk == blkstofrags(fs, blkno) &&
  1424. ffs_snapblkfree(fs, ip->i_devvp, dblk,
  1425. fs->fs_bsize, ip->i_number)) {
  1426. DIP_ADD(ip, blocks, -btodb(fs->fs_bsize));
  1427. idb_assign(ip, ibp->b_data, loc, 0);
  1428. }
  1429. }
  1430. bawrite(ibp);
  1431. UFS_WAPBL_END(mp);
  1432. error = UFS_WAPBL_BEGIN(mp);
  1433. KASSERT(error == 0);
  1434. }
  1435. /*
  1436. * Clear snapshot flag and drop reference.
  1437. */
  1438. ip->i_flags &= ~(SF_SNAPSHOT | SF_SNAPINVAL);
  1439. DIP_ASSIGN(ip, flags, ip->i_flags);
  1440. ip->i_flag |= IN_CHANGE | IN_UPDATE;
  1441. #if defined(QUOTA) || defined(QUOTA2)
  1442. chkdq(ip, DIP(ip, blocks), l->l_cred, FORCE);
  1443. chkiq(ip, 1, l->l_cred, FORCE);
  1444. #endif
  1445. }
  1446. /*
  1447. * Notification that a block is being freed. Return zero if the free
  1448. * should be allowed to proceed. Return non-zero if the snapshot file
  1449. * wants to claim the block. The block will be claimed if it is an
  1450. * uncopied part of one of the snapshots. It will be freed if it is
  1451. * either a BLK_NOCOPY or has already been copied in all of the snapshots.
  1452. * If a fragment is being freed, then all snapshots that care about
  1453. * it must make a copy since a snapshot file can only claim full sized
  1454. * blocks. Note that if more than one snapshot file maps the block,
  1455. * we can pick one at random to claim it. Since none of the snapshots
  1456. * can change, we are assurred that they will all see the same unmodified
  1457. * image. When deleting a snapshot file (see ffs_snapremove above), we
  1458. * must push any of these claimed blocks to one of the other snapshots
  1459. * that maps it. These claimed blocks are easily identified as they will
  1460. * have a block number equal to their logical block number within the
  1461. * snapshot. A copied block can never have this property because they
  1462. * must always have been allocated from a BLK_NOCOPY location.
  1463. */
  1464. int
  1465. ffs_snapblkfree(struct fs *fs, struct vnode *devvp, daddr_t bno,
  1466. long size, ino_t inum)
  1467. {
  1468. struct mount *mp = devvp->v_specmountpoint;
  1469. struct buf *ibp;
  1470. struct inode *ip;
  1471. struct vnode *vp = NULL;
  1472. struct snap_info *si;
  1473. void *saved_data = NULL;
  1474. daddr_t lbn;
  1475. daddr_t blkno;
  1476. uint32_t gen;
  1477. int indiroff = 0, error = 0, claimedblk = 0;
  1478. si = VFSTOUFS(mp)->um_snapinfo;
  1479. lbn = fragstoblks(fs, bno);
  1480. mutex_enter(&si->si_snaplock);
  1481. mutex_enter(&si->si_lock);
  1482. si->si_owner = curlwp;
  1483. retry:
  1484. gen = si->si_gen;
  1485. TAILQ_FOREACH(ip, &si->si_snapshots, i_nextsnap) {
  1486. vp = ITOV(ip);
  1487. /*
  1488. * Lookup block being written.
  1489. */
  1490. if (lbn < NDADDR) {
  1491. blkno = db_get(ip, lbn);
  1492. } else {
  1493. mutex_exit(&si->si_lock);
  1494. error = ffs_balloc(vp, lblktosize(fs, (off_t)lbn),
  1495. fs->fs_bsize, FSCRED, B_METAONLY, &ibp);
  1496. if (error) {
  1497. mutex_enter(&si->si_lock);
  1498. break;
  1499. }
  1500. indiroff = (lbn - NDADDR) % NINDIR(fs);
  1501. blkno = idb_get(ip, ibp->b_data, indiroff);
  1502. mutex_enter(&si->si_lock);
  1503. if (gen != si->si_gen) {
  1504. brelse(ibp, 0);
  1505. goto retry;
  1506. }
  1507. }
  1508. /*
  1509. * Check to see if block needs to be copied.
  1510. */
  1511. if (blkno == 0) {
  1512. /*
  1513. * A block that we map is being freed. If it has not
  1514. * been claimed yet, we will claim or copy it (below).
  1515. */
  1516. claimedblk = 1;
  1517. } else if (blkno == BLK_SNAP) {
  1518. /*
  1519. * No previous snapshot claimed the block,
  1520. * so it will be freed and become a BLK_NOCOPY
  1521. * (don't care) for us.
  1522. */
  1523. if (claimedblk)
  1524. panic("snapblkfree: inconsistent block type");
  1525. if (lbn < NDADDR) {
  1526. db_assign(ip, lbn, BLK_NOCOPY);
  1527. ip->i_flag |= IN_CHANGE | IN_UPDATE;
  1528. } else {
  1529. idb_assign(ip, ibp->b_data, indiroff,
  1530. BLK_NOCOPY);
  1531. mutex_exit(&si->si_lock);
  1532. if (ip->i_nlink > 0)
  1533. bwrite(ibp);
  1534. else
  1535. bdwrite(ibp);
  1536. mutex_enter(&si->si_lock);
  1537. if (gen != si->si_gen)
  1538. goto retry;
  1539. }
  1540. continue;
  1541. } else /* BLK_NOCOPY or default */ {
  1542. /*
  1543. * If the snapshot has already copied the block
  1544. * (default), or does not care about the block,
  1545. * it is not needed.
  1546. */
  1547. if (lbn >= NDADDR)
  1548. brelse(ibp, 0);
  1549. continue;
  1550. }
  1551. /*
  1552. * If this is a full size block, we will just grab it
  1553. * and assign it to the snapshot inode. Otherwise we
  1554. * will proceed to copy it. See explanation for this
  1555. * routine as to why only a single snapshot needs to
  1556. * claim this block.
  1557. */
  1558. if (size == fs->fs_bsize) {
  1559. #ifdef DEBUG
  1560. if (snapdebug)
  1561. printf("%s %llu lbn %" PRId64
  1562. "from inum %llu\n",
  1563. "Grabonremove: snapino",
  1564. (unsigned long long)ip->i_number,
  1565. lbn, (unsigned long long)inum);
  1566. #endif
  1567. mutex_exit(&si->si_lock);
  1568. if (lbn < NDADDR) {
  1569. db_assign(ip, lbn, bno);
  1570. } else {
  1571. idb_assign(ip, ibp->b_data, indiroff, bno);
  1572. if (ip->i_nlink > 0)
  1573. bwrite(ibp);
  1574. else
  1575. bdwrite(ibp);
  1576. }
  1577. DIP_ADD(ip, blocks, btodb(size));
  1578. ip->i_flag |= IN_CHANGE | IN_UPDATE;
  1579. if (ip->i_nlink > 0 && mp->mnt_wapbl)
  1580. error = syncsnap(vp);
  1581. else
  1582. error = 0;
  1583. mutex_enter(&si->si_lock);
  1584. si->si_owner = NULL;
  1585. mutex_exit(&si->si_lock);
  1586. mutex_exit(&si->si_snaplock);
  1587. return (error == 0);
  1588. }
  1589. if (lbn >= NDADDR)
  1590. brelse(ibp, 0);
  1591. #ifdef DEBUG
  1592. if (snapdebug)
  1593. printf("%s%llu lbn %" PRId64 " %s %llu size %ld\n",
  1594. "Copyonremove: snapino ",
  1595. (unsigned long long)ip->i_number,
  1596. lbn, "for inum", (unsigned long long)inum, size);
  1597. #endif
  1598. /*
  1599. * If we have already read the old block contents, then
  1600. * simply copy them to the new block. Note that we need
  1601. * to synchronously write snapshots that have not been
  1602. * unlinked, and hence will be visible after a crash,
  1603. * to ensure their integrity.
  1604. */
  1605. mutex_exit(&si->si_lock);
  1606. if (saved_data == NULL) {
  1607. saved_data = malloc(fs->fs_bsize, M_UFSMNT, M_WAITOK);
  1608. error = rwfsblk(vp, B_READ, saved_data, lbn);
  1609. if (error) {
  1610. free(saved_data, M_UFSMNT);
  1611. saved_data = NULL;
  1612. mutex_enter(&si->si_lock);
  1613. break;
  1614. }
  1615. }
  1616. error = wrsnapblk(vp, saved_data, lbn);
  1617. if (error == 0 && ip->i_nlink > 0 && mp->mnt_wapbl)
  1618. error = syncsnap(vp);
  1619. mutex_enter(&si->si_lock);
  1620. if (error)
  1621. break;
  1622. if (gen != si->si_gen)
  1623. goto retry;
  1624. }
  1625. si->si_owner = NULL;
  1626. mutex_exit(&si->si_lock);
  1627. mutex_exit(&si->si_snaplock);
  1628. if (saved_data)
  1629. free(saved_data, M_UFSMNT);
  1630. /*
  1631. * If we have been unable to allocate a block in which to do
  1632. * the copy, then return non-zero so that the fragment will
  1633. * not be freed. Although space will be lost, the snapshot
  1634. * will stay consistent.
  1635. */
  1636. return (error);
  1637. }
  1638. /*
  1639. * Associate snapshot files when mounting.
  1640. */
  1641. void
  1642. ffs_snapshot_mount(struct mount *mp)
  1643. {
  1644. struct vnode *devvp = VFSTOUFS(mp)->um_devvp;
  1645. struct fs *fs = VFSTOUFS(mp)->um_fs;
  1646. struct lwp *l = curlwp;
  1647. struct vnode *vp;
  1648. struct inode *ip, *xp;
  1649. struct snap_info *si;
  1650. daddr_t snaplistsize, *snapblklist;
  1651. int i, error, ns, snaploc, loc;
  1652. /*
  1653. * No persistent snapshots on apple ufs file systems.
  1654. */
  1655. if (UFS_MPISAPPLEUFS(VFSTOUFS(mp)))
  1656. return;
  1657. si = VFSTOUFS(mp)->um_snapinfo;
  1658. ns = UFS_FSNEEDSWAP(fs);
  1659. /*
  1660. * XXX The following needs to be set before ffs_truncate or
  1661. * VOP_READ can be called.
  1662. */
  1663. mp->mnt_stat.f_iosize = fs->fs_bsize;
  1664. /*
  1665. * Process each snapshot listed in the superblock.
  1666. */
  1667. vp = NULL;
  1668. mutex_enter(&si->si_lock);
  1669. for (snaploc = 0; snaploc < FSMAXSNAP; snaploc++) {
  1670. if (fs->fs_snapinum[snaploc] == 0)
  1671. break;
  1672. if ((error = VFS_VGET(mp, fs->fs_snapinum[snaploc],
  1673. &vp)) != 0) {
  1674. printf("ffs_snapshot_mount: vget failed %d\n", error);
  1675. continue;
  1676. }
  1677. ip = VTOI(vp);
  1678. if ((ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) !=
  1679. SF_SNAPSHOT) {
  1680. printf("ffs_snapshot_mount: non-snapshot inode %d\n",
  1681. fs->fs_snapinum[snaploc]);
  1682. vput(vp);
  1683. vp = NULL;
  1684. for (loc = snaploc + 1; loc < FSMAXSNAP; loc++) {
  1685. if (fs->fs_snapinum[loc] == 0)
  1686. break;
  1687. fs->fs_snapinum[loc - 1] = fs->fs_snapinum[loc];
  1688. }
  1689. fs->fs_snapinum[loc - 1] = 0;
  1690. snaploc--;
  1691. continue;
  1692. }
  1693. /*
  1694. * Read the block hints list. Use an empty list on
  1695. * read errors.
  1696. */
  1697. error = vn_rdwr(UIO_READ, vp,
  1698. (void *)&snaplistsize, sizeof(snaplistsize),
  1699. lblktosize(fs, howmany(fs->fs_size, fs->fs_frag)),
  1700. UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT|IO_ALTSEMANTICS,
  1701. l->l_cred, NULL, NULL);
  1702. if (error) {
  1703. printf("ffs_snapshot_mount: read_1 failed %d\n", error);
  1704. snaplistsize = 1;
  1705. } else
  1706. snaplistsize = ufs_rw64(snaplistsize, ns);
  1707. snapblklist = malloc(
  1708. snaplistsize * sizeof(daddr_t), M_UFSMNT, M_WAITOK);
  1709. if (error)
  1710. snapblklist[0] = 1;
  1711. else {
  1712. error = vn_rdwr(UIO_READ, vp, (void *)snapblklist,
  1713. snaplistsize * sizeof(daddr_t),
  1714. lblktosize(fs, howmany(fs->fs_size, fs->fs_frag)),
  1715. UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT|IO_ALTSEMANTICS,
  1716. l->l_cred, NULL, NULL);
  1717. for (i = 0; i < snaplistsize; i++)

Large files files are truncated, but you can click here to view the full file